From f19283b932f4d8eff78e73c5a9c19d7a65d93f55 Mon Sep 17 00:00:00 2001 From: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com> Date: Fri, 9 Aug 2024 15:50:41 -0700 Subject: [PATCH 01/23] fix(amplify-category-api): data api call print the full error object (#2759) --- packages/amplify-e2e-core/src/utils/rds.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-e2e-core/src/utils/rds.ts b/packages/amplify-e2e-core/src/utils/rds.ts index d965e4bd13..24aaee622f 100644 --- a/packages/amplify-e2e-core/src/utils/rds.ts +++ b/packages/amplify-e2e-core/src/utils/rds.ts @@ -350,7 +350,7 @@ export const setupRDSClusterAndData = async (config: RDSConfig, queries?: string const executeStatementResponse = await client.send(new ExecuteStatementCommand(executeStatementInput)); console.log('Create table response: ' + JSON.stringify(executeStatementResponse)); } catch (err) { - throw new Error(`Error in creating tables in test database: ${err.response.json}`); + throw new Error(`Error in creating tables in test database: ${JSON.stringify(err, null, 4)}`); } }); From b1b8de8c459a8cef5bd6792f4e075fe83e070df5 Mon Sep 17 00:00:00 2001 From: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com> Date: Mon, 12 Aug 2024 08:05:13 -0700 Subject: [PATCH 02/23] fix: refactor data api execute queries (#2760) --- packages/amplify-e2e-core/src/utils/rds.ts | 13 ++++++++----- .../src/cleanup-e2e-rds-instances.sh | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/amplify-e2e-core/src/utils/rds.ts b/packages/amplify-e2e-core/src/utils/rds.ts index 24aaee622f..3dcaf69ab2 100644 --- a/packages/amplify-e2e-core/src/utils/rds.ts +++ b/packages/amplify-e2e-core/src/utils/rds.ts @@ -6,7 +6,6 @@ import { DBInstance, DeleteDBInstanceCommand, waitUntilDBInstanceAvailable, - CreateDBClusterCommandInput, CreateDBClusterMessage, waitUntilDBClusterAvailable, DeleteDBClusterCommand, @@ -339,7 +338,7 @@ export const setupRDSClusterAndData = async (config: RDSConfig, queries?: string } // create the test tables in the test database - queries?.map(async (query) => { + for (const query of queries ?? []) { try { const executeStatementInput: ExecuteStatementCommandInput = { resourceArn: dbCluster.clusterArn, @@ -352,7 +351,7 @@ export const setupRDSClusterAndData = async (config: RDSConfig, queries?: string } catch (err) { throw new Error(`Error in creating tables in test database: ${JSON.stringify(err, null, 4)}`); } - }); + } return { clusterArn: dbCluster.clusterArn, @@ -427,11 +426,15 @@ export const deleteDBCluster = async (identifier: string, region: string): Promi } }; -const createInstanceIdentifier = (prefix: string) => { +const createInstanceIdentifier = (prefix: string): string => { return `${prefix}instance`; }; -export const generateDBName = () => generator.generate({ length: 8 }).toLowerCase(); +export const generateDBName = (): string => + generator + .generate({ length: 8 }) + .toLowerCase() + .replace(/[^a-zA-Z0-9_]/g, ''); /** * Adds the given inbound rule to the security group. diff --git a/packages/amplify-e2e-tests/src/cleanup-e2e-rds-instances.sh b/packages/amplify-e2e-tests/src/cleanup-e2e-rds-instances.sh index 259b820977..26eefe1724 100644 --- a/packages/amplify-e2e-tests/src/cleanup-e2e-rds-instances.sh +++ b/packages/amplify-e2e-tests/src/cleanup-e2e-rds-instances.sh @@ -1,4 +1,4 @@ -declare -a regions=( 'us-east-1' 'us-east-2' 'us-west-2' 'eu-west-2' 'eu-central-1' 'ap-northeast-1' 'ap-southeast-1' 'ap-southeast-2') ## now loop through the above array +declare -a regions=( 'us-east-1' 'us-east-2' 'us-west-2' 'eu-west-2' 'eu-central-1' 'ap-northeast-1' 'ap-southeast-1' 'ap-southeast-2', 'me-south-1') ## now loop through the above array for region in "${regions[@]}" do echo "Deleting all the RDS instances in $region" From b876731c900924f0b0e5cf25eba33b5b348916a5 Mon Sep 17 00:00:00 2001 From: Dane Pilcher Date: Mon, 12 Aug 2024 11:08:11 -0600 Subject: [PATCH 03/23] chore: update .jsii assembly --- packages/amplify-graphql-api-construct/.jsii | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/amplify-graphql-api-construct/.jsii b/packages/amplify-graphql-api-construct/.jsii index 32ce659570..033fcdcbb0 100644 --- a/packages/amplify-graphql-api-construct/.jsii +++ b/packages/amplify-graphql-api-construct/.jsii @@ -8,19 +8,19 @@ "bundled": { "@aws-amplify/backend-output-schemas": "^0.4.0", "@aws-amplify/backend-output-storage": "^0.2.2", - "@aws-amplify/graphql-auth-transformer": "3.6.4", - "@aws-amplify/graphql-default-value-transformer": "2.3.12", + "@aws-amplify/graphql-auth-transformer": "3.6.5", + "@aws-amplify/graphql-default-value-transformer": "2.3.13", "@aws-amplify/graphql-directives": "1.1.0", "@aws-amplify/graphql-function-transformer": "2.1.26", "@aws-amplify/graphql-http-transformer": "2.1.26", - "@aws-amplify/graphql-index-transformer": "2.4.8", - "@aws-amplify/graphql-maps-to-transformer": "3.4.22", - "@aws-amplify/graphql-model-transformer": "2.11.3", + "@aws-amplify/graphql-index-transformer": "2.4.9", + "@aws-amplify/graphql-maps-to-transformer": "3.4.23", + "@aws-amplify/graphql-model-transformer": "2.11.4", "@aws-amplify/graphql-predictions-transformer": "2.1.26", - "@aws-amplify/graphql-relational-transformer": "2.5.10", - "@aws-amplify/graphql-searchable-transformer": "2.7.8", - "@aws-amplify/graphql-sql-transformer": "0.3.8", - "@aws-amplify/graphql-transformer": "1.6.4", + "@aws-amplify/graphql-relational-transformer": "2.5.11", + "@aws-amplify/graphql-searchable-transformer": "2.7.9", + "@aws-amplify/graphql-sql-transformer": "0.3.9", + "@aws-amplify/graphql-transformer": "1.6.5", "@aws-amplify/graphql-transformer-core": "2.9.3", "@aws-amplify/graphql-transformer-interfaces": "3.10.1", "@aws-amplify/platform-core": "^0.2.0", @@ -8648,6 +8648,6 @@ "symbolId": "src/model-datasource-strategy-types:VpcConfig" } }, - "version": "1.11.4", - "fingerprint": "5fy1yu5eRwqSPiVvwGvbKRysZLZayJCvbgq9X46NM6E=" + "version": "1.11.5", + "fingerprint": "5+Y8KpL72ceseyKk8A54umGRZFflmtey1XE3kHDBqsE=" } \ No newline at end of file From 4c07e79f1ab2fbec77a9664b19fa25ba2b24793c Mon Sep 17 00:00:00 2001 From: Dane Pilcher Date: Mon, 12 Aug 2024 11:09:01 -0600 Subject: [PATCH 04/23] chore: update .jsii assembly --- packages/amplify-data-construct/.jsii | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/amplify-data-construct/.jsii b/packages/amplify-data-construct/.jsii index 2dc7e4bcbe..86113d18c7 100644 --- a/packages/amplify-data-construct/.jsii +++ b/packages/amplify-data-construct/.jsii @@ -8,19 +8,19 @@ "bundled": { "@aws-amplify/backend-output-schemas": "^0.4.0", "@aws-amplify/backend-output-storage": "^0.2.2", - "@aws-amplify/graphql-auth-transformer": "3.6.4", - "@aws-amplify/graphql-default-value-transformer": "2.3.12", + "@aws-amplify/graphql-auth-transformer": "3.6.5", + "@aws-amplify/graphql-default-value-transformer": "2.3.13", "@aws-amplify/graphql-directives": "1.1.0", "@aws-amplify/graphql-function-transformer": "2.1.26", "@aws-amplify/graphql-http-transformer": "2.1.26", - "@aws-amplify/graphql-index-transformer": "2.4.8", - "@aws-amplify/graphql-maps-to-transformer": "3.4.22", - "@aws-amplify/graphql-model-transformer": "2.11.3", + "@aws-amplify/graphql-index-transformer": "2.4.9", + "@aws-amplify/graphql-maps-to-transformer": "3.4.23", + "@aws-amplify/graphql-model-transformer": "2.11.4", "@aws-amplify/graphql-predictions-transformer": "2.1.26", - "@aws-amplify/graphql-relational-transformer": "2.5.10", - "@aws-amplify/graphql-searchable-transformer": "2.7.8", - "@aws-amplify/graphql-sql-transformer": "0.3.8", - "@aws-amplify/graphql-transformer": "1.6.4", + "@aws-amplify/graphql-relational-transformer": "2.5.11", + "@aws-amplify/graphql-searchable-transformer": "2.7.9", + "@aws-amplify/graphql-sql-transformer": "0.3.9", + "@aws-amplify/graphql-transformer": "1.6.5", "@aws-amplify/graphql-transformer-core": "2.9.3", "@aws-amplify/graphql-transformer-interfaces": "3.10.1", "@aws-amplify/platform-core": "^0.2.0", @@ -46,7 +46,7 @@ "zod": "^3.22.3" }, "dependencies": { - "@aws-amplify/graphql-api-construct": "1.11.4", + "@aws-amplify/graphql-api-construct": "1.11.5", "aws-cdk-lib": "^2.129.0", "constructs": "^10.3.0" }, @@ -3731,6 +3731,6 @@ } }, "types": {}, - "version": "1.9.4", - "fingerprint": "yar8i9UOGPXL5F0IgqsPFOL68J/RpxMvEnFpAli1gME=" + "version": "1.9.5", + "fingerprint": "3rLvt6FwnCFYd4zsE5ijxkvbyfSTwtcDLeuO+v/itaE=" } \ No newline at end of file From b790478bb771fd9efde0ea70d8bb7c3bba9e6d61 Mon Sep 17 00:00:00 2001 From: Zeyu Li Date: Mon, 12 Aug 2024 15:55:19 -0700 Subject: [PATCH 05/23] chore: add stale rds instances cleanup in scheduled workflow --- .../src/cleanup-e2e-resources.ts | 72 ++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts b/packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts index d65d552b30..bc583a6dd4 100644 --- a/packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts +++ b/packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts @@ -53,6 +53,11 @@ type IamRoleInfo = { cbInfo?: CodeBuild.Build; }; +type RdsInstanceInfo = { + name: string; + region: string; +}; + type ReportEntry = { jobId?: string; buildBatchArn?: string; @@ -63,6 +68,7 @@ type ReportEntry = { stacks: Record; buckets: Record; roles: Record; + instances: Record; }; type JobFilterPredicate = (job: ReportEntry) => boolean; @@ -85,6 +91,7 @@ type AWSAccountInfo = { const BUCKET_TEST_REGEX = /test/; const IAM_TEST_REGEX = /!RotateE2eAwsToken-e2eTestContextRole|-integtest$|^amplify-|^eu-|^us-|^ap-|^auth-exhaustive-tests|rds-schema-inspector-integtest|^amplify_e2e_tests_lambda|^JsonMockStack-jsonMockApi|^SubscriptionAuth|^cdkamplifytable[0-9]*-|^MutationConditionTest-|^SearchableAuth|^SubscriptionRTFTests-|^NonModelAuthV2FunctionTransformerTests-|^MultiAuthV2Transformer|^FunctionTransformerTests/; +const RDS_TEST_REGEX = /integtest/; const STALE_DURATION_MS = 2 * 60 * 60 * 1000; // 2 hours in milliseconds const isCI = (): boolean => !!(process.env.CI && process.env.CODEBUILD); @@ -111,6 +118,13 @@ const testRoleStalenessFilter = (resource: aws.IAM.Role): boolean => { return isTestResource && isStaleResource; }; +const testInstanceStalenessFilter = (resource: aws.RDS.DBInstance): boolean => { + const isTestResource = resource.DBInstanceIdentifier.match(RDS_TEST_REGEX); + const isStaleResource = + resource.DBInstanceStatus == 'available' && Date.now() - resource.InstanceCreateTime.getMilliseconds() > STALE_DURATION_MS; + return isTestResource && isStaleResource; +}; + /** * Get all S3 buckets in the account, and filter down to the ones we consider stale. */ @@ -141,6 +155,27 @@ const getOrphanTestIamRoles = async (account: AWSAccountInfo): Promise ({ name: it.RoleName })); }; +/** + * Get all RDS instances in the account, and filter down to the ones we consider stale. + */ +const getOrphanRdsInstances = async (account: AWSAccountInfo, region: string): Promise => { + try { + const rdsClient = new aws.RDS(getAWSConfig(account, region)); + const listRdsInstanceResponse = await rdsClient.describeDBInstances().promise(); + const staleInstances = listRdsInstanceResponse.DBInstances.filter(testInstanceStalenessFilter); + return staleInstances.map((i) => ({ name: i.DBInstanceIdentifier, region })); + } catch (e) { + if (e?.code === 'InvalidClientTokenId') { + // Do not fail the cleanup and continue + // This is due to either child account or parent account not available in that region + console.log(`Listing RDS instances for account ${account.accountId}-${region} failed with error with code ${e?.code}. Skipping.`); + return []; + } else { + throw e; + } + } +}; + /** * Get the relevant AWS config object for a given account and region. */ @@ -386,6 +421,7 @@ const mergeResourcesByCCIJob = async ( s3Buckets: S3BucketInfo[], orphanS3Buckets: S3BucketInfo[], orphanIamRoles: IamRoleInfo[], + orphanRdsInstances: RdsInstanceInfo[], ): Promise> => { const result: Record = {}; @@ -462,6 +498,16 @@ const mergeResourcesByCCIJob = async ( roles: src, })); + const orphanRdsInstancesGroup = { + [ORPHAN]: orphanRdsInstances, + }; + + _.mergeWith(result, orphanRdsInstancesGroup, (val, src, key) => ({ + ...val, + jobId: key, + instances: src, + })); + return result; }; @@ -575,6 +621,24 @@ const deleteBucket = async (account: AWSAccountInfo, accountIndex: number, bucke } }; +const deleteRdsInstances = async (account: AWSAccountInfo, accountIndex: number, instances: RdsInstanceInfo[]): Promise => { + await Promise.all(instances.map((instance) => deleteRdsInstance(account, accountIndex, instance))); +}; + +const deleteRdsInstance = async (account: AWSAccountInfo, accountIndex: number, instance: RdsInstanceInfo): Promise => { + const { name, region } = instance; + console.log(`${generateAccountInfo(account, accountIndex)} Deleting RDS instance ${name}`); + try { + const rdsClient = new aws.RDS(getAWSConfig(account, region)); + await rdsClient.deleteDBInstance({ DBInstanceIdentifier: name, SkipFinalSnapshot: true }).promise(); + } catch (e) { + console.log(`${generateAccountInfo(account, accountIndex)} Deleting instance ${name} failed with error ${e.message}`); + if (e.code === 'ExpiredTokenException') { + handleExpiredTokenException(); + } + } +}; + const deleteCfnStacks = async (account: AWSAccountInfo, accountIndex: number, stacks: StackInfo[]): Promise => { await Promise.all(stacks.map((stack) => deleteCfnStack(account, accountIndex, stack))); }; @@ -627,6 +691,10 @@ const deleteResources = async ( if (resources.roles) { await deleteIamRoles(account, accountIndex, Object.values(resources.roles)); } + + if (resources.instances) { + await deleteRdsInstances(account, accountIndex, Object.values(resources.instances)); + } } }; @@ -730,14 +798,16 @@ const cleanupAccount = async (account: AWSAccountInfo, accountIndex: number, fil const bucketPromise = getS3Buckets(account); const orphanBucketPromise = getOrphanS3TestBuckets(account); const orphanIamRolesPromise = getOrphanTestIamRoles(account); + const orphanRdsInstancesPromise = testRegions.map((region) => getOrphanRdsInstances(account, region)); const apps = (await Promise.all(appPromises)).flat(); const stacks = (await Promise.all(stackPromises)).flat(); const buckets = await bucketPromise; const orphanBuckets = await orphanBucketPromise; const orphanIamRoles = await orphanIamRolesPromise; + const orphanRdsInstances = (await Promise.all(orphanRdsInstancesPromise)).flat(); - const allResources = await mergeResourcesByCCIJob(apps, stacks, buckets, orphanBuckets, orphanIamRoles); + const allResources = await mergeResourcesByCCIJob(apps, stacks, buckets, orphanBuckets, orphanIamRoles, orphanRdsInstances); const staleResources = _.pickBy(allResources, filterPredicate); generateReport(staleResources, accountIndex); From 7a42189e0c26276350e7f05954953a167f39d5cd Mon Sep 17 00:00:00 2001 From: fuelvin1 Date: Mon, 12 Aug 2024 17:29:21 -0700 Subject: [PATCH 06/23] feat: add --- .../src/utils/test-regions.ts | 10 +++++ .../src/sql-datatabase-controller.ts | 3 +- scripts/e2e-test-regions.json | 38 +++++++++---------- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/packages/amplify-e2e-core/src/utils/test-regions.ts b/packages/amplify-e2e-core/src/utils/test-regions.ts index 29e14415bb..e940ccf014 100644 --- a/packages/amplify-e2e-core/src/utils/test-regions.ts +++ b/packages/amplify-e2e-core/src/utils/test-regions.ts @@ -3,6 +3,7 @@ import fs from 'fs-extra'; type TestRegion = { name: string; + dataAPISupported: boolean; optIn: boolean; }; @@ -14,3 +15,12 @@ export const isOptInRegion = (region: string): boolean => { return specificRegion.optIn; }; + +export const isDataAPISupported = (region: string): boolean => { + const repoRoot = path.join(__dirname, '..', '..', '..', '..'); + const supportedRegionsPath = path.join(repoRoot, 'scripts', 'e2e-test-regions.json'); + const supportedRegions: TestRegion[] = JSON.parse(fs.readFileSync(supportedRegionsPath, 'utf-8')); + const specificRegion = supportedRegions.find((testRegion) => testRegion.name == region); + + return specificRegion.dataAPISupported; +}; diff --git a/packages/amplify-graphql-api-construct-tests/src/sql-datatabase-controller.ts b/packages/amplify-graphql-api-construct-tests/src/sql-datatabase-controller.ts index 0063ac51a0..61bb96dbf5 100644 --- a/packages/amplify-graphql-api-construct-tests/src/sql-datatabase-controller.ts +++ b/packages/amplify-graphql-api-construct-tests/src/sql-datatabase-controller.ts @@ -15,6 +15,7 @@ import { storeDbConnectionConfigWithSecretsManager, deleteDBCluster, isOptInRegion, + isDataAPISupported, } from 'amplify-category-api-e2e-core'; import { SecretsManagerClient, CreateSecretCommand, DeleteSecretCommand, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager'; import { @@ -53,7 +54,7 @@ export class SqlDatatabaseController { constructor(private readonly setupQueries: Array, private readonly options: RDSConfig) { // Data API is not supported in opted-in regions - if (options.engine === 'postgres' && !isOptInRegion(options.region)) { + if (options.engine === 'postgres' && isDataAPISupported(options.region)) { this.useDataAPI = true; } else { this.useDataAPI = false; diff --git a/scripts/e2e-test-regions.json b/scripts/e2e-test-regions.json index b7273ab78e..e97590811d 100644 --- a/scripts/e2e-test-regions.json +++ b/scripts/e2e-test-regions.json @@ -1,21 +1,21 @@ [ - { "name": "ap-east-1", "optIn": true, "cognitoSupported": false, "betaLayerDeployed": true }, - { "name": "ap-northeast-1", "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, - { "name": "ap-northeast-2", "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, - { "name": "ap-south-1", "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, - { "name": "ap-southeast-1", "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, - { "name": "ap-southeast-2", "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, - { "name": "ca-central-1", "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, - { "name": "eu-central-1", "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, - { "name": "eu-north-1", "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, - { "name": "eu-south-1", "optIn": true, "cognitoSupported": true, "betaLayerDeployed": true }, - { "name": "eu-west-1", "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, - { "name": "eu-west-2", "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, - { "name": "eu-west-3", "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, - { "name": "me-south-1", "optIn": true, "cognitoSupported": true, "betaLayerDeployed": false }, - { "name": "sa-east-1", "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, - { "name": "us-east-1", "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, - { "name": "us-east-2", "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, - { "name": "us-west-1", "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, - { "name": "us-west-2", "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true } + { "name": "ap-east-1", "dataAPISupported": false, "optIn": true, "cognitoSupported": false, "betaLayerDeployed": true }, + { "name": "ap-northeast-1", "dataAPISupported": true, "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, + { "name": "ap-northeast-2", "dataAPISupported": true, "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, + { "name": "ap-south-1", "dataAPISupported": true, "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, + { "name": "ap-southeast-1", "dataAPISupported": true, "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, + { "name": "ap-southeast-2", "dataAPISupported": true, "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, + { "name": "ca-central-1", "dataAPISupported": true, "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, + { "name": "eu-central-1", "dataAPISupported": true, "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, + { "name": "eu-north-1", "dataAPISupported": false, "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, + { "name": "eu-south-1", "dataAPISupported": false, "optIn": true, "cognitoSupported": true, "betaLayerDeployed": true }, + { "name": "eu-west-1", "dataAPISupported": true, "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, + { "name": "eu-west-2", "dataAPISupported": true, "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, + { "name": "eu-west-3", "dataAPISupported": true, "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, + { "name": "me-south-1", "dataAPISupported": false, "optIn": true, "cognitoSupported": true, "betaLayerDeployed": false }, + { "name": "sa-east-1", "dataAPISupported": false, "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, + { "name": "us-east-1", "dataAPISupported": true, "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, + { "name": "us-east-2", "dataAPISupported": true, "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, + { "name": "us-west-1", "dataAPISupported": true, "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true }, + { "name": "us-west-2", "dataAPISupported": true, "optIn": false, "cognitoSupported": true, "betaLayerDeployed": true } ] From c19f5432e68949413bfc2bdba04b132fbced2eae Mon Sep 17 00:00:00 2001 From: Doesnt Matter Date: Tue, 13 Aug 2024 19:52:24 -0700 Subject: [PATCH 07/23] chore: update axios dependency --- package.json | 2 +- yarn.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index ebfc743a03..e7728c96a0 100755 --- a/package.json +++ b/package.json @@ -251,7 +251,7 @@ "jest-environment-jsdom": "26.6.2", "jest-environment-node": "26.6.2", "ts-jest": "^26.5.5", - "axios": "^1.6.0", + "axios": "^1.7.4", "braces": "^3.0.3" } } diff --git a/yarn.lock b/yarn.lock index 69eda1c3ae..2048dccdef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10415,12 +10415,12 @@ axe-core@^4.6.2: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.8.2.tgz#2f6f3cde40935825cf4465e3c1c9e77b240ff6ae" integrity sha512-/dlp0fxyM3R8YW7MFzaHWXrf4zzbr0vaYb23VBFCl83R7nWNPg/yaQw2Dc8jzCMmDVLhSdzH8MjrsuIUuvX+6g== -axios@0.26.0, axios@^0.21.1, axios@^1.0.0, axios@^1.6.0: - version "1.6.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.2.tgz#de67d42c755b571d3e698df1b6504cde9b0ee9f2" - integrity sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A== +axios@0.26.0, axios@^0.21.1, axios@^1.0.0, axios@^1.6.0, axios@^1.7.4: + version "1.7.4" + resolved "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz#4c8ded1b43683c8dd362973c393f3ede24052aa2" + integrity sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw== dependencies: - follow-redirects "^1.15.0" + follow-redirects "^1.15.6" form-data "^4.0.0" proxy-from-env "^1.1.0" @@ -13507,9 +13507,9 @@ folder-hash@^4.0.2: debug "^4.3.3" minimatch "~5.1.2" -follow-redirects@^1.15.0: +follow-redirects@^1.15.6: version "1.15.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== for-each@^0.3.3: From 00c9b2f992806a7a1279409fba7d1dd750f1df07 Mon Sep 17 00:00:00 2001 From: bobbyu99 Date: Wed, 14 Aug 2024 13:40:35 -0700 Subject: [PATCH 08/23] add: provisionHotswapFriendlyResources prop (#2772) * add: provisionHotswapFriendlyResources prop * add: 2 more tests * fix: nit --- packages/amplify-graphql-api-construct/.jsii | 124 +++++++++--------- packages/amplify-graphql-api-construct/API.md | 2 + .../src/amplify-graphql-api.ts | 1 + .../src/types.ts | 10 ++ ...ovision-hotswap-friendly-resources.test.ts | 122 +++++++++++++++++ .../src/resolvers/rds/resolver.ts | 46 +++++-- .../resources/rds-model-resource-generator.ts | 4 +- .../API.md | 1 + .../transformer-context/synth-parameters.ts | 1 + 9 files changed, 239 insertions(+), 72 deletions(-) create mode 100644 packages/amplify-graphql-model-transformer/src/__tests__/provision-hotswap-friendly-resources.test.ts diff --git a/packages/amplify-graphql-api-construct/.jsii b/packages/amplify-graphql-api-construct/.jsii index 033fcdcbb0..6e80807c1c 100644 --- a/packages/amplify-graphql-api-construct/.jsii +++ b/packages/amplify-graphql-api-construct/.jsii @@ -3734,7 +3734,7 @@ "kind": "interface", "locationInModule": { "filename": "src/types.ts", - "line": 892 + "line": 902 }, "name": "AddFunctionProps", "properties": [ @@ -3747,7 +3747,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 896 + "line": 906 }, "name": "dataSource", "type": { @@ -3763,7 +3763,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 901 + "line": 911 }, "name": "name", "type": { @@ -3780,7 +3780,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 936 + "line": 946 }, "name": "code", "optional": true, @@ -3798,7 +3798,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 908 + "line": 918 }, "name": "description", "optional": true, @@ -3816,7 +3816,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 915 + "line": 925 }, "name": "requestMappingTemplate", "optional": true, @@ -3834,7 +3834,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 922 + "line": 932 }, "name": "responseMappingTemplate", "optional": true, @@ -3852,7 +3852,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 929 + "line": 939 }, "name": "runtime", "optional": true, @@ -4195,7 +4195,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 290 + "line": 291 }, "name": "addDynamoDbDataSource", "parameters": [ @@ -4244,7 +4244,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 302 + "line": 303 }, "name": "addElasticsearchDataSource", "parameters": [ @@ -4291,7 +4291,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 312 + "line": 313 }, "name": "addEventBridgeDataSource", "parameters": [ @@ -4338,7 +4338,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 394 + "line": 395 }, "name": "addFunction", "parameters": [ @@ -4373,7 +4373,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 323 + "line": 324 }, "name": "addHttpDataSource", "parameters": [ @@ -4421,7 +4421,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 334 + "line": 335 }, "name": "addLambdaDataSource", "parameters": [ @@ -4469,7 +4469,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 345 + "line": 346 }, "name": "addNoneDataSource", "parameters": [ @@ -4508,7 +4508,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 356 + "line": 357 }, "name": "addOpenSearchDataSource", "parameters": [ @@ -4556,7 +4556,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 369 + "line": 370 }, "name": "addRdsDataSource", "parameters": [ @@ -4623,7 +4623,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 385 + "line": 386 }, "name": "addResolver", "parameters": [ @@ -4782,7 +4782,7 @@ "kind": "interface", "locationInModule": { "filename": "src/types.ts", - "line": 795 + "line": 805 }, "name": "AmplifyGraphqlApiCfnResources", "properties": [ @@ -4795,7 +4795,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 849 + "line": 859 }, "name": "additionalCfnResources", "type": { @@ -4816,7 +4816,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 834 + "line": 844 }, "name": "amplifyDynamoDbTables", "type": { @@ -4837,7 +4837,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 824 + "line": 834 }, "name": "cfnDataSources", "type": { @@ -4858,7 +4858,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 819 + "line": 829 }, "name": "cfnFunctionConfigurations", "type": { @@ -4879,7 +4879,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 844 + "line": 854 }, "name": "cfnFunctions", "type": { @@ -4900,7 +4900,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 799 + "line": 809 }, "name": "cfnGraphqlApi", "type": { @@ -4916,7 +4916,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 804 + "line": 814 }, "name": "cfnGraphqlSchema", "type": { @@ -4932,7 +4932,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 814 + "line": 824 }, "name": "cfnResolvers", "type": { @@ -4953,7 +4953,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 839 + "line": 849 }, "name": "cfnRoles", "type": { @@ -4974,7 +4974,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 829 + "line": 839 }, "name": "cfnTables", "type": { @@ -4995,7 +4995,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 809 + "line": 819 }, "name": "cfnApiKey", "optional": true, @@ -5018,7 +5018,7 @@ "kind": "interface", "locationInModule": { "filename": "src/types.ts", - "line": 712 + "line": 722 }, "name": "AmplifyGraphqlApiProps", "properties": [ @@ -5032,7 +5032,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 729 + "line": 739 }, "name": "authorizationModes", "type": { @@ -5049,7 +5049,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 717 + "line": 727 }, "name": "definition", "type": { @@ -5066,7 +5066,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 723 + "line": 733 }, "name": "apiName", "optional": true, @@ -5085,7 +5085,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 744 + "line": 754 }, "name": "conflictResolution", "optional": true, @@ -5103,7 +5103,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 788 + "line": 798 }, "name": "dataStoreConfiguration", "optional": true, @@ -5123,7 +5123,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 737 + "line": 747 }, "name": "functionNameMap", "optional": true, @@ -5146,7 +5146,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 759 + "line": 769 }, "name": "functionSlots", "optional": true, @@ -5181,7 +5181,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 782 + "line": 792 }, "name": "outputStorageStrategy", "optional": true, @@ -5198,7 +5198,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 771 + "line": 781 }, "name": "predictionsBucket", "optional": true, @@ -5216,7 +5216,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 753 + "line": 763 }, "name": "stackMappings", "optional": true, @@ -5242,7 +5242,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 766 + "line": 776 }, "name": "transformerPlugins", "optional": true, @@ -5264,7 +5264,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 777 + "line": 787 }, "name": "translationBehavior", "optional": true, @@ -5287,7 +5287,7 @@ "kind": "interface", "locationInModule": { "filename": "src/types.ts", - "line": 856 + "line": 866 }, "name": "AmplifyGraphqlApiResources", "properties": [ @@ -5300,7 +5300,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 880 + "line": 890 }, "name": "cfnResources", "type": { @@ -5316,7 +5316,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 875 + "line": 885 }, "name": "functions", "type": { @@ -5337,7 +5337,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 860 + "line": 870 }, "name": "graphqlApi", "type": { @@ -5353,7 +5353,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 885 + "line": 895 }, "name": "nestedStacks", "type": { @@ -5374,7 +5374,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 870 + "line": 880 }, "name": "roles", "type": { @@ -5395,7 +5395,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 865 + "line": 875 }, "name": "tables", "type": { @@ -6434,7 +6434,7 @@ "kind": "interface", "locationInModule": { "filename": "src/types.ts", - "line": 646 + "line": 656 }, "name": "IAmplifyGraphqlDefinition", "properties": [ @@ -6449,7 +6449,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 671 + "line": 681 }, "name": "dataSourceStrategies", "type": { @@ -6483,7 +6483,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 657 + "line": 667 }, "name": "functionSlots", "type": { @@ -6517,7 +6517,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 651 + "line": 661 }, "name": "schema", "type": { @@ -6534,7 +6534,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 677 + "line": 687 }, "name": "customSqlDataSourceStrategies", "optional": true, @@ -6558,7 +6558,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 665 + "line": 675 }, "name": "referencedLambdaFunctions", "optional": true, @@ -6584,7 +6584,7 @@ "kind": "interface", "locationInModule": { "filename": "src/types.ts", - "line": 683 + "line": 693 }, "name": "IBackendOutputEntry", "properties": [ @@ -6597,7 +6597,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 692 + "line": 702 }, "name": "payload", "type": { @@ -6618,7 +6618,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 687 + "line": 697 }, "name": "version", "type": { @@ -6638,7 +6638,7 @@ "kind": "interface", "locationInModule": { "filename": "src/types.ts", - "line": 698 + "line": 708 }, "methods": [ { @@ -6649,7 +6649,7 @@ }, "locationInModule": { "filename": "src/types.ts", - "line": 705 + "line": 715 }, "name": "addBackendOutputEntry", "parameters": [ @@ -8649,5 +8649,5 @@ } }, "version": "1.11.5", - "fingerprint": "5+Y8KpL72ceseyKk8A54umGRZFflmtey1XE3kHDBqsE=" + "fingerprint": "itC1sArd8btBzXDzzeFtCEr/UOX5v/yZgKz+LPxAdCg=" } \ No newline at end of file diff --git a/packages/amplify-graphql-api-construct/API.md b/packages/amplify-graphql-api-construct/API.md index c9bf8c1709..dd4283457f 100644 --- a/packages/amplify-graphql-api-construct/API.md +++ b/packages/amplify-graphql-api-construct/API.md @@ -321,6 +321,8 @@ export interface PartialTranslationBehavior { readonly enableSearchNodeToNodeEncryption?: boolean; readonly enableTransformerCfnOutputs?: boolean; readonly populateOwnerFieldForStaticGroupAuth?: boolean; + // @internal + readonly _provisionHotswapFriendlyResources?: boolean; readonly replaceTableUponGsiUpdate?: boolean; readonly respectPrimaryKeyAttributesOnConnectionField?: boolean; readonly sandboxModeEnabled?: boolean; diff --git a/packages/amplify-graphql-api-construct/src/amplify-graphql-api.ts b/packages/amplify-graphql-api-construct/src/amplify-graphql-api.ts index 343b878fda..236f274484 100644 --- a/packages/amplify-graphql-api-construct/src/amplify-graphql-api.ts +++ b/packages/amplify-graphql-api-construct/src/amplify-graphql-api.ts @@ -203,6 +203,7 @@ export class AmplifyGraphqlApi extends Construct { amplifyEnvironmentName: amplifyEnvironmentName, apiName: props.apiName ?? id, ...authSynthParameters, + provisionHotswapFriendlyResources: translationBehavior?._provisionHotswapFriendlyResources, }, schema: definition.schema, userDefinedSlots: parseUserDefinedSlots(separatedFunctionSlots), diff --git a/packages/amplify-graphql-api-construct/src/types.ts b/packages/amplify-graphql-api-construct/src/types.ts index 9f066889dd..cbc38c9200 100644 --- a/packages/amplify-graphql-api-construct/src/types.ts +++ b/packages/amplify-graphql-api-construct/src/types.ts @@ -638,6 +638,16 @@ export interface PartialTranslationBehavior { * The behavior of this may change without warning. */ readonly _allowGen1Patterns?: boolean; + + /** + * When enabled, sandbox deployment will be faster by skipping the creation of the Hotswap friendly resources. + * + * @default false + * @internal + * WARNING: Although this has `public` access, it is intended for internal use and should not be used directly. + * The behavior of this may change without warning. + */ + readonly _provisionHotswapFriendlyResources?: boolean; } /** diff --git a/packages/amplify-graphql-model-transformer/src/__tests__/provision-hotswap-friendly-resources.test.ts b/packages/amplify-graphql-model-transformer/src/__tests__/provision-hotswap-friendly-resources.test.ts new file mode 100644 index 0000000000..0c7a4a2fb8 --- /dev/null +++ b/packages/amplify-graphql-model-transformer/src/__tests__/provision-hotswap-friendly-resources.test.ts @@ -0,0 +1,122 @@ +import { App, Stack } from 'aws-cdk-lib'; +import { SQLLambdaResourceNames } from '@aws-amplify/graphql-transformer-core'; +import { TransformerContextProvider } from '@aws-amplify/graphql-transformer-interfaces'; +import { createLayerVersionCustomResource, createSNSTopicARNCustomResource } from '../resolvers/rds'; + +describe('provisionHotswapFriendlyResources', () => { + const resourceNames = { + sqlLayerVersionResolverCustomResource: 'TestLayerVersionCustomResource', + sqlSNSTopicARNResolverCustomResource: 'TestSNSTopicARNCustomResource', + } as SQLLambdaResourceNames; + const contextToProvideHotswapFriendlyResources = { + synthParameters: { + amplifyEnvironmentName: 'testAmplifyEnvironmentName', + apiName: 'testAPIName', + provisionHotswapFriendlyResources: true, + }, + } as TransformerContextProvider; + const contextToNotProvideHotswapFriendlyResources = { + synthParameters: { + amplifyEnvironmentName: 'testAmplifyEnvironmentName', + apiName: 'testAPIName', + provisionHotswapFriendlyResources: false, + }, + } as TransformerContextProvider; + const layerVersionCustomResourceType = 'Custom::SQLLayerVersionCustomResource'; + const snsTopicARNCustomResourceType = 'Custom::SQLSNSTopicARNCustomResource'; + + let app: App; + let stack: Stack; + beforeEach(() => { + app = new App(); + stack = new Stack(app, 'TestStack'); + }); + + it('should create a layer version custom resource with a fixed physical ID if provisionHotswapFriendlyResources is true', () => { + createLayerVersionCustomResource(stack, resourceNames, contextToProvideHotswapFriendlyResources); + + // Synthesize stack to get CFN template + const synthesizedTemplate = app.synth().getStackByName(stack.stackName).template; + const resources = synthesizedTemplate.Resources; + + // Find custom resource + const customResource = Object.values(resources).find((resource: any) => resource.Type === layerVersionCustomResourceType) as any; + + // Expect custom resource to be defined + expect(customResource).toBeDefined(); + + // Parse 'Create' and 'Update' properties to extract physicalResourceId + const createProperties = JSON.parse(customResource.Properties.Create['Fn::Join'][1].join('')); + const updateProperties = JSON.parse(customResource.Properties.Update['Fn::Join'][1].join('')); + + const expectedPhysicalId = resourceNames.sqlLayerVersionResolverCustomResource; + expect(createProperties.physicalResourceId.id).toEqual(expectedPhysicalId); + expect(updateProperties.physicalResourceId.id).toEqual(expectedPhysicalId); + }); + + it('should create a SNS topic ARN custom resource with a fixed physical ID if provisionHotswapFriendlyResources is true', () => { + createSNSTopicARNCustomResource(stack, resourceNames, contextToProvideHotswapFriendlyResources); + + // Synthesize stack to get CFN template + const synthesizedTemplate = app.synth().getStackByName(stack.stackName).template; + const resources = synthesizedTemplate.Resources; + + // Find custom resource + const customResource = Object.values(resources).find((resource: any) => resource.Type === snsTopicARNCustomResourceType) as any; + + // Expect custom resource to be defined + expect(customResource).toBeDefined(); + + // Parse 'Create' and 'Update' properties to extract physicalResourceId + const createProperties = JSON.parse(customResource.Properties.Create['Fn::Join'][1].join('')); + const updateProperties = JSON.parse(customResource.Properties.Update['Fn::Join'][1].join('')); + + const expectedPhysicalId = resourceNames.sqlSNSTopicARNResolverCustomResource; + expect(createProperties.physicalResourceId.id).toEqual(expectedPhysicalId); + expect(updateProperties.physicalResourceId.id).toEqual(expectedPhysicalId); + }); + + it('should create a layer version custom resource with a unique physical ID if provisionHotswapFriendlyResources is false', () => { + createLayerVersionCustomResource(stack, resourceNames, contextToNotProvideHotswapFriendlyResources); + + // Synthesize stack to get CFN template + const synthesizedTemplate = app.synth().getStackByName(stack.stackName).template; + const resources = synthesizedTemplate.Resources; + + // Find custom resource + const customResource = Object.values(resources).find((resource: any) => resource.Type === layerVersionCustomResourceType) as any; + + // Expect custom resource to be defined + expect(customResource).toBeDefined(); + + // Parse 'Create' and 'Update' properties to extract physicalResourceId + const createProperties = JSON.parse(customResource.Properties.Create['Fn::Join'][1].join('')); + const updateProperties = JSON.parse(customResource.Properties.Update['Fn::Join'][1].join('')); + + const expectedPhysicalId = new RegExp(`^${resourceNames.sqlLayerVersionResolverCustomResource}-\\d{13,}$`); + expect(createProperties.physicalResourceId.id).toMatch(expectedPhysicalId); + expect(updateProperties.physicalResourceId.id).toMatch(expectedPhysicalId); + }); + + it('should create a SNS topic ARN custom resource with a unique physical ID if provisionHotswapFriendlyResources is false', () => { + createSNSTopicARNCustomResource(stack, resourceNames, contextToNotProvideHotswapFriendlyResources); + + // Synthesize stack to get CFN template + const synthesizedTemplate = app.synth().getStackByName(stack.stackName).template; + const resources = synthesizedTemplate.Resources; + + // Find custom resource + const customResource = Object.values(resources).find((resource: any) => resource.Type === snsTopicARNCustomResourceType) as any; + + // Expect custom resource to be defined + expect(customResource).toBeDefined(); + + // Parse 'Create' and 'Update' properties to extract physicalResourceId + const createProperties = JSON.parse(customResource.Properties.Create['Fn::Join'][1].join('')); + const updateProperties = JSON.parse(customResource.Properties.Update['Fn::Join'][1].join('')); + + const expectedPhysicalId = new RegExp(`^${resourceNames.sqlSNSTopicARNResolverCustomResource}-\\d{13,}$`); + expect(createProperties.physicalResourceId.id).toMatch(expectedPhysicalId); + expect(updateProperties.physicalResourceId.id).toMatch(expectedPhysicalId); + }); +}); diff --git a/packages/amplify-graphql-model-transformer/src/resolvers/rds/resolver.ts b/packages/amplify-graphql-model-transformer/src/resolvers/rds/resolver.ts index 7c056b70ff..8fe1b7816d 100644 --- a/packages/amplify-graphql-model-transformer/src/resolvers/rds/resolver.ts +++ b/packages/amplify-graphql-model-transformer/src/resolvers/rds/resolver.ts @@ -196,7 +196,11 @@ export const createRdsLambda = ( * add the name. We can figure out the right way to expose this to customers if needed, but for now we are not invoking `setResourceName` * because it would have no effect. */ -export const createLayerVersionCustomResource = (scope: Construct, resourceNames: SQLLambdaResourceNames): AwsCustomResource => { +export const createLayerVersionCustomResource = ( + scope: Construct, + resourceNames: SQLLambdaResourceNames, + context: TransformerContextProvider, +): AwsCustomResource => { const { SQLLayerManifestBucket, SQLLayerManifestBucketRegion, SQLLayerVersionManifestKeyPrefix } = ResourceConstants.RESOURCES; const key = Fn.join('', [SQLLayerVersionManifestKeyPrefix, Fn.ref('AWS::Region')]); @@ -204,6 +208,17 @@ export const createLayerVersionCustomResource = (scope: Construct, resourceNames const manifestArn = `arn:aws:s3:::${SQLLayerManifestBucket}/${key}`; const resourceName = resourceNames.sqlLayerVersionResolverCustomResource; + + // If deploying in a sandbox, use the same physical ID to speed up deployments + // Otherwise, make the physical ID change each time we do a deployment, so we always check for the latest version. This means we will + // never have a strictly no-op deployment, but the SQL Lambda configuration won't change unless the actual layer value changes + let physicalResourceId; + if (shouldProvisionHotswapFriendlyResources(context)) { + physicalResourceId = PhysicalResourceId.of(resourceName); + } else { + physicalResourceId = PhysicalResourceId.of(`${resourceName}-${Date.now().toString()}`); + } + const customResource = new AwsCustomResource(scope, resourceName, { resourceType: 'Custom::SQLLayerVersionCustomResource', onUpdate: { @@ -214,9 +229,7 @@ export const createLayerVersionCustomResource = (scope: Construct, resourceNames Bucket: SQLLayerManifestBucket, Key: key, }, - // Make the physical ID change each time we do a deployment, so we always check for the latest version. This means we will never have - // a strictly no-op deployment, but the SQL Lambda configuration won't change unless the actual layer value changes - physicalResourceId: PhysicalResourceId.of(`${resourceName}-${Date.now().toString()}`), + physicalResourceId, }, policy: AwsCustomResourcePolicy.fromSdkCalls({ resources: [manifestArn], @@ -231,7 +244,11 @@ export const createLayerVersionCustomResource = (scope: Construct, resourceNames * Generates an AwsCustomResource to resolve the SNS Topic ARNs that the lambda used for updating the SQL Lambda Layer version installed * into the customer account. */ -export const createSNSTopicARNCustomResource = (scope: Construct, resourceNames: SQLLambdaResourceNames): AwsCustomResource => { +export const createSNSTopicARNCustomResource = ( + scope: Construct, + resourceNames: SQLLambdaResourceNames, + context: TransformerContextProvider, +): AwsCustomResource => { const { SQLLayerManifestBucket, SQLLayerManifestBucketRegion, SQLSNSTopicARNManifestKeyPrefix } = ResourceConstants.RESOURCES; const key = Fn.join('', [SQLSNSTopicARNManifestKeyPrefix, Fn.ref('AWS::Region')]); @@ -239,6 +256,17 @@ export const createSNSTopicARNCustomResource = (scope: Construct, resourceNames: const manifestArn = `arn:aws:s3:::${SQLLayerManifestBucket}/${key}`; const resourceName = resourceNames.sqlSNSTopicARNResolverCustomResource; + + // If deploying in a sandbox, use the same physical ID to speed up deployments + // Otherwise, make the physical ID change each time we do a deployment, so we always check for the latest version. This means we will + // never have a strictly no-op deployment, but the SQL Lambda configuration won't change unless the actual layer value changes + let physicalResourceId; + if (shouldProvisionHotswapFriendlyResources(context)) { + physicalResourceId = PhysicalResourceId.of(resourceName); + } else { + physicalResourceId = PhysicalResourceId.of(`${resourceName}-${Date.now().toString()}`); + } + const customResource = new AwsCustomResource(scope, resourceName, { resourceType: 'Custom::SQLSNSTopicARNCustomResource', onUpdate: { @@ -249,9 +277,7 @@ export const createSNSTopicARNCustomResource = (scope: Construct, resourceNames: Bucket: SQLLayerManifestBucket, Key: key, }, - // Make the physical ID change each time we do a deployment, so we always check for the latest version. This means we will never have - // a strictly no-op deployment, but the SQL Lambda configuration won't change unless the actual layer value changes - physicalResourceId: PhysicalResourceId.of(`${resourceName}-${Date.now().toString()}`), + physicalResourceId, }, policy: AwsCustomResourcePolicy.fromSdkCalls({ resources: [manifestArn], @@ -262,6 +288,10 @@ export const createSNSTopicARNCustomResource = (scope: Construct, resourceNames: return customResource; }; +const shouldProvisionHotswapFriendlyResources = (context: TransformerContextProvider): boolean => { + return context?.synthParameters?.provisionHotswapFriendlyResources === true; +}; + const addVpcEndpoint = ( scope: Construct, sqlLambdaVpcConfig: VpcConfig, diff --git a/packages/amplify-graphql-model-transformer/src/resources/rds-model-resource-generator.ts b/packages/amplify-graphql-model-transformer/src/resources/rds-model-resource-generator.ts index 85e612ce1f..b0888c3393 100644 --- a/packages/amplify-graphql-model-transformer/src/resources/rds-model-resource-generator.ts +++ b/packages/amplify-graphql-model-transformer/src/resources/rds-model-resource-generator.ts @@ -251,7 +251,7 @@ const resolveLayerVersion = (scope: Construct, context: TransformerContextProvid setRDSLayerMappings(scope, context.rdsLayerMapping, resourceNames); layerVersionArn = Fn.findInMap(resourceNames.sqlLayerVersionMapping, Fn.ref('AWS::Region'), 'layerRegion'); } else { - const layerVersionCustomResource = createLayerVersionCustomResource(scope, resourceNames); + const layerVersionCustomResource = createLayerVersionCustomResource(scope, resourceNames, context); layerVersionArn = layerVersionCustomResource.getResponseField('Body'); } return layerVersionArn; @@ -274,6 +274,6 @@ const resolveSNSTopicARN = (scope: Construct, context: TransformerContextProvide setRDSSNSTopicMappings(scope, context.rdsSnsTopicMapping, resourceNames); return Fn.findInMap(resourceNames.sqlSNSTopicArnMapping, Fn.ref('AWS::Region'), 'topicArn'); } - const layerVersionCustomResource = createSNSTopicARNCustomResource(scope, resourceNames); + const layerVersionCustomResource = createSNSTopicARNCustomResource(scope, resourceNames, context); return layerVersionCustomResource.getResponseField('Body'); }; diff --git a/packages/amplify-graphql-transformer-interfaces/API.md b/packages/amplify-graphql-transformer-interfaces/API.md index 97195a5c56..52f454060a 100644 --- a/packages/amplify-graphql-transformer-interfaces/API.md +++ b/packages/amplify-graphql-transformer-interfaces/API.md @@ -502,6 +502,7 @@ export type SynthParameters = { identityPoolId?: string; adminRoles?: string[]; enableIamAccess?: boolean; + provisionHotswapFriendlyResources?: boolean; }; // @public (undocumented) diff --git a/packages/amplify-graphql-transformer-interfaces/src/transformer-context/synth-parameters.ts b/packages/amplify-graphql-transformer-interfaces/src/transformer-context/synth-parameters.ts index 5bf073d6cf..9dcfe27801 100644 --- a/packages/amplify-graphql-transformer-interfaces/src/transformer-context/synth-parameters.ts +++ b/packages/amplify-graphql-transformer-interfaces/src/transformer-context/synth-parameters.ts @@ -7,4 +7,5 @@ export type SynthParameters = { identityPoolId?: string; adminRoles?: string[]; enableIamAccess?: boolean; + provisionHotswapFriendlyResources?: boolean; }; From 6cded9fd9c6108a50945e87719f5f9cf112136ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Aug 2024 21:16:29 +0000 Subject: [PATCH 09/23] chore(deps): bump axios from 1.6.7 to 1.7.4 in /scripts Bumps [axios](https://github.com/axios/axios) from 1.6.7 to 1.7.4. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v1.6.7...v1.7.4) --- updated-dependencies: - dependency-name: axios dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- scripts/yarn.lock | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/scripts/yarn.lock b/scripts/yarn.lock index e2e5597d0f..d78bd8513c 100644 --- a/scripts/yarn.lock +++ b/scripts/yarn.lock @@ -175,11 +175,11 @@ aws-sdk@2.1414.0: xml2js "0.5.0" axios@^1.6.0: - version "1.6.7" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.7.tgz#7b48c2e27c96f9c68a2f8f31e2ab19f59b06b0a7" - integrity sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA== + version "1.7.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.4.tgz#4c8ded1b43683c8dd362973c393f3ede24052aa2" + integrity sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw== dependencies: - follow-redirects "^1.15.4" + follow-redirects "^1.15.6" form-data "^4.0.0" proxy-from-env "^1.1.0" @@ -302,7 +302,7 @@ execa@^5.1.1: signal-exit "^3.0.3" strip-final-newline "^2.0.0" -follow-redirects@^1.15.4: +follow-redirects@^1.15.6: version "1.15.6" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== @@ -626,8 +626,16 @@ signal-exit@^4.0.1: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.3: - name string-width-cjs +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== From 084b541e64f702013a089882ccbe34a73db848db Mon Sep 17 00:00:00 2001 From: Zeyu Li Date: Wed, 14 Aug 2024 14:36:43 -0700 Subject: [PATCH 10/23] chore: change name to identifier --- packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts b/packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts index bc583a6dd4..7a5f1a2680 100644 --- a/packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts +++ b/packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts @@ -54,7 +54,7 @@ type IamRoleInfo = { }; type RdsInstanceInfo = { - name: string; + identifier: string; region: string; }; @@ -163,7 +163,7 @@ const getOrphanRdsInstances = async (account: AWSAccountInfo, region: string): P const rdsClient = new aws.RDS(getAWSConfig(account, region)); const listRdsInstanceResponse = await rdsClient.describeDBInstances().promise(); const staleInstances = listRdsInstanceResponse.DBInstances.filter(testInstanceStalenessFilter); - return staleInstances.map((i) => ({ name: i.DBInstanceIdentifier, region })); + return staleInstances.map((i) => ({ identifier: i.DBInstanceIdentifier, region })); } catch (e) { if (e?.code === 'InvalidClientTokenId') { // Do not fail the cleanup and continue @@ -626,11 +626,11 @@ const deleteRdsInstances = async (account: AWSAccountInfo, accountIndex: number, }; const deleteRdsInstance = async (account: AWSAccountInfo, accountIndex: number, instance: RdsInstanceInfo): Promise => { - const { name, region } = instance; + const { identifier, region } = instance; console.log(`${generateAccountInfo(account, accountIndex)} Deleting RDS instance ${name}`); try { const rdsClient = new aws.RDS(getAWSConfig(account, region)); - await rdsClient.deleteDBInstance({ DBInstanceIdentifier: name, SkipFinalSnapshot: true }).promise(); + await rdsClient.deleteDBInstance({ DBInstanceIdentifier: identifier, SkipFinalSnapshot: true }).promise(); } catch (e) { console.log(`${generateAccountInfo(account, accountIndex)} Deleting instance ${name} failed with error ${e.message}`); if (e.code === 'ExpiredTokenException') { From 826ffe880a32c5113fae5e0eaf2b1c59cb2acfaa Mon Sep 17 00:00:00 2001 From: Zeyu Li Date: Thu, 15 Aug 2024 11:45:42 -0700 Subject: [PATCH 11/23] fix: undefined var in cleanup script (#2779) --- packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts b/packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts index 7a5f1a2680..18d261ca24 100644 --- a/packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts +++ b/packages/amplify-e2e-tests/src/cleanup-e2e-resources.ts @@ -627,12 +627,12 @@ const deleteRdsInstances = async (account: AWSAccountInfo, accountIndex: number, const deleteRdsInstance = async (account: AWSAccountInfo, accountIndex: number, instance: RdsInstanceInfo): Promise => { const { identifier, region } = instance; - console.log(`${generateAccountInfo(account, accountIndex)} Deleting RDS instance ${name}`); + console.log(`${generateAccountInfo(account, accountIndex)} Deleting RDS instance ${identifier}`); try { const rdsClient = new aws.RDS(getAWSConfig(account, region)); await rdsClient.deleteDBInstance({ DBInstanceIdentifier: identifier, SkipFinalSnapshot: true }).promise(); } catch (e) { - console.log(`${generateAccountInfo(account, accountIndex)} Deleting instance ${name} failed with error ${e.message}`); + console.log(`${generateAccountInfo(account, accountIndex)} Deleting instance ${identifier} failed with error ${e.message}`); if (e.code === 'ExpiredTokenException') { handleExpiredTokenException(); } From 0cedc24723a26acbe0aae084c391c626f80d5737 Mon Sep 17 00:00:00 2001 From: Doesnt Matter Date: Mon, 5 Aug 2024 18:27:37 -0700 Subject: [PATCH 12/23] chore: remove Gen1 only packages --- packages/amplify-category-api/.npmignore | 7 - packages/amplify-category-api/API.md | 190 - packages/amplify-category-api/Readme.md | 14 - .../amplify-category-api/amplify-plugin.json | 24 - .../defaultCustomResources.json | 58 - .../docker-compose.yml | 23 - .../express/Dockerfile | 12 - .../express/DynamoDBActions.js | 62 - .../express/index.js | 124 - .../python/Dockerfile | 17 - .../python/requirements.txt | 1 - .../python/src/server.py | 9 - .../dockerfile-rest-express/Dockerfile | 12 - .../DynamoDBActions.js | 62 - .../dockerfile-rest-express/index.js | 96 - .../graphql-express/Dockerfile | 10 - .../graphql-express/index.js | 27 - .../graphql-express/resolvers.js | 60 - .../graphql-express/schema.js | 16 - .../graphql-schemas/blank-schema.graphql | 0 .../many-relationship-schema-v2.graphql | 18 - .../many-relationship-schema.graphql | 20 - .../single-object-auth-schema-v2.graphql | 18 - .../single-object-auth-schema.graphql | 17 - .../single-object-schema-v2.graphql | 5 - .../single-object-schema.graphql | 5 - .../lambdas/pipeline-on-event.js | 15 - .../awscloudformation/lambdas/pipeline.js | 109 - .../awscloudformation/lambdas/predeploy.js | 19 - .../APIGW/override.ts.sample | 6 - .../overrides-resource/APIGW/package.json | 15 - .../overrides-resource/APIGW/tsconfig.json | 11 - .../APIGW/tsconfig.resource.json | 13 - .../AppSync/override.ts.sample | 5 - .../overrides-resource/AppSync/package.json | 15 - .../overrides-resource/AppSync/tsconfig.json | 10 - .../AppSync/tsconfig.resource.json | 13 - .../resolver-readme/RESOLVER_README.md | 2 - .../sync-conflict-handler-index.js.ejs | 37 - .../sync-conflict-handler-package.json.ejs | 6 - .../sync-conflict-handler-template.json.ejs | 197 - .../APIGatewayCLIInputs.schema.json | 94 - .../appsync/AppSyncCLIInputs.schema.json | 343 -- .../scripts/generateApiSchemas.ts | 17 - .../is-datastore-enabled.test.ts | 40 - .../category-utils/show-auth-acm.test.ts | 99 - .../api/add-graphql-datasource.test.ts | 32 - .../api/mock-data/empty_schema.graphql | 0 .../api/mock-data/invalid_schema.graphql | 7 - .../commands/api/mock-data/schema.graphql | 7 - .../__tests__/commands/api/rebuild.test.ts | 64 - .../errors/amplify-error-converter.test.ts | 49 - .../force-updates/auth-notifications.ts | 201 - .../api-key-helpers.test.ts | 27 - .../graphql-push-schema-checks.test.ts | 124 - ...function-transformer-override.test.ts.snap | 813 --- ...hql-http-transformer-override.test.ts.snap | 1235 ----- ...ql-index-transformer-override.test.ts.snap | 397 -- ...dictions-transformer-override.test.ts.snap | 1749 ------- ...mary-key-transformer-override.test.ts.snap | 427 -- .../model-transformer-override.test.ts.snap | 4467 ----------------- ...phql-function-transformer-override.test.ts | 56 - ...-graphql-http-transformer-override.test.ts | 62 - ...graphql-index-transformer-override.test.ts | 45 - ...l-predictions-transformer-override.test.ts | 49 - ...l-primary-key-transformer-override.test.ts | 43 - ...ql-searchable-transformer-override.test.ts | 103 - .../function-overrides/build/override.js | 15 - .../override/http-overrides/build/override.js | 29 - .../index-overrides/build/override.js | 16 - .../model-overrides/build/override.js | 16 - .../model-transformer-override.test.ts | 65 - .../predictions-overrides/build/override.js | 13 - .../primary-key-overrides/build/override.js | 16 - .../searchable-overrides/build/override.js | 19 - .../sandbox-mode-helpers.test.ts | 125 - .../transform-graphql-schema-v2.test.ts | 245 - .../transformer-feature-flag-adapter.test.ts | 65 - .../transformer-options-v2.test.ts | 19 - .../user-defined-slots.test.ts | 195 - .../graphql-transformer/utils.test.ts | 338 -- .../src/__tests__/index.test.ts | 51 - .../cfn-api-artifact-handler.test.ts.snap | 52 - .../ecs-apigw-stack.test.ts.snap | 2595 ---------- .../legacy-add-resource.test.ts.snap | 17 - .../legacy-update-resource.test.ts.snap | 17 - .../appsync-api-input-state.test.ts | 61 - .../apigw-input-state.test.ts | 239 - .../apigw-stack-builder.test.ts.snap | 846 ---- .../apigw-stack-builder.test.ts | 94 - .../cfn-api-artifact-handler.test.ts | 393 -- .../convert-deprecated-apigw-paths.test.ts | 73 - ...searchable-node-to-node-encryption.test.ts | 71 - .../awscloudformation/ecs-apigw-stack.test.ts | 89 - .../legacy-add-resource.test.ts | 43 - .../legacy-update-resource.test.ts | 42 - .../prompt-to-add-api-key.test.ts | 44 - .../appSync-walkthrough.test.ts.snap | 14 - .../apigw-walkthrough.test.ts | 6 - .../appSync-walkthrough.test.ts | 130 - ...p-sync-auth-type-bi-di-mapper.test.ts.snap | 73 - .../get-appsync-auth-config.test.ts.snap | 28 - ...flict-resolution-bi-di-mapper.test.ts.snap | 45 - ...ugh-result-to-add-api-request.test.ts.snap | 21 - .../utils/amplify-meta-utils.test.ts | 102 - ...to-app-sync-auth-type-bi-di-mapper.test.ts | 102 - .../set-existing-secret-arns.test.ts | 60 - .../utils/database-url.test.ts | 71 - .../utils/get-appsync-auth-config.test.ts | 67 - .../utils/global-sandbox-mode.test.ts | 10 - .../migrate-api-override-resource.test.ts | 78 - .../rds-secrets/database-resources.test.ts | 53 - .../utils/rds-secrets/ssmClient.test.ts | 93 - .../awscloudformation/utils/rds-utils.test.ts | 192 - ...o-conflict-resolution-bi-di-mapper.test.ts | 72 - .../utils/rest-api-path-utils.test.ts | 70 - ...kthrough-result-to-add-api-request.test.ts | 28 - .../src/category-constants.ts | 6 - .../src/category-utils/context-util.ts | 70 - .../category-utils/is-datastore-enabled.ts | 14 - .../src/category-utils/schema-reader.ts | 87 - .../src/category-utils/show-auth-acm.ts | 150 - .../amplify-category-api/src/commands/api.ts | 76 - .../commands/api/add-graphql-datasource.ts | 254 - .../src/commands/api/add.ts | 62 - .../src/commands/api/console.ts | 22 - .../src/commands/api/generate-schema.ts | 98 - .../src/commands/api/gql-compile.ts | 13 - .../src/commands/api/import.ts | 31 - .../src/commands/api/migrate.ts | 47 - .../src/commands/api/override.ts | 97 - .../src/commands/api/push.ts | 11 - .../src/commands/api/rebuild.ts | 39 - .../src/commands/api/remove.ts | 30 - .../src/commands/api/update-secrets.ts | 42 - .../src/commands/api/update.ts | 24 - .../src/errors/amplify-error-converter.ts | 39 - .../src/force-updates/api-resource-paths.ts | 53 - .../src/force-updates/auth-notifications.ts | 244 - .../src/force-updates/force-refresh-schema.ts | 54 - .../src/force-updates/index.ts | 21 - .../amplify-cli-feature-flag-adapter.ts | 37 - .../graphql-transformer/api-key-helpers.ts | 6 - .../src/graphql-transformer/api-utils.ts | 28 - .../graphql-transformer/auth-mode-compare.ts | 42 - .../amplify-api-resource-stack-types.ts | 91 - .../cdk-compat/amplify-s3-asset.ts | 62 - .../cdk-compat/deployment-resources.ts | 46 - .../cdk-compat/nested-stack.ts | 172 - .../cdk-compat/project-config.ts | 18 - .../cdk-compat/root-stack.ts | 43 - .../cdk-compat/stack-synthesizer.ts | 143 - .../cdk-compat/transform-manager.ts | 169 - .../src/graphql-transformer/constants.ts | 6 - .../directive-definitions.ts | 34 - .../src/graphql-transformer/index.ts | 3 - .../src/graphql-transformer/override.ts | 106 - .../sandbox-mode-helpers.ts | 69 - .../graphql-transformer/transform-config.ts | 107 - .../transform-graphql-schema-v1.ts | 466 -- .../transform-graphql-schema-v2.ts | 484 -- .../transform-graphql-schema.ts | 21 - .../transformer-factory.ts | 115 - .../transformer-options-types.ts | 42 - .../transformer-options-v2.ts | 393 -- .../transformer-version.ts | 60 - .../src/graphql-transformer/types/index.ts | 2 - .../src/graphql-transformer/types/types.ts | 11 - .../src/graphql-transformer/types/utils.ts | 184 - .../graphql-transformer/user-defined-slots.ts | 71 - .../src/graphql-transformer/utils.ts | 334 -- packages/amplify-category-api/src/index.ts | 406 -- .../provider-utils/api-artifact-handler.ts | 10 - .../appsync-api-input-state.ts | 53 - .../awscloudformation/apigw-input-state.ts | 179 - .../awscloudformation/aws-constants.ts | 8 - .../awscloudformation/base-api-stack.ts | 582 --- .../cdk-stack-builder/apigw-stack-builder.ts | 508 -- .../apigw-stack-transform.ts | 253 - .../cdk-stack-builder/index.ts | 3 - .../cdk-stack-builder/types.ts | 53 - .../cfn-api-artifact-handler.ts | 443 -- .../awscloudformation/containers-handler.ts | 260 - .../convert-deprecated-apigw-paths.ts | 92 - .../searchable-node-to-node-encryption.ts | 78 - .../default-values/apigw-defaults.ts | 13 - .../default-values/appSync-defaults.ts | 19 - .../default-values/containers-defaults.ts | 10 - .../docker-compose/DockerUtils.ts | 81 - .../docker-compose/compose-spec/v1.ts | 103 - .../docker-compose/compose-spec/v2.ts | 294 -- .../docker-compose/compose-spec/v3.8.ts | 596 --- .../docker-compose/compose-spec/v3.ts | 156 - .../docker-compose/converter.ts | 171 - .../docker-compose/ecs-objects/container.ts | 95 - .../docker-compose/ecs-objects/service.ts | 75 - .../docker-compose/ecs-objects/types.ts | 93 - .../awscloudformation/docker-compose/index.ts | 1 - .../awscloudformation/ecs-alb-stack.ts | 300 -- .../awscloudformation/ecs-apigw-stack.ts | 100 - .../provider-utils/awscloudformation/index.ts | 331 -- .../awscloudformation/legacy-add-resource.ts | 79 - .../legacy-update-resource.ts | 35 - .../pipeline-with-awaiter.ts | 396 -- .../prompt-to-add-api-key.ts | 27 - .../aPIGateway-user-input-types.ts | 37 - .../service-walkthrough-types/apigw-types.ts | 27 - .../appsync-user-input-types.ts | 171 - .../service-walkthroughs/apigw-walkthrough.ts | 739 --- .../appSync-rds-db-config.ts | 63 - .../appSync-rds-walkthrough.ts | 292 -- .../appSync-walkthrough.ts | 1172 ----- .../containers-walkthrough.ts | 358 -- .../import-appsync-api-walkthrough.ts | 114 - .../syncAssets.ts | 16 - .../utils/amplify-meta-utils.ts | 88 - ...nfig-to-app-sync-auth-type-bi-di-mapper.ts | 94 - .../utils/check-appsync-api-migration.ts | 19 - .../utils/containers-artifacts.ts | 362 -- .../containers/set-existing-secret-arns.ts | 56 - .../awscloudformation/utils/database-url.ts | 36 - .../utils/dynamic-imports.ts | 10 - .../utils/edit-schema-flow.ts | 14 - .../utils/get-appsync-auth-config.ts | 19 - .../utils/get-appsync-resolver-config.ts | 16 - .../utils/getAppSyncApiName.ts | 18 - .../awscloudformation/utils/github.ts | 14 - .../utils/global-sandbox-mode.ts | 6 - .../utils/graphql-schema-utils.ts | 120 - .../utils/migrate-api-override-resource.ts | 110 - .../utils/print-api-key-warnings.ts | 19 - .../utils/rds-input-utils.ts | 28 - .../utils/rds-resources/database-resources.ts | 345 -- .../multi-env-database-secrets.ts | 29 - .../utils/rds-resources/ssmClient.ts | 117 - .../utils/rds-resources/utils.ts | 87 - ...fig-to-conflict-resolution-bi-di-mapper.ts | 107 - .../utils/rest-api-path-utils.ts | 89 - ...e-walkthrough-result-to-add-api-request.ts | 18 - .../provider-utils/supported-datasources.ts | 56 - .../src/provider-utils/supported-services.ts | 153 - .../src/provider-utils/vpc-utils.ts | 14 - packages/amplify-category-api/tsconfig.json | 20 - .../amplify-dynamodb-simulator/.npmignore | 2 - .../amplify-dynamodb-simulator/.pid/.gitkeep | 0 .../amplify-dynamodb-simulator/CHANGELOG.md | 576 --- packages/amplify-dynamodb-simulator/README.md | 50 - .../__test__/index.test.js | 103 - packages/amplify-dynamodb-simulator/index.js | 248 - .../amplify-dynamodb-simulator/package.json | 55 - .../scripts/update-ddb-simulator.js | 44 - .../.npmignore | 5 - .../API.md | 23 - .../CHANGELOG.md | 509 -- .../package.json | 81 - .../__snapshots__/auth-tests.ts.snap | 308 -- .../__snapshots__/migrate-tests.ts.snap | 332 -- .../src/__tests__/migration/auth-tests.ts | 488 -- .../src/__tests__/migration/migrate-tests.ts | 421 -- .../amplify/.config/local-env-info.json | 3 - .../amplify/backend/amplify-meta.json | 19 - .../backend/api/testapi/schema/Mud.graphql | 4 - .../testapi/schema/nested/Obligation.graphql | 5 - .../amplify/backend/backend-config.json | 19 - .../v1-schema-project/amplify/cli.json | 10 - .../amplify/team-provider-info.json | 1 - .../migration/schema-inspector.test.ts | 67 - .../migration/schema-migrator.test.ts | 198 - .../src/constants/graphql-directives.ts | 150 - .../src/index.ts | 2 - .../src/migrators/auth/defaultAuth.ts | 20 - .../src/migrators/auth/index.ts | 49 - .../src/migrators/auth/ownerAuth.ts | 61 - .../src/migrators/connection/index.ts | 77 - .../src/migrators/generators/index.ts | 51 - .../src/migrators/key/index.ts | 69 - .../src/migrators/model/index.ts | 3 - .../src/schema-backup.ts | 27 - .../src/schema-inspector.ts | 86 - .../src/schema-migrator.ts | 225 - .../src/state-migrator.ts | 57 - .../src/utils.ts | 44 - .../tsconfig.json | 13 - packages/amplify-util-mock/.gitignore | 3 - packages/amplify-util-mock/.npmignore | 6 - packages/amplify-util-mock/API.md | 15 - packages/amplify-util-mock/Readme.md | 16 - .../amplify-util-mock/amplify-plugin.json | 6 - .../CFNParser/appsync-resource-processor.ts | 153 - .../src/CFNParser/field-parser.ts | 47 - .../CFNParser/import-model-table-resolver.ts | 19 - .../amplify-util-mock/src/CFNParser/index.ts | 1 - .../src/CFNParser/intrinsic-functions.ts | 210 - .../CFNParser/resource-processors/appsync.ts | 265 - .../src/CFNParser/resource-processors/iam.ts | 19 - .../CFNParser/resource-processors/index.ts | 56 - .../CFNParser/resource-processors/lambda.ts | 59 - .../resource-processors/opensearch.ts | 15 - .../src/CFNParser/stack/index.ts | 297 -- .../src/CFNParser/stack/types.ts | 123 - .../amplify-util-mock/src/CFNParser/types.ts | 29 - .../connections-with-auth-tests.e2e.test.ts | 547 -- .../dynamo-db-model-transformer.e2e.test.ts | 767 --- .../__e2e__/function-transformer.e2e.test.ts | 139 - .../src/__e2e__/key-transformer.e2e.test.ts | 745 --- .../src/__e2e__/key-with-auth.e2e.test.ts | 295 -- .../model-auth-transformer.e2e.test.ts | 2623 ---------- .../model-connection-transformer.e2e.test.ts | 500 -- ...onnection-with-key-transformer.e2e.test.ts | 465 -- .../__e2e__/model-with-maps-to.e2e.test.ts | 75 - ...ti-auth-model-auth-transformer.e2e.test.ts | 497 -- .../__e2e__/per-field-auth-tests.e2e.test.ts | 592 --- .../subscriptions-with-auth.e2e.test.ts | 619 --- .../src/__e2e__/util-method-e2e.test.ts | 138 - .../src/__e2e__/utils/cognito-utils.ts | 39 - .../src/__e2e__/utils/graphql-client.ts | 30 - .../src/__e2e__/utils/index.ts | 168 - .../src/__e2e__/utils/lambda-helper.ts | 15 - .../lambda_functions/src/echoFunction.js | 4 - .../utils/lambda_functions/src/hello.js | 4 - .../src/__e2e__/utils/test-storage.ts | 34 - .../versioned-model-transformer.e2e.test.ts | 216 - .../function-transformer.e2e.test.ts | 132 - .../__e2e_v2__/index-transformer.e2e.test.ts | 742 --- .../model-relational-transformer.e2e.test.ts | 231 - ...elational-with-key-transformer.e2e.test.ts | 353 -- .../__e2e_v2__/model-transformer.e2e.test.ts | 747 --- .../searchable-transformer.e2e.test.ts | 80 - .../src/__e2e_v2__/util-method.e2e.test.ts | 144 - .../import-model-table-resolver.test.ts | 11 - .../CFNParser/intrinsic-functions.test.ts | 387 -- .../CFNParser/nested-aws-no-value.test.ts | 61 - .../resource-processors/appsync.test.ts | 24 - .../__tests__/CFNParser/stack/index.test.ts | 721 --- .../api/lambda-arn-to-config.test.ts | 79 - .../func/__snapshots__/index.test.ts.snap | 17 - .../src/__tests__/func/index.test.ts | 150 - .../__tests__/utils/dynamo-db/helper.test.ts | 74 - .../__tests__/utils/dynamo-db/index.test.ts | 135 - .../__tests__/utils/dynamo-db/util.test.ts | 348 -- .../src/__tests__/utils/index.test.ts | 94 - .../utils/lambda/populate-cfn-params.test.ts | 159 - .../populate-lambda-mock-env-vars.test.ts | 90 - .../velocity/acm-resolver-auth.test.ts | 282 -- .../src/__tests__/velocity/admin-auth.test.ts | 180 - .../src/__tests__/velocity/model-auth.test.ts | 1629 ------ .../src/__tests__/velocity/multi-auth.test.ts | 236 - .../velocity/relational-auth.test.ts | 665 --- .../__tests__/velocity/vtl-behavior.test.ts | 36 - .../src/amplify-plugin-index.ts | 14 - packages/amplify-util-mock/src/api/api.ts | 352 -- packages/amplify-util-mock/src/api/index.ts | 14 - .../src/api/lambda-arn-to-config.ts | 43 - .../src/api/resolver-overrides.ts | 190 - .../src/api/run-graphql-transformer.ts | 11 - .../src/commands/mock/api.ts | 18 - .../src/commands/mock/function.ts | 18 - .../src/commands/mock/help.ts | 24 - .../src/commands/mock/mock.ts | 12 - .../src/commands/mock/storage.ts | 18 - packages/amplify-util-mock/src/func/index.ts | 128 - packages/amplify-util-mock/src/index.ts | 1 - packages/amplify-util-mock/src/mockAll.ts | 46 - .../amplify-util-mock/src/storage/index.ts | 33 - .../amplify-util-mock/src/storage/storage.ts | 208 - .../src/utils/config-override.ts | 41 - .../src/utils/dynamo-db/helpers.ts | 29 - .../src/utils/dynamo-db/index.ts | 50 - .../src/utils/dynamo-db/utils.ts | 78 - .../src/utils/error-serializer.ts | 7 - .../amplify-util-mock/src/utils/git-ignore.ts | 16 - packages/amplify-util-mock/src/utils/index.ts | 47 - .../src/utils/lambda/README.md | 1 - .../src/utils/lambda/load-lambda-config.ts | 50 - .../src/utils/lambda/populate-cfn-params.ts | 92 - .../lambda/populate-lambda-mock-env-vars.ts | 77 - .../src/utils/mock-config-file.ts | 8 - .../src/utils/mock-data-directory.ts | 6 - .../amplify-util-mock/src/velocity/index.ts | 113 - packages/amplify-util-mock/tsconfig.json | 20 - packages/graphql-auth-transformer/.npmignore | 5 - packages/graphql-auth-transformer/API.md | 126 - .../graphql-auth-transformer/CHANGELOG.md | 1288 ----- .../graphql-auth-transformer/package.json | 75 - .../graphql-auth-transformer/src/AuthRule.ts | 20 - .../src/ModelAuthTransformer.ts | 2438 --------- .../src/ModelDirectiveConfiguration.ts | 196 - .../src/__tests__/AmplifyAdminAuth.test.ts | 324 -- .../__tests__/GroupAuthTransformer.test.ts | 139 - .../src/__tests__/MultiAuth.test.ts | 886 ---- .../__tests__/NonModelAuthTransformer.test.ts | 337 -- .../src/__tests__/OperationsArgument.test.ts | 250 - .../__tests__/OwnerAuthTransformer.test.ts | 279 - .../__tests__/PerFieldAuthArgument.test.ts | 152 - .../SearchableAuthTransformer.test.ts | 102 - .../OperationsArgument.test.ts.snap | 1256 ----- .../PerFieldAuthArgument.test.ts.snap | 190 - .../SearchableAuthTransformer.test.ts.snap | 206 - .../src/__tests__/test-helpers.ts | 10 - .../graphql-auth-transformer/src/constants.ts | 10 - .../graphql-auth-transformer/src/index.ts | 2 - .../graphql-auth-transformer/src/resources.ts | 1135 ----- .../graphql-auth-transformer/tsconfig.json | 17 - .../graphql-connection-transformer/.npmignore | 5 - .../graphql-connection-transformer/API.md | 36 - .../CHANGELOG.md | 1106 ---- .../package.json | 68 - .../src/ModelConnectionTransformer.ts | 791 --- .../ModelConnectionTransformer.test.ts | 775 --- .../NewConnectionTransformer.test.ts | 695 --- .../ModelConnectionTransformer.test.ts.snap | 255 - .../NewConnectionTransformer.test.ts.snap | 559 --- .../src/definitions.ts | 23 - .../src/index.ts | 2 - .../src/resources.ts | 453 -- .../tsconfig.json | 16 - .../graphql-dynamodb-transformer/.npmignore | 5 - packages/graphql-dynamodb-transformer/API.md | 191 - .../graphql-dynamodb-transformer/CHANGELOG.md | 1180 ----- .../graphql-dynamodb-transformer/package.json | 73 - .../src/DynamoDBModelTransformer.ts | 745 --- .../src/ModelDirectiveArgs.ts | 59 - .../DynamoDBModelTransformer.test.ts | 854 ---- .../src/__tests__/ModelDirectiveArgs.test.ts | 132 - .../DynamoDBModelTransformer.test.ts.snap | 1842 ------- .../src/definitions.ts | 814 --- .../graphql-dynamodb-transformer/src/index.ts | 4 - .../src/resources.ts | 870 ---- .../tsconfig.json | 14 - .../.npmignore | 6 - .../graphql-elasticsearch-transformer/API.md | 39 - .../CHANGELOG.md | 1101 ---- .../package.json | 72 - .../scripts/ddb_to_es.py | 102 - .../src/SearchableModelTransformer.ts | 211 - .../SearchableModelTransformer.test.ts | 147 - .../SearchableModelTransformer.test.ts.snap | 1153 ----- .../src/definitions.ts | 232 - .../src/index.ts | 2 - .../src/resources.ts | 622 --- .../python_streaming_function.py | 263 - .../tsconfig.json | 15 - .../graphql-function-transformer/.npmignore | 5 - packages/graphql-function-transformer/API.md | 32 - .../graphql-function-transformer/CHANGELOG.md | 741 --- .../graphql-function-transformer/package.json | 67 - .../src/FunctionTransformer.ts | 190 - .../src/__tests__/FunctionTransformer.test.ts | 104 - .../graphql-function-transformer/src/index.ts | 2 - .../src/lambdaArns.ts | 28 - .../tsconfig.json | 14 - packages/graphql-http-transformer/.npmignore | 5 - packages/graphql-http-transformer/API.md | 42 - .../graphql-http-transformer/CHANGELOG.md | 944 ---- .../graphql-http-transformer/package.json | 66 - .../src/HttpTransformer.ts | 238 - .../src/__tests__/HttpTransformer.test.ts | 385 -- .../src/definitions.ts | 103 - .../graphql-http-transformer/src/index.ts | 2 - .../graphql-http-transformer/src/resources.ts | 323 -- .../graphql-http-transformer/tsconfig.json | 14 - packages/graphql-key-transformer/.npmignore | 5 - packages/graphql-key-transformer/API.md | 31 - packages/graphql-key-transformer/CHANGELOG.md | 956 ---- packages/graphql-key-transformer/package.json | 68 - .../src/KeyTransformer.ts | 1330 ----- .../src/__tests__/KeyTransformer.test.ts | 537 -- .../__snapshots__/KeyTransformer.test.ts.snap | 1855 ------- packages/graphql-key-transformer/src/index.ts | 2 - .../graphql-key-transformer/tsconfig.json | 15 - .../.npmignore | 6 - .../graphql-predictions-transformer/API.md | 41 - .../CHANGELOG.md | 651 --- .../lambdaFunction/predictionsLambda.js | 35 - .../package.json | 70 - .../src/PredictionsTransformer.ts | 175 - .../__tests__/PredictionsTransformer.test.ts | 107 - .../PredictionsTransformer.test.ts.snap | 208 - .../src/definitions.ts | 74 - .../src/index.ts | 2 - .../src/predictions_utils.ts | 22 - .../src/resources.ts | 479 -- .../tsconfig.json | 14 - .../.npmignore | 5 - .../API.md | 163 - .../CHANGELOG.md | 537 -- .../package.json | 76 - .../src/AuroraDataAPIClient.ts | 128 - .../AuroraServerlessMySQLDatabaseReader.ts | 178 - .../src/IRelationalDBReader.ts | 15 - .../src/RelationalDBMappingTemplate.ts | 20 - .../src/RelationalDBParsingException.ts | 8 - .../src/RelationalDBResolverGenerator.ts | 507 -- .../src/RelationalDBSchemaTransformer.ts | 314 -- .../src/RelationalDBSchemaTransformerUtils.ts | 276 - .../src/RelationalDBTemplateGenerator.ts | 189 - .../src/ResourceConstants.ts | 42 - .../src/__tests__/AuroraDataAPIClient.test.ts | 464 -- .../AuroraServerlessMySQLDBReader.test.ts | 160 - .../RelationalDBMappingTemplate.test.ts | 32 - .../RelationalDBResolverGenerator.test.ts | 169 - .../RelationalDBSchemaTransformer.test.ts | 184 - ...RelationalDBSchemaTransformerUtils.test.ts | 196 - .../RelationalDBTemplateGenerator.test.ts | 84 - ...RelationalDBResolverGenerator.test.ts.snap | 485 -- .../src/index.ts | 4 - .../tsconfig.json | 13 - .../graphql-versioned-transformer/.npmignore | 5 - packages/graphql-versioned-transformer/API.md | 21 - .../CHANGELOG.md | 983 ---- .../package.json | 68 - .../src/VersionedModelTransformer.ts | 213 - .../VersionedModelTransformer.test.ts | 95 - .../src/index.ts | 3 - .../tsconfig.json | 14 - 515 files changed, 99595 deletions(-) delete mode 100644 packages/amplify-category-api/.npmignore delete mode 100644 packages/amplify-category-api/API.md delete mode 100644 packages/amplify-category-api/Readme.md delete mode 100644 packages/amplify-category-api/amplify-plugin.json delete mode 100644 packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/defaultCustomResources.json delete mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/docker-compose.yml delete mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/Dockerfile delete mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/DynamoDBActions.js delete mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/index.js delete mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/Dockerfile delete mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/requirements.txt delete mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/src/server.py delete mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/Dockerfile delete mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/DynamoDBActions.js delete mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/index.js delete mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/Dockerfile delete mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/index.js delete mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/resolvers.js delete mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/schema.js delete mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-schemas/blank-schema.graphql delete mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-schemas/many-relationship-schema-v2.graphql delete mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-schemas/many-relationship-schema.graphql delete mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-auth-schema-v2.graphql delete mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-auth-schema.graphql delete mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-schema-v2.graphql delete mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-schema.graphql delete mode 100644 packages/amplify-category-api/resources/awscloudformation/lambdas/pipeline-on-event.js delete mode 100644 packages/amplify-category-api/resources/awscloudformation/lambdas/pipeline.js delete mode 100644 packages/amplify-category-api/resources/awscloudformation/lambdas/predeploy.js delete mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/override.ts.sample delete mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/package.json delete mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/tsconfig.json delete mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/tsconfig.resource.json delete mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/override.ts.sample delete mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/package.json delete mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/tsconfig.json delete mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/tsconfig.resource.json delete mode 100644 packages/amplify-category-api/resources/awscloudformation/resolver-readme/RESOLVER_README.md delete mode 100644 packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-index.js.ejs delete mode 100644 packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-package.json.ejs delete mode 100644 packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-template.json.ejs delete mode 100644 packages/amplify-category-api/resources/schemas/aPIGateway/APIGatewayCLIInputs.schema.json delete mode 100644 packages/amplify-category-api/resources/schemas/appsync/AppSyncCLIInputs.schema.json delete mode 100644 packages/amplify-category-api/scripts/generateApiSchemas.ts delete mode 100644 packages/amplify-category-api/src/__tests__/category-utils/is-datastore-enabled.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/category-utils/show-auth-acm.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/commands/api/mock-data/empty_schema.graphql delete mode 100644 packages/amplify-category-api/src/__tests__/commands/api/mock-data/invalid_schema.graphql delete mode 100644 packages/amplify-category-api/src/__tests__/commands/api/mock-data/schema.graphql delete mode 100644 packages/amplify-category-api/src/__tests__/commands/api/rebuild.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/errors/amplify-error-converter.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/force-updates/auth-notifications.ts delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/api-key-helpers.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/graphql-push-schema-checks.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-function-transformer-override.test.ts.snap delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-http-transformer-override.test.ts.snap delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-index-transformer-override.test.ts.snap delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-predictions-transformer-override.test.ts.snap delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-primary-key-transformer-override.test.ts.snap delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/model-transformer-override.test.ts.snap delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-function-transformer-override.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-http-transformer-override.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-index-transformer-override.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-predictions-transformer-override.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-primary-key-transformer-override.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-searchable-transformer-override.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/function-overrides/build/override.js delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/http-overrides/build/override.js delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/index-overrides/build/override.js delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/model-overrides/build/override.js delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/model-transformer-override.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/predictions-overrides/build/override.js delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/primary-key-overrides/build/override.js delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/override/searchable-overrides/build/override.js delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/sandbox-mode-helpers.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/transform-graphql-schema-v2.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/transformer-feature-flag-adapter.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/transformer-options-v2.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/user-defined-slots.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/utils.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/index.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/cfn-api-artifact-handler.test.ts.snap delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/ecs-apigw-stack.test.ts.snap delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/legacy-add-resource.test.ts.snap delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/legacy-update-resource.test.ts.snap delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/api-input-manager/appsync-api-input-state.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/apigw-input-state.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cdk-stack-builder/__snapshots__/apigw-stack-builder.test.ts.snap delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cfn-api-artifact-handler.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/convert-deprecated-apigw-paths.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/current-backend-state/searchable-node-to-node-encryption.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/ecs-apigw-stack.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-add-resource.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-update-resource.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/prompt-to-add-api-key.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/__snapshots__/appSync-walkthrough.test.ts.snap delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/auth-config-to-app-sync-auth-type-bi-di-mapper.test.ts.snap delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/get-appsync-auth-config.test.ts.snap delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/resolver-config-to-conflict-resolution-bi-di-mapper.test.ts.snap delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/service-walkthrough-result-to-add-api-request.test.ts.snap delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/amplify-meta-utils.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/containers/set-existing-secret-arns.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/database-url.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/get-appsync-auth-config.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/global-sandbox-mode.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/migrate-api-override-resource.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rds-secrets/database-resources.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rds-secrets/ssmClient.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rds-utils.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/resolver-config-to-conflict-resolution-bi-di-mapper.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rest-api-path-utils.test.ts delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/service-walkthrough-result-to-add-api-request.test.ts delete mode 100644 packages/amplify-category-api/src/category-constants.ts delete mode 100644 packages/amplify-category-api/src/category-utils/context-util.ts delete mode 100644 packages/amplify-category-api/src/category-utils/is-datastore-enabled.ts delete mode 100644 packages/amplify-category-api/src/category-utils/schema-reader.ts delete mode 100644 packages/amplify-category-api/src/category-utils/show-auth-acm.ts delete mode 100644 packages/amplify-category-api/src/commands/api.ts delete mode 100644 packages/amplify-category-api/src/commands/api/add-graphql-datasource.ts delete mode 100644 packages/amplify-category-api/src/commands/api/add.ts delete mode 100644 packages/amplify-category-api/src/commands/api/console.ts delete mode 100644 packages/amplify-category-api/src/commands/api/generate-schema.ts delete mode 100644 packages/amplify-category-api/src/commands/api/gql-compile.ts delete mode 100644 packages/amplify-category-api/src/commands/api/import.ts delete mode 100644 packages/amplify-category-api/src/commands/api/migrate.ts delete mode 100644 packages/amplify-category-api/src/commands/api/override.ts delete mode 100644 packages/amplify-category-api/src/commands/api/push.ts delete mode 100644 packages/amplify-category-api/src/commands/api/rebuild.ts delete mode 100644 packages/amplify-category-api/src/commands/api/remove.ts delete mode 100644 packages/amplify-category-api/src/commands/api/update-secrets.ts delete mode 100644 packages/amplify-category-api/src/commands/api/update.ts delete mode 100644 packages/amplify-category-api/src/errors/amplify-error-converter.ts delete mode 100644 packages/amplify-category-api/src/force-updates/api-resource-paths.ts delete mode 100644 packages/amplify-category-api/src/force-updates/auth-notifications.ts delete mode 100644 packages/amplify-category-api/src/force-updates/force-refresh-schema.ts delete mode 100644 packages/amplify-category-api/src/force-updates/index.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/amplify-cli-feature-flag-adapter.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/api-key-helpers.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/api-utils.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/auth-mode-compare.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/cdk-compat/amplify-api-resource-stack-types.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/cdk-compat/amplify-s3-asset.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/cdk-compat/deployment-resources.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/cdk-compat/nested-stack.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/cdk-compat/project-config.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/cdk-compat/root-stack.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/cdk-compat/stack-synthesizer.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/cdk-compat/transform-manager.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/constants.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/directive-definitions.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/index.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/override.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/sandbox-mode-helpers.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/transform-config.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema-v1.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema-v2.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/transformer-factory.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/transformer-options-types.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/transformer-options-v2.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/transformer-version.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/types/index.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/types/types.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/types/utils.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/user-defined-slots.ts delete mode 100644 packages/amplify-category-api/src/graphql-transformer/utils.ts delete mode 100644 packages/amplify-category-api/src/index.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/api-artifact-handler.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/api-input-manager/appsync-api-input-state.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/apigw-input-state.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/aws-constants.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/base-api-stack.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-transform.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/index.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/types.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/cfn-api-artifact-handler.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/containers-handler.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/convert-deprecated-apigw-paths.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/current-backend-state/searchable-node-to-node-encryption.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/containers-defaults.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/DockerUtils.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v1.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v2.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v3.8.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v3.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/converter.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/container.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/service.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/types.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/index.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/ecs-alb-stack.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/ecs-apigw-stack.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/legacy-add-resource.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/legacy-update-resource.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/pipeline-with-awaiter.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/prompt-to-add-api-key.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/aPIGateway-user-input-types.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/apigw-types.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/appsync-user-input-types.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-db-config.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/containers-walkthrough.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/import-appsync-api-walkthrough.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/amplify-meta-utils.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-appsync-api-migration.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/containers-artifacts.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/containers/set-existing-secret-arns.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/database-url.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/dynamic-imports.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/edit-schema-flow.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/get-appsync-auth-config.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/get-appsync-resolver-config.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/getAppSyncApiName.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/github.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/global-sandbox-mode.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/graphql-schema-utils.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/migrate-api-override-resource.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/print-api-key-warnings.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-input-utils.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-resources/database-resources.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-resources/multi-env-database-secrets.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-resources/ssmClient.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-resources/utils.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/resolver-config-to-conflict-resolution-bi-di-mapper.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rest-api-path-utils.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/service-walkthrough-result-to-add-api-request.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/supported-datasources.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/supported-services.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/vpc-utils.ts delete mode 100644 packages/amplify-category-api/tsconfig.json delete mode 100644 packages/amplify-dynamodb-simulator/.npmignore delete mode 100644 packages/amplify-dynamodb-simulator/.pid/.gitkeep delete mode 100644 packages/amplify-dynamodb-simulator/CHANGELOG.md delete mode 100644 packages/amplify-dynamodb-simulator/README.md delete mode 100644 packages/amplify-dynamodb-simulator/__test__/index.test.js delete mode 100644 packages/amplify-dynamodb-simulator/index.js delete mode 100644 packages/amplify-dynamodb-simulator/package.json delete mode 100644 packages/amplify-dynamodb-simulator/scripts/update-ddb-simulator.js delete mode 100644 packages/amplify-graphql-transformer-migrator/.npmignore delete mode 100644 packages/amplify-graphql-transformer-migrator/API.md delete mode 100644 packages/amplify-graphql-transformer-migrator/CHANGELOG.md delete mode 100644 packages/amplify-graphql-transformer-migrator/package.json delete mode 100644 packages/amplify-graphql-transformer-migrator/src/__tests__/migration/__snapshots__/auth-tests.ts.snap delete mode 100644 packages/amplify-graphql-transformer-migrator/src/__tests__/migration/__snapshots__/migrate-tests.ts.snap delete mode 100644 packages/amplify-graphql-transformer-migrator/src/__tests__/migration/auth-tests.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/src/__tests__/migration/migrate-tests.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/.config/local-env-info.json delete mode 100644 packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/backend/amplify-meta.json delete mode 100644 packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/backend/api/testapi/schema/Mud.graphql delete mode 100644 packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/backend/api/testapi/schema/nested/Obligation.graphql delete mode 100644 packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/backend/backend-config.json delete mode 100644 packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/cli.json delete mode 100644 packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/team-provider-info.json delete mode 100644 packages/amplify-graphql-transformer-migrator/src/__tests__/migration/schema-inspector.test.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/src/__tests__/migration/schema-migrator.test.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/src/constants/graphql-directives.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/src/index.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/src/migrators/auth/defaultAuth.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/src/migrators/auth/index.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/src/migrators/auth/ownerAuth.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/src/migrators/connection/index.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/src/migrators/generators/index.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/src/migrators/key/index.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/src/migrators/model/index.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/src/schema-backup.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/src/schema-inspector.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/src/schema-migrator.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/src/state-migrator.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/src/utils.ts delete mode 100644 packages/amplify-graphql-transformer-migrator/tsconfig.json delete mode 100644 packages/amplify-util-mock/.gitignore delete mode 100644 packages/amplify-util-mock/.npmignore delete mode 100644 packages/amplify-util-mock/API.md delete mode 100644 packages/amplify-util-mock/Readme.md delete mode 100644 packages/amplify-util-mock/amplify-plugin.json delete mode 100644 packages/amplify-util-mock/src/CFNParser/appsync-resource-processor.ts delete mode 100644 packages/amplify-util-mock/src/CFNParser/field-parser.ts delete mode 100644 packages/amplify-util-mock/src/CFNParser/import-model-table-resolver.ts delete mode 100644 packages/amplify-util-mock/src/CFNParser/index.ts delete mode 100644 packages/amplify-util-mock/src/CFNParser/intrinsic-functions.ts delete mode 100644 packages/amplify-util-mock/src/CFNParser/resource-processors/appsync.ts delete mode 100644 packages/amplify-util-mock/src/CFNParser/resource-processors/iam.ts delete mode 100644 packages/amplify-util-mock/src/CFNParser/resource-processors/index.ts delete mode 100644 packages/amplify-util-mock/src/CFNParser/resource-processors/lambda.ts delete mode 100644 packages/amplify-util-mock/src/CFNParser/resource-processors/opensearch.ts delete mode 100644 packages/amplify-util-mock/src/CFNParser/stack/index.ts delete mode 100644 packages/amplify-util-mock/src/CFNParser/stack/types.ts delete mode 100644 packages/amplify-util-mock/src/CFNParser/types.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/connections-with-auth-tests.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/dynamo-db-model-transformer.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/function-transformer.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/key-transformer.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/key-with-auth.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/model-auth-transformer.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/model-connection-transformer.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/model-connection-with-key-transformer.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/model-with-maps-to.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/multi-auth-model-auth-transformer.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/per-field-auth-tests.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/subscriptions-with-auth.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/util-method-e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/utils/cognito-utils.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/utils/graphql-client.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/utils/index.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/utils/lambda-helper.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/utils/lambda_functions/src/echoFunction.js delete mode 100644 packages/amplify-util-mock/src/__e2e__/utils/lambda_functions/src/hello.js delete mode 100644 packages/amplify-util-mock/src/__e2e__/utils/test-storage.ts delete mode 100644 packages/amplify-util-mock/src/__e2e__/versioned-model-transformer.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e_v2__/function-transformer.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e_v2__/index-transformer.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e_v2__/model-relational-transformer.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e_v2__/model-relational-with-key-transformer.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e_v2__/model-transformer.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e_v2__/searchable-transformer.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__e2e_v2__/util-method.e2e.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/CFNParser/import-model-table-resolver.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/CFNParser/intrinsic-functions.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/CFNParser/nested-aws-no-value.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/CFNParser/resource-processors/appsync.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/CFNParser/stack/index.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/api/lambda-arn-to-config.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/func/__snapshots__/index.test.ts.snap delete mode 100644 packages/amplify-util-mock/src/__tests__/func/index.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/utils/dynamo-db/helper.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/utils/dynamo-db/index.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/utils/dynamo-db/util.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/utils/index.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/utils/lambda/populate-cfn-params.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/utils/lambda/populate-lambda-mock-env-vars.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/velocity/acm-resolver-auth.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/velocity/admin-auth.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/velocity/model-auth.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/velocity/multi-auth.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/velocity/relational-auth.test.ts delete mode 100644 packages/amplify-util-mock/src/__tests__/velocity/vtl-behavior.test.ts delete mode 100644 packages/amplify-util-mock/src/amplify-plugin-index.ts delete mode 100644 packages/amplify-util-mock/src/api/api.ts delete mode 100644 packages/amplify-util-mock/src/api/index.ts delete mode 100644 packages/amplify-util-mock/src/api/lambda-arn-to-config.ts delete mode 100644 packages/amplify-util-mock/src/api/resolver-overrides.ts delete mode 100644 packages/amplify-util-mock/src/api/run-graphql-transformer.ts delete mode 100644 packages/amplify-util-mock/src/commands/mock/api.ts delete mode 100644 packages/amplify-util-mock/src/commands/mock/function.ts delete mode 100644 packages/amplify-util-mock/src/commands/mock/help.ts delete mode 100644 packages/amplify-util-mock/src/commands/mock/mock.ts delete mode 100644 packages/amplify-util-mock/src/commands/mock/storage.ts delete mode 100644 packages/amplify-util-mock/src/func/index.ts delete mode 100644 packages/amplify-util-mock/src/index.ts delete mode 100644 packages/amplify-util-mock/src/mockAll.ts delete mode 100644 packages/amplify-util-mock/src/storage/index.ts delete mode 100644 packages/amplify-util-mock/src/storage/storage.ts delete mode 100644 packages/amplify-util-mock/src/utils/config-override.ts delete mode 100644 packages/amplify-util-mock/src/utils/dynamo-db/helpers.ts delete mode 100644 packages/amplify-util-mock/src/utils/dynamo-db/index.ts delete mode 100644 packages/amplify-util-mock/src/utils/dynamo-db/utils.ts delete mode 100644 packages/amplify-util-mock/src/utils/error-serializer.ts delete mode 100644 packages/amplify-util-mock/src/utils/git-ignore.ts delete mode 100644 packages/amplify-util-mock/src/utils/index.ts delete mode 100644 packages/amplify-util-mock/src/utils/lambda/README.md delete mode 100644 packages/amplify-util-mock/src/utils/lambda/load-lambda-config.ts delete mode 100644 packages/amplify-util-mock/src/utils/lambda/populate-cfn-params.ts delete mode 100644 packages/amplify-util-mock/src/utils/lambda/populate-lambda-mock-env-vars.ts delete mode 100644 packages/amplify-util-mock/src/utils/mock-config-file.ts delete mode 100644 packages/amplify-util-mock/src/utils/mock-data-directory.ts delete mode 100644 packages/amplify-util-mock/src/velocity/index.ts delete mode 100644 packages/amplify-util-mock/tsconfig.json delete mode 100644 packages/graphql-auth-transformer/.npmignore delete mode 100644 packages/graphql-auth-transformer/API.md delete mode 100644 packages/graphql-auth-transformer/CHANGELOG.md delete mode 100644 packages/graphql-auth-transformer/package.json delete mode 100644 packages/graphql-auth-transformer/src/AuthRule.ts delete mode 100644 packages/graphql-auth-transformer/src/ModelAuthTransformer.ts delete mode 100644 packages/graphql-auth-transformer/src/ModelDirectiveConfiguration.ts delete mode 100644 packages/graphql-auth-transformer/src/__tests__/AmplifyAdminAuth.test.ts delete mode 100644 packages/graphql-auth-transformer/src/__tests__/GroupAuthTransformer.test.ts delete mode 100644 packages/graphql-auth-transformer/src/__tests__/MultiAuth.test.ts delete mode 100644 packages/graphql-auth-transformer/src/__tests__/NonModelAuthTransformer.test.ts delete mode 100644 packages/graphql-auth-transformer/src/__tests__/OperationsArgument.test.ts delete mode 100644 packages/graphql-auth-transformer/src/__tests__/OwnerAuthTransformer.test.ts delete mode 100644 packages/graphql-auth-transformer/src/__tests__/PerFieldAuthArgument.test.ts delete mode 100644 packages/graphql-auth-transformer/src/__tests__/SearchableAuthTransformer.test.ts delete mode 100644 packages/graphql-auth-transformer/src/__tests__/__snapshots__/OperationsArgument.test.ts.snap delete mode 100644 packages/graphql-auth-transformer/src/__tests__/__snapshots__/PerFieldAuthArgument.test.ts.snap delete mode 100644 packages/graphql-auth-transformer/src/__tests__/__snapshots__/SearchableAuthTransformer.test.ts.snap delete mode 100644 packages/graphql-auth-transformer/src/__tests__/test-helpers.ts delete mode 100644 packages/graphql-auth-transformer/src/constants.ts delete mode 100644 packages/graphql-auth-transformer/src/index.ts delete mode 100644 packages/graphql-auth-transformer/src/resources.ts delete mode 100644 packages/graphql-auth-transformer/tsconfig.json delete mode 100644 packages/graphql-connection-transformer/.npmignore delete mode 100644 packages/graphql-connection-transformer/API.md delete mode 100644 packages/graphql-connection-transformer/CHANGELOG.md delete mode 100644 packages/graphql-connection-transformer/package.json delete mode 100644 packages/graphql-connection-transformer/src/ModelConnectionTransformer.ts delete mode 100644 packages/graphql-connection-transformer/src/__tests__/ModelConnectionTransformer.test.ts delete mode 100644 packages/graphql-connection-transformer/src/__tests__/NewConnectionTransformer.test.ts delete mode 100644 packages/graphql-connection-transformer/src/__tests__/__snapshots__/ModelConnectionTransformer.test.ts.snap delete mode 100644 packages/graphql-connection-transformer/src/__tests__/__snapshots__/NewConnectionTransformer.test.ts.snap delete mode 100644 packages/graphql-connection-transformer/src/definitions.ts delete mode 100644 packages/graphql-connection-transformer/src/index.ts delete mode 100644 packages/graphql-connection-transformer/src/resources.ts delete mode 100644 packages/graphql-connection-transformer/tsconfig.json delete mode 100644 packages/graphql-dynamodb-transformer/.npmignore delete mode 100644 packages/graphql-dynamodb-transformer/API.md delete mode 100644 packages/graphql-dynamodb-transformer/CHANGELOG.md delete mode 100644 packages/graphql-dynamodb-transformer/package.json delete mode 100644 packages/graphql-dynamodb-transformer/src/DynamoDBModelTransformer.ts delete mode 100644 packages/graphql-dynamodb-transformer/src/ModelDirectiveArgs.ts delete mode 100644 packages/graphql-dynamodb-transformer/src/__tests__/DynamoDBModelTransformer.test.ts delete mode 100644 packages/graphql-dynamodb-transformer/src/__tests__/ModelDirectiveArgs.test.ts delete mode 100644 packages/graphql-dynamodb-transformer/src/__tests__/__snapshots__/DynamoDBModelTransformer.test.ts.snap delete mode 100644 packages/graphql-dynamodb-transformer/src/definitions.ts delete mode 100644 packages/graphql-dynamodb-transformer/src/index.ts delete mode 100644 packages/graphql-dynamodb-transformer/src/resources.ts delete mode 100644 packages/graphql-dynamodb-transformer/tsconfig.json delete mode 100644 packages/graphql-elasticsearch-transformer/.npmignore delete mode 100644 packages/graphql-elasticsearch-transformer/API.md delete mode 100644 packages/graphql-elasticsearch-transformer/CHANGELOG.md delete mode 100644 packages/graphql-elasticsearch-transformer/package.json delete mode 100644 packages/graphql-elasticsearch-transformer/scripts/ddb_to_es.py delete mode 100644 packages/graphql-elasticsearch-transformer/src/SearchableModelTransformer.ts delete mode 100644 packages/graphql-elasticsearch-transformer/src/__tests__/SearchableModelTransformer.test.ts delete mode 100644 packages/graphql-elasticsearch-transformer/src/__tests__/__snapshots__/SearchableModelTransformer.test.ts.snap delete mode 100644 packages/graphql-elasticsearch-transformer/src/definitions.ts delete mode 100644 packages/graphql-elasticsearch-transformer/src/index.ts delete mode 100644 packages/graphql-elasticsearch-transformer/src/resources.ts delete mode 100644 packages/graphql-elasticsearch-transformer/streaming-lambda/python_streaming_function.py delete mode 100644 packages/graphql-elasticsearch-transformer/tsconfig.json delete mode 100644 packages/graphql-function-transformer/.npmignore delete mode 100644 packages/graphql-function-transformer/API.md delete mode 100644 packages/graphql-function-transformer/CHANGELOG.md delete mode 100644 packages/graphql-function-transformer/package.json delete mode 100644 packages/graphql-function-transformer/src/FunctionTransformer.ts delete mode 100644 packages/graphql-function-transformer/src/__tests__/FunctionTransformer.test.ts delete mode 100644 packages/graphql-function-transformer/src/index.ts delete mode 100644 packages/graphql-function-transformer/src/lambdaArns.ts delete mode 100644 packages/graphql-function-transformer/tsconfig.json delete mode 100644 packages/graphql-http-transformer/.npmignore delete mode 100644 packages/graphql-http-transformer/API.md delete mode 100644 packages/graphql-http-transformer/CHANGELOG.md delete mode 100644 packages/graphql-http-transformer/package.json delete mode 100644 packages/graphql-http-transformer/src/HttpTransformer.ts delete mode 100644 packages/graphql-http-transformer/src/__tests__/HttpTransformer.test.ts delete mode 100644 packages/graphql-http-transformer/src/definitions.ts delete mode 100644 packages/graphql-http-transformer/src/index.ts delete mode 100644 packages/graphql-http-transformer/src/resources.ts delete mode 100644 packages/graphql-http-transformer/tsconfig.json delete mode 100644 packages/graphql-key-transformer/.npmignore delete mode 100644 packages/graphql-key-transformer/API.md delete mode 100644 packages/graphql-key-transformer/CHANGELOG.md delete mode 100644 packages/graphql-key-transformer/package.json delete mode 100644 packages/graphql-key-transformer/src/KeyTransformer.ts delete mode 100644 packages/graphql-key-transformer/src/__tests__/KeyTransformer.test.ts delete mode 100644 packages/graphql-key-transformer/src/__tests__/__snapshots__/KeyTransformer.test.ts.snap delete mode 100644 packages/graphql-key-transformer/src/index.ts delete mode 100644 packages/graphql-key-transformer/tsconfig.json delete mode 100644 packages/graphql-predictions-transformer/.npmignore delete mode 100644 packages/graphql-predictions-transformer/API.md delete mode 100644 packages/graphql-predictions-transformer/CHANGELOG.md delete mode 100644 packages/graphql-predictions-transformer/lambdaFunction/predictionsLambda.js delete mode 100644 packages/graphql-predictions-transformer/package.json delete mode 100644 packages/graphql-predictions-transformer/src/PredictionsTransformer.ts delete mode 100644 packages/graphql-predictions-transformer/src/__tests__/PredictionsTransformer.test.ts delete mode 100644 packages/graphql-predictions-transformer/src/__tests__/__snapshots__/PredictionsTransformer.test.ts.snap delete mode 100644 packages/graphql-predictions-transformer/src/definitions.ts delete mode 100644 packages/graphql-predictions-transformer/src/index.ts delete mode 100644 packages/graphql-predictions-transformer/src/predictions_utils.ts delete mode 100644 packages/graphql-predictions-transformer/src/resources.ts delete mode 100644 packages/graphql-predictions-transformer/tsconfig.json delete mode 100644 packages/graphql-relational-schema-transformer/.npmignore delete mode 100644 packages/graphql-relational-schema-transformer/API.md delete mode 100644 packages/graphql-relational-schema-transformer/CHANGELOG.md delete mode 100644 packages/graphql-relational-schema-transformer/package.json delete mode 100644 packages/graphql-relational-schema-transformer/src/AuroraDataAPIClient.ts delete mode 100644 packages/graphql-relational-schema-transformer/src/AuroraServerlessMySQLDatabaseReader.ts delete mode 100644 packages/graphql-relational-schema-transformer/src/IRelationalDBReader.ts delete mode 100644 packages/graphql-relational-schema-transformer/src/RelationalDBMappingTemplate.ts delete mode 100644 packages/graphql-relational-schema-transformer/src/RelationalDBParsingException.ts delete mode 100644 packages/graphql-relational-schema-transformer/src/RelationalDBResolverGenerator.ts delete mode 100644 packages/graphql-relational-schema-transformer/src/RelationalDBSchemaTransformer.ts delete mode 100644 packages/graphql-relational-schema-transformer/src/RelationalDBSchemaTransformerUtils.ts delete mode 100644 packages/graphql-relational-schema-transformer/src/RelationalDBTemplateGenerator.ts delete mode 100644 packages/graphql-relational-schema-transformer/src/ResourceConstants.ts delete mode 100644 packages/graphql-relational-schema-transformer/src/__tests__/AuroraDataAPIClient.test.ts delete mode 100644 packages/graphql-relational-schema-transformer/src/__tests__/AuroraServerlessMySQLDBReader.test.ts delete mode 100644 packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBMappingTemplate.test.ts delete mode 100644 packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBResolverGenerator.test.ts delete mode 100644 packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBSchemaTransformer.test.ts delete mode 100644 packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBSchemaTransformerUtils.test.ts delete mode 100644 packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBTemplateGenerator.test.ts delete mode 100644 packages/graphql-relational-schema-transformer/src/__tests__/__snapshots__/RelationalDBResolverGenerator.test.ts.snap delete mode 100644 packages/graphql-relational-schema-transformer/src/index.ts delete mode 100644 packages/graphql-relational-schema-transformer/tsconfig.json delete mode 100644 packages/graphql-versioned-transformer/.npmignore delete mode 100644 packages/graphql-versioned-transformer/API.md delete mode 100644 packages/graphql-versioned-transformer/CHANGELOG.md delete mode 100644 packages/graphql-versioned-transformer/package.json delete mode 100644 packages/graphql-versioned-transformer/src/VersionedModelTransformer.ts delete mode 100644 packages/graphql-versioned-transformer/src/__tests__/VersionedModelTransformer.test.ts delete mode 100644 packages/graphql-versioned-transformer/src/index.ts delete mode 100644 packages/graphql-versioned-transformer/tsconfig.json diff --git a/packages/amplify-category-api/.npmignore b/packages/amplify-category-api/.npmignore deleted file mode 100644 index a1f3bf2a32..0000000000 --- a/packages/amplify-category-api/.npmignore +++ /dev/null @@ -1,7 +0,0 @@ -**/__mocks__/** -**/__tests__/** -./src -tsconfig.json -tsconfig.tsbuildinfo -!resources/awscloudformation/overrides-resource/AppSync/tsconfig.json -!resources/awscloudformation/overrides-resource/APIGW/tsconfig.json diff --git a/packages/amplify-category-api/API.md b/packages/amplify-category-api/API.md deleted file mode 100644 index 07fe0f852d..0000000000 --- a/packages/amplify-category-api/API.md +++ /dev/null @@ -1,190 +0,0 @@ -## API Report File for "@aws-amplify/amplify-category-api" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import * as cdk from 'aws-cdk-lib'; -import * as cloudmap from 'aws-cdk-lib/aws-servicediscovery'; -import { Construct } from 'constructs'; -import { DeploymentResources as DeploymentResources_2 } from 'graphql-transformer-core'; -import * as ec2 from 'aws-cdk-lib/aws-ec2'; -import * as ecs from 'aws-cdk-lib/aws-ecs'; -import * as iam from 'aws-cdk-lib/aws-iam'; -import { ResolverConfig } from 'graphql-transformer-core'; - -// @public (undocumented) -export function addAdminQueriesApi(context: $TSContext, apiProps: { - apiName: string; - functionName: string; - authResourceName: string; - dependsOn: Record[]; -}): Promise; - -// @public (undocumented) -export const addGraphQLAuthorizationMode: (context: $TSContext, args: Record) => Promise<{ - authenticationType: string; -}>; - -// @public (undocumented) -export type ApiResource = { - category: string; - resourceName: string; - gitHubInfo?: { - path: string; - tokenSecretArn: string; - }; - deploymentMechanism: DEPLOYMENT_MECHANISM; - authName: string; - restrictAccess: boolean; - dependsOn: ResourceDependency[]; - environmentMap: Record; - categoryPolicies: any[]; - mutableParametersState: any; - output?: Record; - apiType?: API_TYPE; - exposedContainer?: { - name: string; - port: number; - }; -}; - -// @public (undocumented) -export const checkForcedUpdates: (context: $TSContext) => Promise; - -// @public (undocumented) -const console_2: (context: $TSContext) => Promise; -export { console_2 as console } - -// @public (undocumented) -export function convertDeperecatedRestApiPaths(deprecatedParametersFileName: string, deprecatedParametersFilePath: string, resourceName: string): {}; - -// @public (undocumented) -export enum DEPLOYMENT_MECHANISM { - // (undocumented) - FULLY_MANAGED = "FULLY_MANAGED", - // (undocumented) - INDENPENDENTLY_MANAGED = "INDENPENDENTLY_MANAGED", - // (undocumented) - SELF_MANAGED = "SELF_MANAGED" -} - -// Warning: (ae-forgotten-export) The symbol "ContainersStack" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export class EcsAlbStack extends ContainersStack { - // Warning: (ae-forgotten-export) The symbol "EcsStackProps" needs to be exported by the entry point index.d.ts - constructor(scope: Construct, id: string, ecsProps: EcsStackProps); -} - -// @public (undocumented) -export class EcsStack extends ContainersStack { - // Warning: (ae-forgotten-export) The symbol "EcsStackProps_2" needs to be exported by the entry point index.d.ts - constructor(scope: Construct, id: string, ecsProps: EcsStackProps_2); -} - -// @public (undocumented) -export const executeAmplifyCommand: (context: $TSContext) => Promise; - -// @public (undocumented) -export const executeAmplifyHeadlessCommand: (context: $TSContext, headlessPayload: string) => Promise; - -// Warning: (ae-forgotten-export) The symbol "ContainerArtifactsMetadata" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export function generateContainersArtifacts(context: $TSContext, resource: ApiResource, askForExposedContainer?: boolean): Promise; - -// @public (undocumented) -export const getAuthConfig: (context: $TSContext, resourceName: string) => Promise<{ - defaultAuthentication: any; - additionalAuthenticationProviders: any[]; -}>; - -// Warning: (ae-forgotten-export) The symbol "DockerServiceInfo" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export function getContainers(composeContents?: string, dockerfileContents?: string): DockerServiceInfo; - -// @public (undocumented) -export const getDirectiveDefinitions: (context: $TSContext, resourceDir: string) => Promise; - -// @public (undocumented) -export function getGitHubOwnerRepoFromPath(path: string): { - owner: string; - repo: string; - branch: string; - path: string; -}; - -// @public (undocumented) -export const getPermissionPolicies: (context: $TSContext, resourceOpsMapping: Record) => Promise<{ - permissionPolicies: any[]; - resourceAttributes: any[]; -}>; - -// @public (undocumented) -export const getResolverConfig: (context: $TSContext, resourceName: string) => Promise; - -// @public (undocumented) -export const getTransformerVersion: (context: any) => Promise; - -// @public (undocumented) -export const handleAmplifyEvent: (context: $TSContext, args: any) => Promise; - -// @public (undocumented) -export const initEnv: (context: $TSContext) => Promise; - -// @public (undocumented) -export const isDataStoreEnabled: (context: $TSContext) => Promise; - -// @public (undocumented) -export const migrate: (context: $TSContext, serviceName?: string) => Promise; - -// @public (undocumented) -export const NETWORK_STACK_LOGICAL_ID = "NetworkStack"; - -// @public (undocumented) -export function processDockerConfig(context: $TSContext, resource: ApiResource, srcPath: string, askForExposedContainer?: boolean): Promise<{ - containersPorts: number[]; - containers: Container[]; - isInitialDeploy: boolean; - desiredCount: number; - exposedContainer: { - name: string; - port: number; - }; - secretsArns: Map; -}>; - -// @public (undocumented) -export function promptToAddApiKey(context: $TSContext): Promise; - -// @public (undocumented) -export const showApiAuthAcm: (context: $TSContext, modelName: string) => Promise; - -// @public (undocumented) -export const transformCategoryStack: (context: $TSContext, resource: Record) => Promise; - -// Warning: (ae-forgotten-export) The symbol "DeploymentResources" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export const transformGraphQLSchema: (context: $TSContext, options: any) => Promise; - -// @public (undocumented) -export function updateAdminQueriesApi(context: $TSContext, apiProps: { - apiName: string; - functionName: string; - authResourceName: string; - dependsOn: Record[]; -}): Promise; - -// Warnings were encountered during analysis: -// -// src/provider-utils/awscloudformation/utils/containers-artifacts.ts:30:3 - (ae-forgotten-export) The symbol "ResourceDependency" needs to be exported by the entry point index.d.ts -// src/provider-utils/awscloudformation/utils/containers-artifacts.ts:35:3 - (ae-forgotten-export) The symbol "API_TYPE" needs to be exported by the entry point index.d.ts -// src/provider-utils/awscloudformation/utils/containers-artifacts.ts:124:42 - (ae-forgotten-export) The symbol "Container" needs to be exported by the entry point index.d.ts - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/amplify-category-api/Readme.md b/packages/amplify-category-api/Readme.md deleted file mode 100644 index f401238340..0000000000 --- a/packages/amplify-category-api/Readme.md +++ /dev/null @@ -1,14 +0,0 @@ -# Amplify CLI API Plugin - -## Commands Summary - -The following table lists the current set of commands supported by the Amplify API Category Plugin. - -| Command | Description | -| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | -| amplify api add | Takes you through steps in the CLI to add an API resource to your backend. | -| amplify api add-graphql-datasource | Takes you through the steps in the CLI to import an already existing Aurora Serverless data source to an existing GraphQL API resource. | -| amplify api update | Takes you through steps in the CLI to update an API resource. | -| amplify api gql-compile | Compiles your GraphQL schema and generates a corresponding cloudformation template. | -| amplify api push | Provisions only API cloud resources with the latest local developments. | -| amplify api remove | Removes an API resource from your local backend. The resource is removed from the cloud on the next push command. | diff --git a/packages/amplify-category-api/amplify-plugin.json b/packages/amplify-category-api/amplify-plugin.json deleted file mode 100644 index 4607343489..0000000000 --- a/packages/amplify-category-api/amplify-plugin.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "api", - "type": "category", - "commands": [ - "add-graphql-datasource", - "add", - "console", - "gql-compile", - "migrate", - "override", - "push", - "rebuild", - "remove", - "update", - "help", - "import", - "generate-schema", - "update-secrets" - ], - "commandAliases": { - "configure": "update" - }, - "eventHandlers": ["InternalOnlyPostEnvRemove"] -} diff --git a/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/defaultCustomResources.json b/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/defaultCustomResources.json deleted file mode 100644 index f95feea378..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/defaultCustomResources.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "AWSTemplateFormatVersion": "2010-09-09", - "Description": "An auto-generated nested stack.", - "Metadata": {}, - "Parameters": { - "AppSyncApiId": { - "Type": "String", - "Description": "The id of the AppSync API associated with this project." - }, - "AppSyncApiName": { - "Type": "String", - "Description": "The name of the AppSync API", - "Default": "AppSyncSimpleTransform" - }, - "env": { - "Type": "String", - "Description": "The environment name. e.g. Dev, Test, or Production", - "Default": "NONE" - }, - "S3DeploymentBucket": { - "Type": "String", - "Description": "The S3 bucket containing all deployment assets for the project." - }, - "S3DeploymentRootKey": { - "Type": "String", - "Description": "An S3 key relative to the S3DeploymentBucket that points to the root\nof the deployment directory." - } - }, - "Resources": { - "EmptyResource": { - "Type": "Custom::EmptyResource", - "Condition": "AlwaysFalse" - } - }, - "Conditions": { - "HasEnvironmentParameter": { - "Fn::Not": [ - { - "Fn::Equals": [ - { - "Ref": "env" - }, - "NONE" - ] - } - ] - }, - "AlwaysFalse": { - "Fn::Equals": ["true", "false"] - } - }, - "Outputs": { - "EmptyOutput": { - "Description": "An empty output. You may delete this if you have at least one resource above.", - "Value": "" - } - } -} diff --git a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/docker-compose.yml b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/docker-compose.yml deleted file mode 100644 index ec14c45640..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/docker-compose.yml +++ /dev/null @@ -1,23 +0,0 @@ -version: "3.8" -services: - express: - build: - context: ./express - dockerfile: Dockerfile - ports: - - "8080:8080" - networks: - - public - - private - python: - build: - context: ./python - dockerfile: Dockerfile - networks: - - public - - private - ports: - - "5000:5000" -networks: - public: - private: \ No newline at end of file diff --git a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/Dockerfile b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/Dockerfile deleted file mode 100644 index 3488a8c76c..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM public.ecr.aws/bitnami/node:18-debian-10 - -ENV PORT=8080 -EXPOSE 8080 - -WORKDIR /usr/src/app - -COPY package*.json ./ -RUN npm install -COPY . . - -CMD [ "node", "index.js" ] diff --git a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/DynamoDBActions.js b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/DynamoDBActions.js deleted file mode 100644 index 743d880e54..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/DynamoDBActions.js +++ /dev/null @@ -1,62 +0,0 @@ -const { DynamoDBDocument } = require('@aws-sdk/lib-dynamodb'); -const { DynamoDB } = require('@aws-sdk/client-dynamodb'); - -const docClient = DynamoDBDocument.from(new DynamoDB()); - -const TableName = process.env.STORAGE_POSTS_NAME; - -const addPostToDDB = async ({ id, title, author, description, topic }) => { - - var params = { - Item: { - id: parseInt(id, 10), - title: title, - author: author, - description: description, - topic: topic - }, - TableName: TableName - } - try { - const data = await docClient.put(params) - return params.Item; - } catch (err) { - console.log('Error: ' + err); - return err - } -} - -const scanPostsFromDDB = async () => { - var params = { - TableName: TableName, - } - - try { - const data = await docClient.scan(params); - return data.Items; - } catch (err) { - console.log('Error: ' + err); - return err; - } -} - -const getPostFromDDB = async (id) => { - const key = parseInt(id, 10); - var params = { - TableName: TableName, - Key: { id: key }, - } - try { - const data = await docClient.get(params) - return data.Item; - } catch (err) { - console.log('Error: ' + err); - return err - } -} - -module.exports = { - addPostToDDB, - scanPostsFromDDB, - getPostFromDDB -}; \ No newline at end of file diff --git a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/index.js b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/index.js deleted file mode 100644 index 78228b2775..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/index.js +++ /dev/null @@ -1,124 +0,0 @@ -const express = require("express"); -const bodyParser = require('body-parser'); -const http = require('http'); -const port = process.env.PORT || 3001; - -const { - addPostToDDB, - scanPostsFromDDB, - getPostFromDDB -} = require('./DynamoDBActions'); - -const app = express(); -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({ extended: true })); - -// Enable CORS for all methods -app.use(function (req, res, next) { - res.header("Access-Control-Allow-Origin", "*") - res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept") - next() -}); - -const checkAuthRules = (req, res, next) => { - const jwt = req.header("Authorization") || ""; - - const [, jwtBody] = jwt.split("."); - - const obj = JSON.parse( - jwtBody ? Buffer.from(jwtBody, "base64").toString("utf-8") : "{}" - ); - - //Customer can perform logic on JWT body - //console.log(obj); - next(); - - //Failure example: - // const err = new Error("Access denied"); - // err.statusCode = 403; - // return next(err); -} - -app.use(checkAuthRules); - -app.get("/posts", async (req, res, next) => { - - try { - const result = await scanPostsFromDDB(); - res.contentType("application/json").send(result); - } catch (err) { - next(err); - } -}); - -app.get("/post", async (req, res, next) => { - console.log(req.query.id); - - try { - const result = await getPostFromDDB(req.query.id); - res.contentType("application/json").send(result); - } catch (err) { - next(err); - } -}); - -app.post("/post", async (req, res, next) => { - - try { - const result = await addPostToDDB(req.body); - res.contentType("application/json").send(result); - } catch (err) { - next(err); - } -}); - -app.get("/images", (req, res, next) => { - const options = { - port: 5000, - host: 'localhost', - method: 'GET', - path: '/images' - }; - - http.get(options, data => { - var body = ''; - data.on('data', (chunk) => { - body += chunk; - }); - data.on('end', () => { - console.log(body); - try { - res.contentType("application/json").send(body); - } catch (err) { - console.log(err); - next(err); - } - }).on('error', (error) => { - console.log(error); - }); - }) -}); - -app.use((req, res, next) => { - - try { - const result = `Please try GET on /posts, /post?id=xyz, GET on /images, or a POST to /post with JSON {\"id\":\"123\",\"title\":\"Fargate test\"}`; - res.contentType("application/json").send(result); - } catch (err) { - next(err); - } -}); - -// Error middleware must be defined last -app.use((err, req, res, next) => { - console.error(err.message); - if (!err.statusCode) err.statusCode = 500; // If err has no specified error code, set error code to 'Internal Server Error (500)' - res - .status(err.statusCode) - .json({ message: err.message }) - .end(); -}); - -app.listen(port, () => { - console.log('Example app listening at http://localhost:' + port); -}); \ No newline at end of file diff --git a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/Dockerfile b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/Dockerfile deleted file mode 100644 index ceac55382f..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -# set base image (host OS) -FROM public.ecr.aws/bitnami/python:3.8-prod-debian-10 - -# set the working directory in the container -WORKDIR /code - -# copy the dependencies file to the working directory -COPY requirements.txt . - -# install dependencies -RUN pip install -r requirements.txt - -# copy the content of the local src directory to the working directory -COPY src/ . - -# command to run on container start -CMD [ "python", "./server.py" ] diff --git a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/requirements.txt b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/requirements.txt deleted file mode 100644 index 7883f5be06..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -Flask==2.3.2 \ No newline at end of file diff --git a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/src/server.py b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/src/server.py deleted file mode 100644 index b46754de98..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/src/server.py +++ /dev/null @@ -1,9 +0,0 @@ -from flask import Flask -server = Flask(__name__) - -@server.route('/images') -def hello(): - return 'Processing images...' - -if __name__ == "__main__": - server.run(host='0.0.0.0') \ No newline at end of file diff --git a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/Dockerfile b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/Dockerfile deleted file mode 100644 index 3488a8c76c..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM public.ecr.aws/bitnami/node:18-debian-10 - -ENV PORT=8080 -EXPOSE 8080 - -WORKDIR /usr/src/app - -COPY package*.json ./ -RUN npm install -COPY . . - -CMD [ "node", "index.js" ] diff --git a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/DynamoDBActions.js b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/DynamoDBActions.js deleted file mode 100644 index b6af292101..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/DynamoDBActions.js +++ /dev/null @@ -1,62 +0,0 @@ -const { DynamoDBDocument } = require('@aws-sdk/lib-dynamodb'); -const { DynamoDB } = require('@aws-sdk/client-dynamodb'); - -const docClient = DynamoDBDocument.from(new DynamoDB()); - -const TableName = process.env.STORAGE_POSTS_NAME; - -const addPostToDDB = async ({ id, title, author, description, topic }) => { - - var params = { - Item: { - id: parseInt(id, 10), - title: title, - author: author, - description: description, - topic: topic - }, - TableName: TableName - } - try { - const data = await docClient.put(params) - return params.Item; - } catch (err) { - console.log('Error: ' + err); - return err - } -} - -const scanPostsFromDDB = async () => { - var params = { - TableName: TableName, - } - - try { - const data = await docClient.scan(params); - return data.Items; - } catch (err) { - console.log('Error: ' + err); - return err; - } -} - -const getPostFromDDB = async (id) => { - const key = parseInt(id, 10); - var params = { - TableName: TableName, - Key: { id: key }, - } - try { - const data = await docClient.get(params) - return data.Item; - } catch (err) { - console.log('Error: ' + err); - return err - } -} - -module.exports = { - addPostToDDB, - scanPostsFromDDB, - getPostFromDDB -}; \ No newline at end of file diff --git a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/index.js b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/index.js deleted file mode 100644 index 0d40649139..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/index.js +++ /dev/null @@ -1,96 +0,0 @@ -const express = require("express"); -const bodyParser = require('body-parser'); -const port = process.env.PORT || 3001; - -const { - addPostToDDB, - scanPostsFromDDB, - getPostFromDDB -} = require('./DynamoDBActions'); - -const app = express(); -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({ extended: true })); - -// Enable CORS for all methods -app.use(function (req, res, next) { - res.header("Access-Control-Allow-Origin", "*") - res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept") - next() -}); - -const checkAuthRules = (req, res, next) => { - const jwt = req.header("Authorization") || ""; - - const [, jwtBody] = jwt.split("."); - - const obj = JSON.parse( - jwtBody ? Buffer.from(jwtBody, "base64").toString("utf-8") : "{}" - ); - - //Customer can perform logic on JWT body - //console.log(obj); - next(); - - //Failure example: - // const err = new Error("Access denied"); - // err.statusCode = 403; - // return next(err); -} - -app.use(checkAuthRules); - -app.get("/posts", async (req, res, next) => { - - try { - const result = await scanPostsFromDDB(); - res.contentType("application/json").send(result); - } catch (err) { - next(err); - } -}); - -app.get("/post", async (req, res, next) => { - console.log(req.query.id); - - try { - const result = await getPostFromDDB(req.query.id); - res.contentType("application/json").send(result); - } catch (err) { - next(err); - } -}); - -app.post("/post", async (req, res, next) => { - - try { - const result = await addPostToDDB(req.body); - res.contentType("application/json").send(result); - } catch (err) { - next(err); - } -}); - -app.use((req, res, next) => { - - try { - const result = `Please try GET on /posts, /post?id=xyz, or a POST to /post with JSON {\"id\":\"123\",\"title\":\"Fargate test\"}`; - res.contentType("application/json").send(result); - } catch (err) { - next(err); - } -}); - -// Error middleware must be defined last -app.use((err, req, res, next) => { - console.error(err.message); - if (!err.statusCode) err.statusCode = 500; // If err has no specified error code, set error code to 'Internal Server Error (500)' - res - .status(err.statusCode) - .json({ message: err.message }) - .end(); -}); - -app.listen(port, () => { - console.log('Example app listening at http://localhost:' + port); -}); \ No newline at end of file diff --git a/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/Dockerfile b/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/Dockerfile deleted file mode 100644 index cd9add03c5..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM public.ecr.aws/bitnami/node:18-debian-10 - -WORKDIR /usr/src/app -COPY package*.json ./ -RUN npm install -COPY . . - -EXPOSE 3000 - -CMD ["node", "index.js"] diff --git a/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/index.js b/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/index.js deleted file mode 100644 index 685aa6d669..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/index.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; -const PORT = 3000; -var express = require('express'); -var { graphqlHTTP } = require('express-graphql'); -var { buildSchema } = require('graphql'); -var Query = require('./schema.js'); -var root = require('./resolvers.js'); -var app = express(); -// Enable CORS for all methods -app.use(function (req, res, next) { - res.header("Access-Control-Allow-Origin", "*") - res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept") - next() -}); -app.use('/graphql', graphqlHTTP({ - schema: buildSchema(Query), - rootValue: root, - graphiql: true -})); -app.get('/', (req, res, next) => { - try { - res.redirect('/graphql'); - } catch (err){ - next(err); - } - }); -app.listen(PORT, () => console.log('Listening on localhost:' + PORT + '/graphql')); \ No newline at end of file diff --git a/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/resolvers.js b/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/resolvers.js deleted file mode 100644 index c27e40afd7..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/resolvers.js +++ /dev/null @@ -1,60 +0,0 @@ -const { DynamoDBDocument } = require('@aws-sdk/lib-dynamodb'); -const { DynamoDB } = require('@aws-sdk/client-dynamodb'); - -const docClient = DynamoDBDocument.from(new DynamoDB()); - -const TableName = process.env.STORAGE_POSTS_NAME; - -const addPostToDDB = async ({ id, title, author, description, topic }) => { - var params = { - Item: { - id: id, - title: title, - author: author, - description: description, - topic: topic - }, - TableName: TableName - } - try { - const data = await docClient.put(params) - return params.Item; - } catch (err) { - return err - } -} - -const scanPostsFromDDB = async () => { - var params = { - TableName: TableName, - } - - try { - const data = await docClient.scan(params); - return data.Items; - } catch (err) { - console.log(err); - return err; - } -} - -const getPostFromDDB = async (id) => { - var params = { - TableName: TableName, - Key: id, - } - try { - const data = await docClient.get(params) - return data.Item; - } catch (err) { - return err - } -} - -var root = { - getPost: getPostFromDDB, - posts: scanPostsFromDDB, - addPost: addPostToDDB -}; - -module.exports = root; diff --git a/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/schema.js b/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/schema.js deleted file mode 100644 index 0c9b2ef376..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/schema.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = ` -type Query { - getPost(id: Int!): Post - posts: [Post] -}, -type Mutation { - addPost(id: Int!, title: String, author: String, description: String, topic: String): Post -}, -type Post { - id: Int - title: String - author: String - description: String - topic: String -} -` \ No newline at end of file diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/blank-schema.graphql b/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/blank-schema.graphql deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/many-relationship-schema-v2.graphql b/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/many-relationship-schema-v2.graphql deleted file mode 100644 index 2619b18729..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/many-relationship-schema-v2.graphql +++ /dev/null @@ -1,18 +0,0 @@ -type Blog @model { - id: ID! - name: String! - posts: [Post] @hasMany -} - -type Post @model { - id: ID! - title: String! - blog: Blog @belongsTo - comments: [Comment] @hasMany -} - -type Comment @model { - id: ID! - post: Post @belongsTo - content: String! -} diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/many-relationship-schema.graphql b/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/many-relationship-schema.graphql deleted file mode 100644 index cf765373f8..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/many-relationship-schema.graphql +++ /dev/null @@ -1,20 +0,0 @@ -type Blog @model { - id: ID! - name: String! - posts: [Post] @connection(keyName: "byBlog", fields: ["id"]) -} - -type Post @model @key(name: "byBlog", fields: ["blogID"]) { - id: ID! - title: String! - blogID: ID! - blog: Blog @connection(fields: ["blogID"]) - comments: [Comment] @connection(keyName: "byPost", fields: ["id"]) -} - -type Comment @model @key(name: "byPost", fields: ["postID", "content"]) { - id: ID! - postID: ID! - post: Post @connection(fields: ["postID"]) - content: String! -} diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-auth-schema-v2.graphql b/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-auth-schema-v2.graphql deleted file mode 100644 index d1706a3bab..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-auth-schema-v2.graphql +++ /dev/null @@ -1,18 +0,0 @@ -type Task - @model - @auth( - rules: [ - { allow: groups, groups: ["Managers"], operations: [create, update, read, delete] } - { allow: groups, groups: ["Employees"], operations: [read] } - ] - ) { - id: ID! - title: String! - description: String - status: String -} - -type PrivateNote @model @auth(rules: [{ allow: owner }]) { - id: ID! - content: String! -} diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-auth-schema.graphql b/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-auth-schema.graphql deleted file mode 100644 index 3438d56938..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-auth-schema.graphql +++ /dev/null @@ -1,17 +0,0 @@ -type Task - @model - @auth( - rules: [ - { allow: groups, groups: ["Managers"], queries: null, mutations: [create, update, delete] } - { allow: groups, groups: ["Employees"], queries: [get, list], mutations: null } - ] - ) { - id: ID! - title: String! - description: String - status: String -} -type PrivateNote @model @auth(rules: [{ allow: owner }]) { - id: ID! - content: String! -} diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-schema-v2.graphql b/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-schema-v2.graphql deleted file mode 100644 index 74b097ceae..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-schema-v2.graphql +++ /dev/null @@ -1,5 +0,0 @@ -type Todo @model { - id: ID! - name: String! - description: String -} diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-schema.graphql b/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-schema.graphql deleted file mode 100644 index 74b097ceae..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-schema.graphql +++ /dev/null @@ -1,5 +0,0 @@ -type Todo @model { - id: ID! - name: String! - description: String -} diff --git a/packages/amplify-category-api/resources/awscloudformation/lambdas/pipeline-on-event.js b/packages/amplify-category-api/resources/awscloudformation/lambdas/pipeline-on-event.js deleted file mode 100644 index bbec181a7e..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/lambdas/pipeline-on-event.js +++ /dev/null @@ -1,15 +0,0 @@ -exports.handler = async function({ RequestType, PhysicalResourceId, ResourceProperties }) { - switch (RequestType) { - case 'Delete': - case 'Update': - return { PhysicalResourceId }; - } - - const { pipelineName } = ResourceProperties; - - const result = { - PhysicalResourceId: `pipelineawaiter-${pipelineName}`, - }; - - return result; -}; diff --git a/packages/amplify-category-api/resources/awscloudformation/lambdas/pipeline.js b/packages/amplify-category-api/resources/awscloudformation/lambdas/pipeline.js deleted file mode 100644 index ea51374811..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/lambdas/pipeline.js +++ /dev/null @@ -1,109 +0,0 @@ -const { CloudFormation } = require('@aws-sdk/client-cloudformation'); -const { CodePipeline } = require('@aws-sdk/client-codepipeline'); - -const stageName = 'Source'; -const actionName = 'Source'; - -const codePipeline = new CodePipeline(); -const cloudFormation = new CloudFormation(); - -exports.handler = async function({ RequestType, ResourceProperties, StackId }) { - const { pipelineName, artifactBucketName, artifactKey, deploymentMechanism } = ResourceProperties; - - console.log('Properties', ResourceProperties); - - switch (RequestType) { - case 'Delete': - return { IsComplete: true }; - case 'Update': - const [, StackName] = StackId.split('/'); - const { Stacks } = await cloudFormation.describeStacks({ StackName }); - const [{ StackStatus }] = Stacks; - - if (StackStatus.includes('ROLLBACK')) { - return { IsComplete: true }; - } - } - - let stages; - - try { - const { pipeline } = await codePipeline.getPipeline({ name: pipelineName }); - - ({ stages } = pipeline); - } catch (error) { - const { code } = error; - - switch (code) { - case 'PipelineNotFoundException': - console.warn(error); - - return { - IsComplete: false, - }; - default: - throw error; - } - } - - const stage = stages.find(({ name }) => name === stageName); - - if (stage === undefined) { - throw new Error(`There is no stage named "${stageName}" in the "${pipelineName}" pipeline`); - } - - const action = stage.actions.find(({ name }) => name === actionName); - - if (action === undefined) { - throw new Error(`There is no action named "${actionName}" in the "${stageName}" stage of the "${pipelineName}" pipeline`); - } - - const { - configuration, - configuration: { S3Bucket, S3ObjectKey }, - } = action; - - if (deploymentMechanism === 'FULLY_MANAGED') { - if (S3Bucket !== artifactBucketName || S3ObjectKey !== artifactKey) { - console.warn( - `Bucket "${artifactBucketName}" and key "${artifactKey}" dont match the "${actionName}" action configuration ${JSON.stringify( - configuration, - )}`, - ); - - return { - IsComplete: false, - }; - } - } - - let execution; - - try { - const { pipelineExecutionSummaries } = await codePipeline.listPipelineExecutions({ pipelineName }); - - [execution] = pipelineExecutionSummaries; - } catch (error) { - console.warn(error); - - return { - IsComplete: false, - }; - } - - console.log(execution); - - const { status } = execution || {}; - - let IsComplete = false; - - switch (status) { - case 'Failed': - case 'Stopped': - throw new Error("The execution didn't succeed"); - case 'Succeeded': - IsComplete = true; - } - - return { IsComplete }; -}; diff --git a/packages/amplify-category-api/resources/awscloudformation/lambdas/predeploy.js b/packages/amplify-category-api/resources/awscloudformation/lambdas/predeploy.js deleted file mode 100644 index 6df0068a40..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/lambdas/predeploy.js +++ /dev/null @@ -1,19 +0,0 @@ -const { CodePipeline } = require('@aws-sdk/client-codepipeline'); -const { ECS } = require('@aws-sdk/client-ecs'); - -const codepipeline = new CodePipeline(); -const ecs = new ECS(); - -const { DESIRED_COUNT: desiredCountStr, CLUSTER_NAME: cluster, SERVICE_NAME: service } = process.env; - -const desiredCount = parseInt(desiredCountStr, 10); - -exports.handler = async function({ 'CodePipeline.job': { id: jobId } }) { - await ecs.updateService({ - service, - cluster, - desiredCount, - }); - - return await codepipeline.putJobSuccessResult({ jobId }); -}; diff --git a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/override.ts.sample b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/override.ts.sample deleted file mode 100644 index 97291c6d6b..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/override.ts.sample +++ /dev/null @@ -1,6 +0,0 @@ -// This file is used to override the REST API resources configuration -import { AmplifyApiRestResourceStackTemplate, AmplifyProjectInfo } from '@aws-amplify/cli-extensibility-helper'; - -export function override(resources: AmplifyApiRestResourceStackTemplate, amplifyProjectInfo: AmplifyProjectInfo) { - -} diff --git a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/package.json b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/package.json deleted file mode 100644 index ef718d30cc..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "overrides", - "version": "1.0.0", - "description": "", - "scripts": { - "build": "tsc", - "watch": "tsc -w" - }, - "dependencies": { - "@aws-amplify/cli-extensibility-helper": "^3.0.33" - }, - "devDependencies": { - "typescript": "^4.2.4" - } -} diff --git a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/tsconfig.json b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/tsconfig.json deleted file mode 100644 index c6f1a33b4d..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "target": "es6", - "module": "commonjs", - "strict": false, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "outDir": "build" - } -} diff --git a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/tsconfig.resource.json b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/tsconfig.resource.json deleted file mode 100644 index 6504da8028..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/tsconfig.resource.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "compilerOptions": { - "target": "es6", - "module": "commonjs", - "strict": false, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "outDir": "./", - "rootDir": "../" - }, - "include": ["../**/*"] -} diff --git a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/override.ts.sample b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/override.ts.sample deleted file mode 100644 index 34fdfda2a1..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/override.ts.sample +++ /dev/null @@ -1,5 +0,0 @@ -import { AmplifyApiGraphQlResourceStackTemplate, AmplifyProjectInfo } from '@aws-amplify/cli-extensibility-helper'; - -export function override(resources: AmplifyApiGraphQlResourceStackTemplate, amplifyProjectInfo: AmplifyProjectInfo) { - -} diff --git a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/package.json b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/package.json deleted file mode 100644 index ef718d30cc..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "overrides", - "version": "1.0.0", - "description": "", - "scripts": { - "build": "tsc", - "watch": "tsc -w" - }, - "dependencies": { - "@aws-amplify/cli-extensibility-helper": "^3.0.33" - }, - "devDependencies": { - "typescript": "^4.2.4" - } -} diff --git a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/tsconfig.json b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/tsconfig.json deleted file mode 100644 index 9a070be831..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "target": "es6", - "module": "commonjs", - "strict": false, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "outDir": "build" - } -} \ No newline at end of file diff --git a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/tsconfig.resource.json b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/tsconfig.resource.json deleted file mode 100644 index 6504da8028..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/tsconfig.resource.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "compilerOptions": { - "target": "es6", - "module": "commonjs", - "strict": false, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "outDir": "./", - "rootDir": "../" - }, - "include": ["../**/*"] -} diff --git a/packages/amplify-category-api/resources/awscloudformation/resolver-readme/RESOLVER_README.md b/packages/amplify-category-api/resources/awscloudformation/resolver-readme/RESOLVER_README.md deleted file mode 100644 index 89e564c5b3..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/resolver-readme/RESOLVER_README.md +++ /dev/null @@ -1,2 +0,0 @@ -Any resolvers that you add in this directory will override the ones automatically generated by Amplify CLI and will be directly copied to the cloud. -For more information, visit [https://docs.amplify.aws/cli/graphql-transformer/resolvers](https://docs.amplify.aws/cli/graphql-transformer/resolvers) \ No newline at end of file diff --git a/packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-index.js.ejs b/packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-index.js.ejs deleted file mode 100644 index 7034c711ce..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-index.js.ejs +++ /dev/null @@ -1,37 +0,0 @@ -// This is sample code. Please update this to suite your schema - -exports.handler = async (event, context, callback) => { - console.log('Received event {}', JSON.stringify(event, 3)); - let action, item; - switch (event.resolver.field) { - case 'updatePost': - if (event.existingItem.postId === '1') { - action = 'RESOLVE'; - item = event.newItem; - } else { - action = 'REJECT'; - } - break; - case 'deletePost': - if (event.existingItem.postId === '1') { - action = 'REMOVE'; - } else { - action = 'REJECT'; - } - break; - case 'addPost': - if (event.existingItem.postId === '1') { - action = 'RESOLVE'; - item = event.newItem; - } else { - action = 'REJECT'; - } - break; - default: - throw new Error('Unknown Resolver'); - } - return { - action, - item, - }; -}; diff --git a/packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-package.json.ejs b/packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-package.json.ejs deleted file mode 100644 index 084c06bc3d..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-package.json.ejs +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "<%= props.functionName %>", - "version": "1.0.0", - "description": "Lambda function generated by Amplify for conflict handling", - "main": "index.js" -} diff --git a/packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-template.json.ejs b/packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-template.json.ejs deleted file mode 100644 index a98ecae384..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-template.json.ejs +++ /dev/null @@ -1,197 +0,0 @@ -{ - "AWSTemplateFormatVersion": "2010-09-09", - "Description": "Lambda resource stack creation using Amplify CLI", - "Parameters": { - "env": { - "Type": "String" - }<%if (props.dependsOn && props.dependsOn.length > 0) { %>,<% } %> - <% if (props.dependsOn) { %> - <% for(var i=0; i < props.dependsOn.length; i++) { %> - <% for(var j=0; j < props.dependsOn[i].attributes.length; j++) { %> - "<%= props.dependsOn[i].category %><%= props.dependsOn[i].resourceName %><%= props.dependsOn[i].attributes[j] %>": { - "Type": "String", - "Default": "<%= props.dependsOn[i].category %><%= props.dependsOn[i].resourceName %><%= props.dependsOn[i].attributes[j] %>" - }<%if (i !== props.dependsOn.length - 1 || j !== props.dependsOn[i].attributes.length - 1) { %>,<% } %> - <% } %> - <% } %> - <% } %> - }, - "Conditions": { - "ShouldNotCreateEnvResources": { - "Fn::Equals": [ - { - "Ref": "env" - }, - "NONE" - ] - } - }, - "Resources": { - "LambdaFunction": { - "Type": "AWS::Lambda::Function", - "Metadata": { - "aws:asset:path": "./src", - "aws:asset:property": "Code" - }, - "Properties": { - "Handler": "index.handler", - "FunctionName": { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "<%= props.functionName %>", - { - - "Fn::Join": [ - "", - [ - "<%= props.functionName %>", - "-", - { - "Ref": "env" - } - ] - ] - } - ] - }, - "Environment": { - "Variables" : { - "ENV": { - "Ref": "env" - }, - "REGION": { - "Ref": "AWS::Region" - } - <% if (props.resourceProperties && props.resourceProperties.length > 0) { %>,<%- props.resourceProperties%> <% } %> - } - }, - "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, - "Runtime": "nodejs18.x", - "Timeout": 25 - } - }, - "LambdaExecutionRole": { - "Type": "AWS::IAM::Role", - "Properties": { - "RoleName": { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "<%=props.roleName %>", - { - - "Fn::Join": [ - "", - [ - "<%=props.roleName %>", - "-", - { - "Ref": "env" - } - ] - ] - } - ] - }, - "AssumeRolePolicyDocument": { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Principal": { - "Service": [ - "lambda.amazonaws.com" - ] - }, - "Action": [ - "sts:AssumeRole" - ] - } - ] - } - } - } - ,"lambdaexecutionpolicy": { - "DependsOn": ["LambdaExecutionRole"], - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyName": "lambda-execution-policy", - "Roles": [{ "Ref": "LambdaExecutionRole" }], - "PolicyDocument": { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Action":["logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents"], - "Resource": { "Fn::Sub" : [ "arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:*", { "region": {"Ref": "AWS::Region"}, "account": {"Ref": "AWS::AccountId"}, "lambda": {"Ref": "LambdaFunction"}} ]} - }<% if (props.database && props.database.resourceName) { %>, - { - "Effect": "Allow", - "Action": ["dynamodb:GetItem","dynamodb:Query","dynamodb:Scan","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem"], - "Resource": [ - <% if (props.database && props.database.Arn) { %> - "<%= props.database.Arn %>", - { - "Fn::Join": [ - "/", - [ - "<%= props.database.Arn %>", - "index/*" - ] - ] - } - <% } else { %> - { "Ref": "storage<%= props.database.resourceName %>Arn" }, - { - "Fn::Join": [ - "/", - [ - { "Ref": "storage<%= props.database.resourceName %>Arn" }, - "index/*" - ] - ] - } - <% } %> - ] - } - <% } %> - ] - } - } - }<% if (props.categoryPolicies && props.categoryPolicies.length > 0 ) { %> - ,"AmplifyResourcesPolicy": { - "DependsOn": ["LambdaExecutionRole"], - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyName": "amplify-lambda-execution-policy", - "Roles": [{ "Ref": "LambdaExecutionRole" }], - "PolicyDocument": { - "Version": "2012-10-17", - "Statement": <%- JSON.stringify(props.categoryPolicies) %> - } - } - } - <% } %> - }, - "Outputs": { - "Name": { - "Value": { - "Ref": "LambdaFunction" - } - }, - "Arn": { - "Value": {"Fn::GetAtt": ["LambdaFunction", "Arn"]} - }, - "Region": { - "Value": { - "Ref": "AWS::Region" - } - }, - "LambdaExecutionRole": { - "Value": { - "Ref": "LambdaExecutionRole" - } - } - } -} diff --git a/packages/amplify-category-api/resources/schemas/aPIGateway/APIGatewayCLIInputs.schema.json b/packages/amplify-category-api/resources/schemas/aPIGateway/APIGatewayCLIInputs.schema.json deleted file mode 100644 index 8a8269ba85..0000000000 --- a/packages/amplify-category-api/resources/schemas/aPIGateway/APIGatewayCLIInputs.schema.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "description": "Defines the json object expected by the amplify api category", - "type": "object", - "properties": { - "version": { - "description": "The schema version.", - "type": "number", - "enum": [ - 1 - ] - }, - "paths": { - "description": "map of paths in the REST API.", - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "lambdaFunction": { - "type": "string" - }, - "permissions": { - "type": "object", - "properties": { - "setting": { - "$ref": "#/definitions/PermissionSetting" - }, - "auth": { - "type": "array", - "items": { - "enum": [ - "create", - "delete", - "read", - "update" - ], - "type": "string" - } - }, - "guest": { - "type": "array", - "items": { - "enum": [ - "create", - "delete", - "read", - "update" - ], - "type": "string" - } - }, - "groups": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "enum": [ - "create", - "delete", - "read", - "update" - ], - "type": "string" - } - } - } - }, - "required": [ - "setting" - ] - } - }, - "required": [ - "lambdaFunction", - "permissions" - ] - } - } - }, - "required": [ - "paths", - "version" - ], - "definitions": { - "PermissionSetting": { - "enum": [ - "open", - "private", - "protected" - ], - "type": "string" - } - }, - "$schema": "http://json-schema.org/draft-07/schema#" -} \ No newline at end of file diff --git a/packages/amplify-category-api/resources/schemas/appsync/AppSyncCLIInputs.schema.json b/packages/amplify-category-api/resources/schemas/appsync/AppSyncCLIInputs.schema.json deleted file mode 100644 index 6dd7fcccbe..0000000000 --- a/packages/amplify-category-api/resources/schemas/appsync/AppSyncCLIInputs.schema.json +++ /dev/null @@ -1,343 +0,0 @@ -{ - "description": "Defines the json object expected by `amplify api category", - "type": "object", - "properties": { - "version": { - "description": "The schema version.", - "type": "number", - "enum": [ - 1 - ] - }, - "serviceConfiguration": { - "$ref": "#/definitions/AppSyncServiceConfig", - "description": "The service configuration that will be interpreted by Amplify." - } - }, - "required": [ - "serviceConfiguration", - "version" - ], - "definitions": { - "AppSyncServiceConfig": { - "description": "Configuration exposed by AppSync. Currently this is the only API type supported by Amplify headless mode.", - "type": "object", - "properties": { - "serviceName": { - "description": "The service name of the resource provider.", - "type": "string", - "enum": [ - "AppSync" - ] - }, - "apiName": { - "description": "The name of the API that will be created.", - "type": "string" - }, - "defaultAuthType": { - "description": "The auth type that will be used by default.", - "anyOf": [ - { - "$ref": "#/definitions/AppSyncAPIKeyAuthType" - }, - { - "$ref": "#/definitions/AppSyncAWSIAMAuthType" - }, - { - "$ref": "#/definitions/AppSyncCognitoUserPoolsAuthType" - }, - { - "$ref": "#/definitions/AppSyncOpenIDConnectAuthType" - }, - { - "$ref": "#/definitions/AppSyncLambdaAuthType" - } - ] - }, - "additionalAuthTypes": { - "description": "Additional methods of authenticating API requests.", - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/definitions/AppSyncAPIKeyAuthType" - }, - { - "$ref": "#/definitions/AppSyncAWSIAMAuthType" - }, - { - "$ref": "#/definitions/AppSyncCognitoUserPoolsAuthType" - }, - { - "$ref": "#/definitions/AppSyncOpenIDConnectAuthType" - }, - { - "$ref": "#/definitions/AppSyncLambdaAuthType" - } - ] - } - }, - "conflictResolution": { - "$ref": "#/definitions/ConflictResolution", - "description": "The strategy for resolving API write conflicts." - } - }, - "required": [ - "apiName", - "defaultAuthType", - "serviceName" - ] - }, - "AppSyncAPIKeyAuthType": { - "description": "Specifies that the AppSync API should be secured using an API key.", - "type": "object", - "properties": { - "mode": { - "type": "string", - "enum": [ - "API_KEY" - ] - }, - "expirationTime": { - "type": "number" - }, - "apiKeyExpirationDate": { - "type": "string", - "format": "date-time" - }, - "keyDescription": { - "type": "string" - } - }, - "required": [ - "mode" - ] - }, - "AppSyncAWSIAMAuthType": { - "description": "Specifies that the AppSync API should be secured using AWS IAM.", - "type": "object", - "properties": { - "mode": { - "type": "string", - "enum": [ - "AWS_IAM" - ] - } - }, - "required": [ - "mode" - ] - }, - "AppSyncCognitoUserPoolsAuthType": { - "description": "Specifies that the AppSync API should be secured using Cognito.", - "type": "object", - "properties": { - "mode": { - "type": "string", - "enum": [ - "AMAZON_COGNITO_USER_POOLS" - ] - }, - "cognitoUserPoolId": { - "description": "The user pool that will be used to authenticate requests.", - "type": "string" - } - }, - "required": [ - "mode" - ] - }, - "AppSyncOpenIDConnectAuthType": { - "description": "Specifies that the AppSync API should be secured using OpenID.", - "type": "object", - "properties": { - "mode": { - "type": "string", - "enum": [ - "OPENID_CONNECT" - ] - }, - "openIDProviderName": { - "type": "string" - }, - "openIDIssuerURL": { - "type": "string" - }, - "openIDClientID": { - "type": "string" - }, - "openIDAuthTTL": { - "type": "string" - }, - "openIDIatTTL": { - "type": "string" - } - }, - "required": [ - "mode", - "openIDClientID", - "openIDIssuerURL", - "openIDProviderName" - ] - }, - "AppSyncLambdaAuthType": { - "description": "Specifies that the AppSync API should be secured using Lambda.", - "type": "object", - "properties": { - "mode": { - "type": "string", - "enum": [ - "AWS_LAMBDA" - ] - }, - "lambdaFunction": { - "type": "string" - }, - "ttlSeconds": { - "type": "string" - } - }, - "required": [ - "lambdaFunction", - "mode" - ] - }, - "ConflictResolution": { - "description": "Defines a strategy for resolving API write conflicts.", - "type": "object", - "properties": { - "defaultResolutionStrategy": { - "description": "The strategy that will be used for all models by default.", - "anyOf": [ - { - "$ref": "#/definitions/PredefinedResolutionStrategy" - }, - { - "$ref": "#/definitions/LambdaResolutionStrategy" - } - ] - }, - "perModelResolutionStrategy": { - "description": "Strategies that will be used for individual models.", - "type": "array", - "items": { - "$ref": "#/definitions/PerModelResolutionstrategy" - } - } - } - }, - "PredefinedResolutionStrategy": { - "description": "Resolution strategies provided by AppSync. See https://docs.aws.amazon.com/appsync/latest/devguide/conflict-detection-and-sync.html for details.", - "type": "object", - "properties": { - "type": { - "enum": [ - "AUTOMERGE", - "NONE", - "OPTIMISTIC_CONCURRENCY" - ], - "type": "string" - } - }, - "required": [ - "type" - ] - }, - "LambdaResolutionStrategy": { - "description": "Resolution strategy using a custom lambda function.", - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "LAMBDA" - ] - }, - "resolver": { - "description": "The lambda function used to resolve conflicts.", - "anyOf": [ - { - "$ref": "#/definitions/NewLambdaConflictResolver" - }, - { - "$ref": "#/definitions/ExistingLambdaConflictResolver" - } - ] - } - }, - "required": [ - "resolver", - "type" - ] - }, - "NewLambdaConflictResolver": { - "description": "Defines a new lambda conflict resolver. Using this resolver type will create a new lambda function with boilerplate resolver logic.", - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "NEW" - ] - } - }, - "required": [ - "type" - ] - }, - "ExistingLambdaConflictResolver": { - "description": "Defines an lambda conflict resolver that uses an existing lambda function.", - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "EXISTING" - ] - }, - "name": { - "description": "The name of the lambda function (this must be a lambda function that exists in the Amplify project).", - "type": "string" - }, - "region": { - "description": "The lambda function region.", - "type": "string" - }, - "arn": { - "description": "A lambda function ARN. This could be an ARN outside of the Amplify project but in that case extra care must be taken to ensure the AppSync API has access to the Lambda.", - "type": "string" - } - }, - "required": [ - "name", - "type" - ] - }, - "PerModelResolutionstrategy": { - "description": "Defines a resolution strategy for a single model.", - "type": "object", - "properties": { - "resolutionStrategy": { - "description": "The resolution strategy for the model.", - "anyOf": [ - { - "$ref": "#/definitions/PredefinedResolutionStrategy" - }, - { - "$ref": "#/definitions/LambdaResolutionStrategy" - } - ] - }, - "entityName": { - "description": "The model name.", - "type": "string" - } - }, - "required": [ - "entityName", - "resolutionStrategy" - ] - } - }, - "$schema": "http://json-schema.org/draft-07/schema#" -} \ No newline at end of file diff --git a/packages/amplify-category-api/scripts/generateApiSchemas.ts b/packages/amplify-category-api/scripts/generateApiSchemas.ts deleted file mode 100644 index 5b7b2473c1..0000000000 --- a/packages/amplify-category-api/scripts/generateApiSchemas.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { AmplifySupportedService, CLIInputSchemaGenerator, TypeDef } from '@aws-amplify/amplify-cli-core'; - -const AppsyncApiTypeDef: TypeDef = { - typeName: 'AppSyncCLIInputs', - service: AmplifySupportedService.APPSYNC, -}; - -const ApigwTypeDef: TypeDef = { - typeName: 'APIGatewayCLIInputs', - service: AmplifySupportedService.APIGW, -}; - -// Defines the type names and the paths to the TS files that define them -const apiCategoryTypeDefs: TypeDef[] = [AppsyncApiTypeDef, ApigwTypeDef]; - -const schemaGenerator = new CLIInputSchemaGenerator(apiCategoryTypeDefs); -schemaGenerator.generateJSONSchemas(); // convert CLI input data into json schemas. diff --git a/packages/amplify-category-api/src/__tests__/category-utils/is-datastore-enabled.test.ts b/packages/amplify-category-api/src/__tests__/category-utils/is-datastore-enabled.test.ts deleted file mode 100644 index cc9d7fc234..0000000000 --- a/packages/amplify-category-api/src/__tests__/category-utils/is-datastore-enabled.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { isDataStoreEnabled as isDataStoreEnabledAtDirectory } from 'graphql-transformer-core'; -import { mocked } from 'ts-jest'; -import { isDataStoreEnabled } from '../../category-utils/is-datastore-enabled'; -import { contextUtil } from '../../category-utils/context-util'; - -jest.mock('graphql-transformer-core'); -jest.mock('../../category-utils/context-util'); - -const isDataStoreEnabledAtDirectoryMock = mocked(isDataStoreEnabledAtDirectory); -const contextUtilMock = mocked(contextUtil); - -const MOCK_RESOURCE_DIR = 'resource/dir'; -const MOCK_CONTEXT = {} as unknown as $TSContext; - -describe('isDataStoreEnabled', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('invokes the underlying utility methods, and returns true if utility returns true', async () => { - contextUtilMock.getResourceDir.mockResolvedValue(MOCK_RESOURCE_DIR); - isDataStoreEnabledAtDirectoryMock.mockResolvedValue(true); - - await expect(isDataStoreEnabled(MOCK_CONTEXT)).resolves.toEqual(true); - - expect(contextUtilMock.getResourceDir).toHaveBeenCalledWith(MOCK_CONTEXT, { forceCompile: true }); - expect(isDataStoreEnabledAtDirectoryMock).toHaveBeenCalledWith(MOCK_RESOURCE_DIR); - }); - - it('invokes the underlying utility methods, and returns false if utility returns false', async () => { - contextUtilMock.getResourceDir.mockResolvedValue(MOCK_RESOURCE_DIR); - isDataStoreEnabledAtDirectoryMock.mockResolvedValue(false); - - await expect(isDataStoreEnabled(MOCK_CONTEXT)).resolves.toEqual(false); - - expect(contextUtilMock.getResourceDir).toHaveBeenCalledWith(MOCK_CONTEXT, { forceCompile: true }); - expect(isDataStoreEnabledAtDirectoryMock).toHaveBeenCalledWith(MOCK_RESOURCE_DIR); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/category-utils/show-auth-acm.test.ts b/packages/amplify-category-api/src/__tests__/category-utils/show-auth-acm.test.ts deleted file mode 100644 index 8b31936811..0000000000 --- a/packages/amplify-category-api/src/__tests__/category-utils/show-auth-acm.test.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { DEFAULT_GROUP_CLAIM } from '@aws-amplify/graphql-auth-transformer'; -import { printACM } from '../../category-utils/show-auth-acm'; - -jest.mock('@aws-amplify/amplify-cli-core', () => ({ - ...(jest.requireActual('@aws-amplify/amplify-cli-core') as {}), - FeatureFlags: { - getBoolean: () => true, - }, -})); - -describe('show-auth-acm helper:', () => { - let functionArguments: { sdl: string; node: 'Blog' }; - - it('...the show-auth-acm helper should be exported', () => { - expect(printACM).toBeDefined(); - }); - - it('...should return a function', () => { - expect(typeof printACM).toEqual('function'); - }); - - describe('case: where identical auth rules exist with default group claim', () => { - beforeEach(() => { - functionArguments = { - sdl: `type Blog - @model - @auth(rules: [ - { allow: groups, groupsField: "tenantId" } - { allow: groups, groupsField: "tenantId" } - ]) - { - id: ID! - name: String! - tenantId: String! - }`, - node: 'Blog', - }; - }); - - it('...should throw a specific exception', () => { - expect(() => printACM(functionArguments.sdl, functionArguments.node)).toThrow( - `@auth userPools:dynamicGroup:${DEFAULT_GROUP_CLAIM}:tenantId already exists for Blog`, - ); - }); - }); - - describe('case: where identical auth rules exist with custom group claim', () => { - beforeEach(() => { - functionArguments = { - sdl: `type Blog - @model - @auth(rules: [ - { allow: groups, groupsField: "tenantId", groupClaim: "custom:adminRole" } - { allow: groups, groupsField: "tenantId", groupClaim: "custom:adminRole" } - { allow: groups, groupsField: "tenantId", groupClaim: "custom:editorRole", operations: [read, update] } - ]) - { - id: ID! - name: String! - tenantId: String! - }`, - node: 'Blog', - }; - }); - - it('...should throw a specific exception', () => { - expect(() => printACM(functionArguments.sdl, functionArguments.node)).toThrow( - `@auth userPools:dynamicGroup:custom:adminRole:tenantId already exists for Blog`, - ); - }); - }); - - describe('case: auth rules with a custom groupField are distinguished by a custom group claim', () => { - beforeEach(() => { - functionArguments = { - sdl: `type Blog - @model - @auth(rules: [ - { allow: groups, groupsField: "tenantId", groupClaim: "custom:adminRole" } - { allow: groups, groupsField: "tenantId", groupClaim: "custom:editorRole", operations: [read, update] } - ]) - { - id: ID! - name: String! - tenantId: String! - }`, - node: 'Blog', - }; - }); - - it('...should complete without exception', () => { - const callShowAcm = jest.fn(() => printACM(functionArguments.sdl, functionArguments.node)); - - callShowAcm(); - - expect(callShowAcm).toHaveReturned(); - }); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.ts b/packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.ts deleted file mode 100644 index c8f84735e1..0000000000 --- a/packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import * as path from 'path'; -import { readSchema } from '../../../commands/api/add-graphql-datasource'; - -describe('read schema', () => { - it('Valid schema present in folder', async () => { - const graphqlSchemaPath = path.join(__dirname, 'mock-data', 'schema.graphql'); - expect(readSchema(graphqlSchemaPath)).toBeDefined(); - }); - - it('Invalid schema present in folder', async () => { - function invalidSchema() { - const graphqlSchemaPath = path.join(__dirname, 'mock-data', 'invalid_schema.graphql'); - readSchema(graphqlSchemaPath); - } - expect(invalidSchema).toThrowErrorMatchingInlineSnapshot(` - "Could not parse graphql scehma - typo Todo @model { - id: ID! - name: String! - description: String - createdAt: AWSDateTime! - updatedAt: AWSDateTime! - } - " - `); - }); - - it('Empty schema present in folder', async () => { - const graphqlSchemaPath = path.join(__dirname, 'mock-data', 'empty_schema.graphql'); - expect(readSchema(graphqlSchemaPath)).toBeNull(); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/commands/api/mock-data/empty_schema.graphql b/packages/amplify-category-api/src/__tests__/commands/api/mock-data/empty_schema.graphql deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/amplify-category-api/src/__tests__/commands/api/mock-data/invalid_schema.graphql b/packages/amplify-category-api/src/__tests__/commands/api/mock-data/invalid_schema.graphql deleted file mode 100644 index 4d56fbd77d..0000000000 --- a/packages/amplify-category-api/src/__tests__/commands/api/mock-data/invalid_schema.graphql +++ /dev/null @@ -1,7 +0,0 @@ -typo Todo @model { - id: ID! - name: String! - description: String - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} \ No newline at end of file diff --git a/packages/amplify-category-api/src/__tests__/commands/api/mock-data/schema.graphql b/packages/amplify-category-api/src/__tests__/commands/api/mock-data/schema.graphql deleted file mode 100644 index 619867da0a..0000000000 --- a/packages/amplify-category-api/src/__tests__/commands/api/mock-data/schema.graphql +++ /dev/null @@ -1,7 +0,0 @@ -type Todo @model { - id: ID! - name: String! - description: String - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} diff --git a/packages/amplify-category-api/src/__tests__/commands/api/rebuild.test.ts b/packages/amplify-category-api/src/__tests__/commands/api/rebuild.test.ts deleted file mode 100644 index a6369c2a80..0000000000 --- a/packages/amplify-category-api/src/__tests__/commands/api/rebuild.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { $TSContext, FeatureFlags, stateManager } from '@aws-amplify/amplify-cli-core'; -import { printer, prompter } from '@aws-amplify/amplify-prompts'; -import { mocked } from 'ts-jest/utils'; -import { run } from '../../../commands/api/rebuild'; - -jest.mock('@aws-amplify/amplify-cli-core'); -jest.mock('@aws-amplify/amplify-prompts'); - -const FeatureFlags_mock = mocked(FeatureFlags); -const stateManager_mock = mocked(stateManager); -const printer_mock = mocked(printer); -const prompter_mock = mocked(prompter); - -FeatureFlags_mock.getBoolean.mockReturnValue(true); - -beforeEach(jest.clearAllMocks); - -const pushResourcesMock = jest.fn(); - -const context_stub = { - amplify: { - constructExeInfo: jest.fn(), - pushResources: pushResourcesMock, - }, - parameters: { - first: 'resourceName', - }, -} as unknown as $TSContext; - -it('prints error if iterative updates not enabled', async () => { - FeatureFlags_mock.getBoolean.mockReturnValueOnce(false); - - await run(context_stub); - - expect(printer_mock.error.mock.calls.length).toBe(1); - expect(pushResourcesMock.mock.calls.length).toBe(0); -}); - -it('exits early if no api in project', async () => { - stateManager_mock.getMeta.mockReturnValueOnce({ - api: {}, - }); - - await run(context_stub); - - expect(printer_mock.info.mock.calls.length).toBe(1); - expect(pushResourcesMock.mock.calls.length).toBe(0); -}); - -it('asks for strong confirmation before continuing', async () => { - stateManager_mock.getMeta.mockReturnValueOnce({ - api: { - testapiname: { - service: 'AppSync', - }, - }, - }); - - await run(context_stub); - - expect(prompter_mock.input.mock.calls.length).toBe(1); - expect(pushResourcesMock.mock.calls.length).toBe(1); - expect(pushResourcesMock.mock.calls[0][4]).toBe(true); // rebuild flag is set -}); diff --git a/packages/amplify-category-api/src/__tests__/errors/amplify-error-converter.test.ts b/packages/amplify-category-api/src/__tests__/errors/amplify-error-converter.test.ts deleted file mode 100644 index 4c692b7f9b..0000000000 --- a/packages/amplify-category-api/src/__tests__/errors/amplify-error-converter.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { AmplifyError, AmplifyErrorType, AmplifyException } from '@aws-amplify/amplify-cli-core'; -import { InvalidDirectiveError } from '@aws-amplify/graphql-transformer-core'; -import { AmplifyGraphQLTransformerErrorConverter } from '../../errors/amplify-error-converter'; -import { InvalidOverrideError } from '../../graphql-transformer/override'; - -const errorType: AmplifyErrorType = 'DeploymentError'; -// converted error to amplifyException -const error = new Error('mockMessage'); -error.name = errorType; -/** - * deepest amplify exception to get printed if amplify fault is thrown - */ - -const amplifyError = new AmplifyError('AmplifyStudioError', { - message: 'mockMessage', -}); - -test('returns error if the error isnt mentioned in list', async () => { - expect(AmplifyGraphQLTransformerErrorConverter.convert(error)).toBeInstanceOf(Error); - expect(AmplifyGraphQLTransformerErrorConverter.convert(error).name).toMatch(errorType); -}); - -test('returns a default error if the error isnt instance of Error', async () => { - expect(AmplifyGraphQLTransformerErrorConverter.convert(amplifyError).name).toMatch('AmplifyStudioError'); -}); - -test('returns user error if the error is present in list', async () => { - // error name is user error list - error.name = 'InvalidDirectiveError'; - expect(AmplifyGraphQLTransformerErrorConverter.convert(error)).toBeInstanceOf(AmplifyException); - expect(AmplifyGraphQLTransformerErrorConverter.convert(error).name).toMatch('InvalidDirectiveError'); -}); - -test('returns all properties if the error is present in list', async () => { - const originalError = new Error('original error message'); - const invalidOverrideError = new InvalidOverrideError(originalError); - const amplifyError = AmplifyGraphQLTransformerErrorConverter.convert(invalidOverrideError); - expect(amplifyError).toBeInstanceOf(AmplifyException); - expect(amplifyError.name).toEqual('InvalidOverrideError'); - expect(amplifyError.details).toEqual(originalError.message); - expect(amplifyError.resolution).toEqual('There may be runtime errors in your overrides file. If so, fix the errors and try again.'); -}); - -test('message is included if not overridden', () => { - const message = 'invalid directive message'; - // Invalid directive error does not override the message - const invalidDirectiveError = new InvalidDirectiveError(message); - expect(AmplifyGraphQLTransformerErrorConverter.convert(invalidDirectiveError).message).toEqual(message); -}); diff --git a/packages/amplify-category-api/src/__tests__/force-updates/auth-notifications.ts b/packages/amplify-category-api/src/__tests__/force-updates/auth-notifications.ts deleted file mode 100644 index 409219e90d..0000000000 --- a/packages/amplify-category-api/src/__tests__/force-updates/auth-notifications.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { collectDirectivesByType } from 'graphql-transformer-core'; -import { parse } from 'graphql'; -import { $TSContext, FeatureFlags, pathManager, stateManager } from '@aws-amplify/amplify-cli-core'; -import { - displayAuthNotification, - hasFieldAuthDirectives, - notifyFieldAuthSecurityChange, - notifyListQuerySecurityChange, - notifySecurityEnhancement, -} from '../../force-updates/auth-notifications'; - -jest.mock('@aws-amplify/amplify-cli-core'); - -const FeatureFlagsMock = FeatureFlags as jest.Mocked; -FeatureFlagsMock.getNumber.mockReturnValue(2); - -const stateManagerMock = stateManager as jest.Mocked; -// eslint-disable-next-line spellcheck/spell-checker -stateManagerMock.getCLIJSON.mockReturnValue({ features: { graphqltransformer: {} } }); - -const contextMock = { - amplify: {}, - parameters: { - first: 'resourceName', - }, -} as unknown as $TSContext; - -describe('displayAuthNotification', () => { - it('level "off" returns true', () => { - const map: any = collectDirectivesByType(` - type MyModel @model(subscriptions: { level: off }) { - id: ID! - } - `); - const set: Set = new Set(['MyModel']); - - expect(displayAuthNotification(map, set)).toBe(true); - }); - - it('level "null" returns true', () => { - const map: any = collectDirectivesByType(` - type MyModel @model(subscriptions: { level: null }) { - id: ID! - } - `); - const set: Set = new Set(['MyModel']); - - expect(displayAuthNotification(map, set)).toBe(true); - }); - - it('subscriptions is null returns true', () => { - const map: any = collectDirectivesByType(` - type MyModel @model(subscriptions: null) { - id: ID! - } - `); - const set: Set = new Set(['MyModel']); - - expect(displayAuthNotification(map, set)).toBe(true); - }); - - it('"public" returns false', () => { - const map: any = collectDirectivesByType(` - type MyModel @model(subscriptions: { level: public }) { - id: ID! - } - `); - const set: Set = new Set(['MyModel']); - - expect(displayAuthNotification(map, set)).toBe(false); - }); - - it('"on" returns false', () => { - const map: any = collectDirectivesByType(` - type MyModel @model(subscriptions: { level: on }) { - id: ID! - } - `); - const set: Set = new Set(['MyModel']); - - expect(displayAuthNotification(map, set)).toBe(false); - }); - - it('absent value returns false', () => { - const map: any = collectDirectivesByType(` - type MyModel @model { - id: ID! - } - `); - const set: Set = new Set(['MyModel']); - - expect(displayAuthNotification(map, set)).toBe(false); - }); -}); - -describe('hasFieldAuthDirectives', () => { - it('returns types with field auth directives', () => { - const doc = parse(` - type TypeWithFieldAuth @auth(rules: { allow: private, operations: [read] }) { - fieldWithAuth: String! @auth(rules: { allow: groups, group: "admin" }) - } - - type TypeWithoutFieldAuth @auth(rules: { allow: private, operations: [read] }) { - fieldWithoutAuth: String! - } - `); - - const result = hasFieldAuthDirectives(doc); - - expect(result).toContain('TypeWithFieldAuth'); - expect(result).not.toContain('TypeWithoutFieldAuth'); - }); - - it('returns empty set when no field auth', () => { - const doc = parse(` - type TypeWithoutFieldAuth @auth(rules: { allow: private, operations: [read] }) { - fieldWithoutAuth: String! - } - `); - - const result = hasFieldAuthDirectives(doc); - expect(result.size).toBe(0); - }); - - it('returns empty set with nullable and field auth', () => { - const doc = parse(` - type TypeWithFieldAuth @auth(rules: { allow: private, operations: [read] }) { - fieldWithAuth: String @auth(rules: { allow: groups, group: "admin" }) - } - `); - - const result = hasFieldAuthDirectives(doc); - expect(result.size).toBe(0); - }); -}); - -describe('push notifications', () => { - afterEach(() => { - jest.clearAllMocks(); - }); - - it('notifyFieldAuthSecurityChange should exit without fail when there is not api resource directory', async () => { - (FeatureFlags.getBoolean).mockReturnValue(true); - (pathManager.getResourceDirectoryPath).mockReturnValue('path-to-non-existing-resource-directory'); - (stateManager.getMeta).mockReturnValue({ - api: { - 'test-api-dev': { - service: 'AppSync', - output: { - name: 'test-api-dev', - }, - }, - }, - }); - (FeatureFlags.ensureFeatureFlag).mockImplementation(() => { - /* noop */ - }); - await notifyFieldAuthSecurityChange(contextMock); - // eslint-disable-next-line spellcheck/spell-checker - expect(FeatureFlags.ensureFeatureFlag).toHaveBeenCalledWith('graphqltransformer', 'showFieldAuthNotification'); - }); - - it('notifyListQuerySecurityChange should exit without fail when there is not api resource directory', async () => { - (pathManager.getResourceDirectoryPath).mockReturnValue('path-to-non-existing-resource-directory'); - (stateManager.getMeta).mockReturnValue({ - api: { - 'test-api-dev': { - service: 'AppSync', - output: { - name: 'test-api-dev', - }, - }, - }, - }); - (FeatureFlags.ensureFeatureFlag).mockImplementation(() => { - /* noop */ - }); - await notifyListQuerySecurityChange(contextMock); - }); - - it('notifySecurityEnhancement should exit without fail when there is not api resource directory', async () => { - (FeatureFlags.getBoolean).mockReturnValue(true); - (pathManager.getResourceDirectoryPath).mockReturnValue('path-to-non-existing-resource-directory'); - (stateManager.getMeta).mockReturnValue({ - api: { - 'test-api-dev': { - service: 'AppSync', - output: { - name: 'test-api-dev', - }, - }, - }, - }); - (FeatureFlags.ensureFeatureFlag).mockImplementation(() => { - /* noop */ - }); - await notifySecurityEnhancement(contextMock); - // eslint-disable-next-line spellcheck/spell-checker - expect(FeatureFlags.ensureFeatureFlag).toHaveBeenCalledWith('graphqltransformer', 'securityEnhancementNotification'); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/api-key-helpers.test.ts b/packages/amplify-category-api/src/__tests__/graphql-transformer/api-key-helpers.test.ts deleted file mode 100644 index f914e94a7c..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/api-key-helpers.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ApiKeyConfig } from '@aws-amplify/graphql-transformer-interfaces'; -import { hasApiKey } from '../../graphql-transformer/api-key-helpers'; - -jest.mock('@aws-amplify/amplify-cli-core', () => { - const original = jest.requireActual('@aws-amplify/amplify-cli-core'); - return { - ...original, - CloudformationProviderFacade: { - getApiKeyConfig: jest.fn( - () => - ({ - apiKeyExpirationDays: 2, - apiKeyExpirationDate: new Date('2021-08-20T20:38:07.585Z'), - description: '', - } as ApiKeyConfig), - ), - }, - }; -}); - -describe('hasApiKey', () => { - describe('if api key config is present', () => { - it('returns true if api key is present', () => { - expect(hasApiKey(expect.anything())).toBeTruthy(); - }); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/graphql-push-schema-checks.test.ts b/packages/amplify-category-api/src/__tests__/graphql-transformer/graphql-push-schema-checks.test.ts deleted file mode 100644 index 5480f6c4fe..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/graphql-push-schema-checks.test.ts +++ /dev/null @@ -1,124 +0,0 @@ -const getParamMock = jest.fn(); - -import { - $TSContext, - stateManager, - getGraphQLTransformerOpenSearchProductionDocLink, - ApiCategoryFacade, -} from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; -import { searchablePushChecks } from '../../graphql-transformer/api-utils'; - -jest.mock('@aws-amplify/amplify-cli-core'); -jest.mock('@aws-amplify/amplify-prompts'); - -jest.mock('@aws-amplify/amplify-environment-parameters', () => ({ - ensureEnvParamManager: jest.fn().mockResolvedValue({ - instance: { - getResourceParamManager: jest.fn().mockReturnValue({ - getParam: getParamMock, - }), - }, - }), -})); - -const printerMock = printer as jest.Mocked; -const stateManagerMock = stateManager as jest.Mocked; -const getTransformerVersionMock = ApiCategoryFacade.getTransformerVersion as jest.MockedFunction< - typeof ApiCategoryFacade.getTransformerVersion ->; -const getGraphQLTransformerOpenSearchProductionDocLinkMock = getGraphQLTransformerOpenSearchProductionDocLink as jest.MockedFunction< - typeof getGraphQLTransformerOpenSearchProductionDocLink ->; -printerMock.warn.mockImplementation(jest.fn()); -getGraphQLTransformerOpenSearchProductionDocLinkMock.mockReturnValue('mockDocsLink'); -// use transformer v2 for tests -getTransformerVersionMock.mockReturnValue(new Promise((resolve) => resolve(2))); - -describe('graphql schema checks', () => { - const contextMock = { - amplify: { - getEnvInfo: jest.fn(), - }, - } as unknown as $TSContext; - - const printerWarning = - 'Your instance type for OpenSearch is t2.small.elasticsearch, you may experience performance issues or data loss.' + - ' Consider reconfiguring with the instructions here mockDocsLink'; - - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('should warn users if they use not recommended open search instance without overrides', async () => { - stateManagerMock.getLocalEnvInfo.mockReturnValue({ envName: 'test' }); - getParamMock.mockReturnValueOnce(undefined); - const map = { Post: ['model', 'searchable'] }; - await searchablePushChecks(contextMock, map, 'test_api_name'); - expect(printerMock.warn).lastCalledWith(printerWarning); - }); - - it('should warn users if they use not recommended open search instance with overrides', async () => { - getParamMock.mockReturnValueOnce('t2.small.elasticsearch'); - stateManagerMock.getLocalEnvInfo.mockReturnValue({ envName: 'test' }); - const map = { Post: ['model', 'searchable'] }; - await searchablePushChecks(contextMock, map, 'test_api_name'); - expect(printerMock.warn).lastCalledWith(printerWarning); - }); - - it('should warn users if they use not recommended elastic search instance with overrides', async () => { - getParamMock.mockReturnValueOnce('t2.small.elasticsearch'); - stateManagerMock.getLocalEnvInfo.mockReturnValue({ envName: 'test' }); - const map = { Post: ['model', 'searchable'] }; - await searchablePushChecks(contextMock, map, 'test_api_name'); - expect(printerMock.warn).lastCalledWith(printerWarning); - }); - - it('should NOT warn users if they use recommended open search instance', async () => { - getParamMock.mockReturnValueOnce('t2.medium.elasticsearch'); - stateManagerMock.getLocalEnvInfo.mockReturnValue({ envName: 'test' }); - const map = { Post: ['model', 'searchable'] }; - await searchablePushChecks(contextMock, map, 'test_api_name'); - expect(printerMock.warn).not.toBeCalled(); - }); - - it('should NOT warn users if they use recommended elastic search instance', async () => { - getParamMock.mockReturnValueOnce('t2.medium.elasticsearch'); - stateManagerMock.getLocalEnvInfo.mockReturnValue({ envName: 'test' }); - const map = { Post: ['model', 'searchable'] }; - await searchablePushChecks(contextMock, map, 'test_api_name'); - expect(printerMock.warn).not.toBeCalled(); - }); - - it('should NOT warn users if they use recommended open search instance on the environment', async () => { - getParamMock.mockReturnValueOnce('t2.medium.elasticsearch'); - stateManagerMock.getLocalEnvInfo.mockReturnValue({ envName: 'prod' }); - const map = { Post: ['model', 'searchable'] }; - await searchablePushChecks(contextMock, map, 'test_api_name'); - expect(printerMock.warn).not.toBeCalled(); - }); - - it('should NOT warn users if they use recommended elastic search instance on the environment', async () => { - getParamMock.mockReturnValueOnce('t2.medium.elasticsearch'); - stateManagerMock.getLocalEnvInfo.mockReturnValue({ envName: 'prod' }); - const map = { Post: ['model', 'searchable'] }; - await searchablePushChecks(contextMock, map, 'test_api_name'); - expect(printerMock.warn).not.toBeCalled(); - }); - - it('should NOT warn users if they do NOT use searchable', async () => { - getParamMock.mockReturnValueOnce(undefined); - stateManagerMock.getLocalEnvInfo.mockReturnValue({ envName: 'test' }); - const map = { Post: ['model'] }; - await searchablePushChecks(contextMock, map, 'test_api_name'); - expect(printerMock.warn).not.toBeCalled(); - }); - - it('should warn users if they use not recommended open search instance with overrides', async () => { - getParamMock.mockReturnValueOnce(undefined); - stateManagerMock.getLocalEnvInfo.mockReturnValue({ envName: 'test' }); - const map = { Post: ['model', 'searchable'] }; - await searchablePushChecks(contextMock, map, 'test_api_name'); - expect(printerMock.warn).lastCalledWith(printerWarning); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-function-transformer-override.test.ts.snap b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-function-transformer-override.test.ts.snap deleted file mode 100644 index f0b1e1c0fa..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-function-transformer-override.test.ts.snap +++ /dev/null @@ -1,813 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`it ovderrides the expected resources 1`] = ` -Object { - "AWSTemplateFormatVersion": "2010-09-09", - "Conditions": Object { - "HasEnvironmentParameter": Object { - "Fn::Not": Array [ - Object { - "Fn::Equals": Array [ - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - "NONE", - ], - }, - ], - }, - }, - "Description": "An auto-generated nested stack for the @function directive.", - "Parameters": Object { - "referencetotransformerrootstackGraphQLAPI20497F53ApiId": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentBucket7592718ARef": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref": Object { - "Type": "String", - }, - "referencetotransformerrootstackenv10C5A902Ref": Object { - "Type": "String", - }, - }, - "Resources": Object { - "EchofunctionLambdaDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "LambdaConfig": Object { - "LambdaFunctionArn": Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:echofunction-\${env}", - Object { - "env": Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - }, - ], - }, - Object { - "Fn::Sub": "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:echofunction", - }, - ], - }, - }, - "Name": "EchofunctionLambdaDataSource", - "ServiceRoleArn": "mockArn", - "Type": "AWS_LAMBDA", - }, - "Type": "AWS::AppSync::DataSource", - }, - "EchofunctionLambdaDataSourceServiceRole3BE2FA57": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "EchofunctionLambdaDataSourceServiceRoleDefaultPolicyCAA363A9": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:echofunction-\${env}", - Object { - "env": Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - }, - ], - }, - Object { - "Fn::Sub": "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:echofunction", - }, - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:echofunction-\${env}", - Object { - "env": Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - }, - ], - }, - Object { - "Fn::Sub": "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:echofunction", - }, - ], - }, - ":*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "EchofunctionLambdaDataSourceServiceRoleDefaultPolicyCAA363A9", - "Roles": Array [ - Object { - "Ref": "EchofunctionLambdaDataSourceServiceRole3BE2FA57", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "InvokeEchofunctionLambdaDataSourceInvokeEchofunctionLambdaDataSourceAppSyncFunctionCDB52C03": Object { - "DependsOn": Array [ - "EchofunctionLambdaDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "EchofunctionLambdaDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "InvokeEchofunctionLambdaDataSource", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/InvokeEchofunctionLambdaDataSource.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/InvokeEchofunctionLambdaDataSource.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "InvokeOtherfunctionLambdaDataSourceInvokeOtherfunctionLambdaDataSourceAppSyncFunctionB834903D": Object { - "DependsOn": Array [ - "OtherfunctionLambdaDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "OtherfunctionLambdaDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "InvokeOtherfunctionLambdaDataSource", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/InvokeOtherfunctionLambdaDataSource.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/InvokeOtherfunctionLambdaDataSource.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "OtherfunctionLambdaDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "LambdaConfig": Object { - "LambdaFunctionArn": Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:otherfunction", - Object {}, - ], - }, - Object { - "Fn::Sub": "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:otherfunction", - }, - ], - }, - }, - "Name": "OtherfunctionLambdaDataSource", - "ServiceRoleArn": "mockArn", - "Type": "AWS_LAMBDA", - }, - "Type": "AWS::AppSync::DataSource", - }, - "OtherfunctionLambdaDataSourceServiceRole611EC792": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "OtherfunctionLambdaDataSourceServiceRoleDefaultPolicy3263A5C1": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:otherfunction", - Object {}, - ], - }, - Object { - "Fn::Sub": "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:otherfunction", - }, - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:otherfunction", - Object {}, - ], - }, - Object { - "Fn::Sub": "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:otherfunction", - }, - ], - }, - ":*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "OtherfunctionLambdaDataSourceServiceRoleDefaultPolicy3263A5C1", - "Roles": Array [ - Object { - "Ref": "OtherfunctionLambdaDataSourceServiceRole611EC792", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "QueryechoResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "echo", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "InvokeEchofunctionLambdaDataSourceInvokeEchofunctionLambdaDataSourceAppSyncFunctionCDB52C03", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "InvokeOtherfunctionLambdaDataSourceInvokeOtherfunctionLambdaDataSourceAppSyncFunctionB834903D", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": "mockTemplate", - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.echo.res.vtl", - ], - ], - }, - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", - }, - }, -} -`; - -exports[`it skips override if override file does not exist 1`] = ` -Object { - "AWSTemplateFormatVersion": "2010-09-09", - "Conditions": Object { - "HasEnvironmentParameter": Object { - "Fn::Not": Array [ - Object { - "Fn::Equals": Array [ - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - "NONE", - ], - }, - ], - }, - }, - "Description": "An auto-generated nested stack for the @function directive.", - "Parameters": Object { - "referencetotransformerrootstackGraphQLAPI20497F53ApiId": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentBucket7592718ARef": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref": Object { - "Type": "String", - }, - "referencetotransformerrootstackenv10C5A902Ref": Object { - "Type": "String", - }, - }, - "Resources": Object { - "EchofunctionLambdaDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "LambdaConfig": Object { - "LambdaFunctionArn": Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:echofunction-\${env}", - Object { - "env": Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - }, - ], - }, - Object { - "Fn::Sub": "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:echofunction", - }, - ], - }, - }, - "Name": "EchofunctionLambdaDataSource", - "ServiceRoleArn": Object { - "Fn::GetAtt": Array [ - "EchofunctionLambdaDataSourceServiceRole3BE2FA57", - "Arn", - ], - }, - "Type": "AWS_LAMBDA", - }, - "Type": "AWS::AppSync::DataSource", - }, - "EchofunctionLambdaDataSourceServiceRole3BE2FA57": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "EchofunctionLambdaDataSourceServiceRoleDefaultPolicyCAA363A9": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:echofunction-\${env}", - Object { - "env": Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - }, - ], - }, - Object { - "Fn::Sub": "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:echofunction", - }, - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:echofunction-\${env}", - Object { - "env": Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - }, - ], - }, - Object { - "Fn::Sub": "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:echofunction", - }, - ], - }, - ":*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "EchofunctionLambdaDataSourceServiceRoleDefaultPolicyCAA363A9", - "Roles": Array [ - Object { - "Ref": "EchofunctionLambdaDataSourceServiceRole3BE2FA57", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "InvokeEchofunctionLambdaDataSourceInvokeEchofunctionLambdaDataSourceAppSyncFunctionCDB52C03": Object { - "DependsOn": Array [ - "EchofunctionLambdaDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "EchofunctionLambdaDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "InvokeEchofunctionLambdaDataSource", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/InvokeEchofunctionLambdaDataSource.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/InvokeEchofunctionLambdaDataSource.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "InvokeOtherfunctionLambdaDataSourceInvokeOtherfunctionLambdaDataSourceAppSyncFunctionB834903D": Object { - "DependsOn": Array [ - "OtherfunctionLambdaDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "OtherfunctionLambdaDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "InvokeOtherfunctionLambdaDataSource", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/InvokeOtherfunctionLambdaDataSource.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/InvokeOtherfunctionLambdaDataSource.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "OtherfunctionLambdaDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "LambdaConfig": Object { - "LambdaFunctionArn": Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:otherfunction", - Object {}, - ], - }, - Object { - "Fn::Sub": "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:otherfunction", - }, - ], - }, - }, - "Name": "OtherfunctionLambdaDataSource", - "ServiceRoleArn": Object { - "Fn::GetAtt": Array [ - "OtherfunctionLambdaDataSourceServiceRole611EC792", - "Arn", - ], - }, - "Type": "AWS_LAMBDA", - }, - "Type": "AWS::AppSync::DataSource", - }, - "OtherfunctionLambdaDataSourceServiceRole611EC792": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "OtherfunctionLambdaDataSourceServiceRoleDefaultPolicy3263A5C1": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:otherfunction", - Object {}, - ], - }, - Object { - "Fn::Sub": "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:otherfunction", - }, - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:otherfunction", - Object {}, - ], - }, - Object { - "Fn::Sub": "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:otherfunction", - }, - ], - }, - ":*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "OtherfunctionLambdaDataSourceServiceRoleDefaultPolicy3263A5C1", - "Roles": Array [ - Object { - "Ref": "OtherfunctionLambdaDataSourceServiceRole611EC792", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "QueryechoResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "echo", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "InvokeEchofunctionLambdaDataSourceInvokeEchofunctionLambdaDataSourceAppSyncFunctionCDB52C03", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "InvokeOtherfunctionLambdaDataSourceInvokeOtherfunctionLambdaDataSourceAppSyncFunctionB834903D", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": "## [Start] Stash resolver specific context.. ** -$util.qr($ctx.stash.put(\\"typeName\\", \\"Query\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"echo\\")) -{} -## [End] Stash resolver specific context.. **", - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.echo.res.vtl", - ], - ], - }, - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", - }, - }, -} -`; diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-http-transformer-override.test.ts.snap b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-http-transformer-override.test.ts.snap deleted file mode 100644 index 5b2e7f2724..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-http-transformer-override.test.ts.snap +++ /dev/null @@ -1,1235 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`it generates the overrided resources 1`] = ` -Object { - "AWSTemplateFormatVersion": "2010-09-09", - "Description": "An auto-generated nested stack for the @http directive.", - "Parameters": Object { - "referencetotransformerrootstackGraphQLAPI20497F53ApiId": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentBucket7592718ARef": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref": Object { - "Type": "String", - }, - }, - "Resources": Object { - "Commentcontent2Resolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "content2", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "httpwwwapicomDataSourceCommentcontent2FunctionhttpwwwapicomDataSourceCommentcontent2FunctionAppSyncFunctionA4F35A01", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": "## [Start] Stash resolver specific context.. ** -$util.qr($ctx.stash.put(\\"typeName\\", \\"Comment\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"content2\\")) -{} -## [End] Stash resolver specific context.. **", - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.content2.res.vtl", - ], - ], - }, - "TypeName": "Comment", - }, - "Type": "AWS::AppSync::Resolver", - }, - "CommentcontentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "content", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "httpwwwapicomDataSourceCommentcontentFunctionhttpwwwapicomDataSourceCommentcontentFunctionAppSyncFunction685EFA2A", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": "mockTemplate", - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.content.res.vtl", - ], - ], - }, - "TypeName": "Comment", - }, - "Type": "AWS::AppSync::Resolver", - }, - "CommentevenMoreResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "evenMore", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "httpwwwgooglecomDataSourceCommentevenMoreFunctionhttpwwwgooglecomDataSourceCommentevenMoreFunctionAppSyncFunction47773D49", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": "## [Start] Stash resolver specific context.. ** -$util.qr($ctx.stash.put(\\"typeName\\", \\"Comment\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"evenMore\\")) -{} -## [End] Stash resolver specific context.. **", - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.evenMore.res.vtl", - ], - ], - }, - "TypeName": "Comment", - }, - "Type": "AWS::AppSync::Resolver", - }, - "CommentmoreResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "more", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "httpapicomDataSourceCommentmoreFunctionhttpapicomDataSourceCommentmoreFunctionAppSyncFunction5BEF6F35", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": "## [Start] Stash resolver specific context.. ** -$util.qr($ctx.stash.put(\\"typeName\\", \\"Comment\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"more\\")) -{} -## [End] Stash resolver specific context.. **", - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.more.res.vtl", - ], - ], - }, - "TypeName": "Comment", - }, - "Type": "AWS::AppSync::Resolver", - }, - "CommentstillMoreResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "stillMore", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "httpswwwapicomDataSourceCommentstillMoreFunctionhttpswwwapicomDataSourceCommentstillMoreFunctionAppSyncFunction51FAE1A5", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": "## [Start] Stash resolver specific context.. ** -$util.qr($ctx.stash.put(\\"typeName\\", \\"Comment\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"stillMore\\")) -{} -## [End] Stash resolver specific context.. **", - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.stillMore.res.vtl", - ], - ], - }, - "TypeName": "Comment", - }, - "Type": "AWS::AppSync::Resolver", - }, - "httpapicomDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "HttpConfig": Object { - "Endpoint": "mockEndpoint", - }, - "Name": "httpapicomDataSource", - "ServiceRoleArn": "mockArn", - "Type": "HTTP", - }, - "Type": "AWS::AppSync::DataSource", - }, - "httpapicomDataSourceCommentmoreFunctionhttpapicomDataSourceCommentmoreFunctionAppSyncFunction5BEF6F35": Object { - "DependsOn": Array [ - "httpapicomDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "httpapicomDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "httpapicomDataSourceCommentmoreFunction", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.more.DataResolver.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.more.DataResolver.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "httpapicomDataSourceServiceRoleC12170E3": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "httpswwwapicomDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "HttpConfig": Object { - "Endpoint": "mockEndpoint", - }, - "Name": "httpswwwapicomDataSource", - "ServiceRoleArn": "mockArn", - "Type": "HTTP", - }, - "Type": "AWS::AppSync::DataSource", - }, - "httpswwwapicomDataSourceCommentstillMoreFunctionhttpswwwapicomDataSourceCommentstillMoreFunctionAppSyncFunction51FAE1A5": Object { - "DependsOn": Array [ - "httpswwwapicomDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "httpswwwapicomDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "httpswwwapicomDataSourceCommentstillMoreFunction", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.stillMore.DataResolver.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.stillMore.DataResolver.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "httpswwwapicomDataSourceServiceRoleDE26F49B": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "httpwwwapicomDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "HttpConfig": Object { - "Endpoint": "mockEndpoint", - }, - "Name": "httpwwwapicomDataSource", - "ServiceRoleArn": "mockArn", - "Type": "HTTP", - }, - "Type": "AWS::AppSync::DataSource", - }, - "httpwwwapicomDataSourceCommentcontent2FunctionhttpwwwapicomDataSourceCommentcontent2FunctionAppSyncFunctionA4F35A01": Object { - "DependsOn": Array [ - "httpwwwapicomDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "httpwwwapicomDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "httpwwwapicomDataSourceCommentcontent2Function", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.content2.DataResolver.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.content2.DataResolver.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "httpwwwapicomDataSourceCommentcontentFunctionhttpwwwapicomDataSourceCommentcontentFunctionAppSyncFunction685EFA2A": Object { - "DependsOn": Array [ - "httpwwwapicomDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "httpwwwapicomDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "httpwwwapicomDataSourceCommentcontentFunction", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.content.DataResolver.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.content.DataResolver.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "httpwwwapicomDataSourceServiceRole20167D8C": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "httpwwwgooglecomDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "HttpConfig": Object { - "Endpoint": "mockEndpoint", - }, - "Name": "httpwwwgooglecomDataSource", - "ServiceRoleArn": "mockArn", - "Type": "HTTP", - }, - "Type": "AWS::AppSync::DataSource", - }, - "httpwwwgooglecomDataSourceCommentevenMoreFunctionhttpwwwgooglecomDataSourceCommentevenMoreFunctionAppSyncFunction47773D49": Object { - "DependsOn": Array [ - "httpwwwgooglecomDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "httpwwwgooglecomDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "httpwwwgooglecomDataSourceCommentevenMoreFunction", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.evenMore.DataResolver.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.evenMore.DataResolver.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "httpwwwgooglecomDataSourceServiceRole08261832": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - }, -} -`; - -exports[`it skips override if file does not exist 1`] = ` -Object { - "AWSTemplateFormatVersion": "2010-09-09", - "Description": "An auto-generated nested stack for the @http directive.", - "Parameters": Object { - "referencetotransformerrootstackGraphQLAPI20497F53ApiId": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentBucket7592718ARef": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref": Object { - "Type": "String", - }, - }, - "Resources": Object { - "Commentcontent2Resolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "content2", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "httpwwwapicomDataSourceCommentcontent2FunctionhttpwwwapicomDataSourceCommentcontent2FunctionAppSyncFunctionA4F35A01", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": "## [Start] Stash resolver specific context.. ** -$util.qr($ctx.stash.put(\\"typeName\\", \\"Comment\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"content2\\")) -{} -## [End] Stash resolver specific context.. **", - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.content2.res.vtl", - ], - ], - }, - "TypeName": "Comment", - }, - "Type": "AWS::AppSync::Resolver", - }, - "CommentcontentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "content", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "httpwwwapicomDataSourceCommentcontentFunctionhttpwwwapicomDataSourceCommentcontentFunctionAppSyncFunction685EFA2A", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": "## [Start] Stash resolver specific context.. ** -$util.qr($ctx.stash.put(\\"typeName\\", \\"Comment\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"content\\")) -{} -## [End] Stash resolver specific context.. **", - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.content.res.vtl", - ], - ], - }, - "TypeName": "Comment", - }, - "Type": "AWS::AppSync::Resolver", - }, - "CommentevenMoreResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "evenMore", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "httpwwwgooglecomDataSourceCommentevenMoreFunctionhttpwwwgooglecomDataSourceCommentevenMoreFunctionAppSyncFunction47773D49", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": "## [Start] Stash resolver specific context.. ** -$util.qr($ctx.stash.put(\\"typeName\\", \\"Comment\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"evenMore\\")) -{} -## [End] Stash resolver specific context.. **", - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.evenMore.res.vtl", - ], - ], - }, - "TypeName": "Comment", - }, - "Type": "AWS::AppSync::Resolver", - }, - "CommentmoreResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "more", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "httpapicomDataSourceCommentmoreFunctionhttpapicomDataSourceCommentmoreFunctionAppSyncFunction5BEF6F35", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": "## [Start] Stash resolver specific context.. ** -$util.qr($ctx.stash.put(\\"typeName\\", \\"Comment\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"more\\")) -{} -## [End] Stash resolver specific context.. **", - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.more.res.vtl", - ], - ], - }, - "TypeName": "Comment", - }, - "Type": "AWS::AppSync::Resolver", - }, - "CommentstillMoreResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "stillMore", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "httpswwwapicomDataSourceCommentstillMoreFunctionhttpswwwapicomDataSourceCommentstillMoreFunctionAppSyncFunction51FAE1A5", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": "## [Start] Stash resolver specific context.. ** -$util.qr($ctx.stash.put(\\"typeName\\", \\"Comment\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"stillMore\\")) -{} -## [End] Stash resolver specific context.. **", - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.stillMore.res.vtl", - ], - ], - }, - "TypeName": "Comment", - }, - "Type": "AWS::AppSync::Resolver", - }, - "httpapicomDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "HttpConfig": Object { - "Endpoint": "http://api.com", - }, - "Name": "httpapicomDataSource", - "ServiceRoleArn": Object { - "Fn::GetAtt": Array [ - "httpapicomDataSourceServiceRoleC12170E3", - "Arn", - ], - }, - "Type": "HTTP", - }, - "Type": "AWS::AppSync::DataSource", - }, - "httpapicomDataSourceCommentmoreFunctionhttpapicomDataSourceCommentmoreFunctionAppSyncFunction5BEF6F35": Object { - "DependsOn": Array [ - "httpapicomDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "httpapicomDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "httpapicomDataSourceCommentmoreFunction", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.more.DataResolver.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.more.DataResolver.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "httpapicomDataSourceServiceRoleC12170E3": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "httpswwwapicomDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "HttpConfig": Object { - "Endpoint": "https://www.api.com", - }, - "Name": "httpswwwapicomDataSource", - "ServiceRoleArn": Object { - "Fn::GetAtt": Array [ - "httpswwwapicomDataSourceServiceRoleDE26F49B", - "Arn", - ], - }, - "Type": "HTTP", - }, - "Type": "AWS::AppSync::DataSource", - }, - "httpswwwapicomDataSourceCommentstillMoreFunctionhttpswwwapicomDataSourceCommentstillMoreFunctionAppSyncFunction51FAE1A5": Object { - "DependsOn": Array [ - "httpswwwapicomDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "httpswwwapicomDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "httpswwwapicomDataSourceCommentstillMoreFunction", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.stillMore.DataResolver.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.stillMore.DataResolver.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "httpswwwapicomDataSourceServiceRoleDE26F49B": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "httpwwwapicomDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "HttpConfig": Object { - "Endpoint": "http://www.api.com", - }, - "Name": "httpwwwapicomDataSource", - "ServiceRoleArn": Object { - "Fn::GetAtt": Array [ - "httpwwwapicomDataSourceServiceRole20167D8C", - "Arn", - ], - }, - "Type": "HTTP", - }, - "Type": "AWS::AppSync::DataSource", - }, - "httpwwwapicomDataSourceCommentcontent2FunctionhttpwwwapicomDataSourceCommentcontent2FunctionAppSyncFunctionA4F35A01": Object { - "DependsOn": Array [ - "httpwwwapicomDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "httpwwwapicomDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "httpwwwapicomDataSourceCommentcontent2Function", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.content2.DataResolver.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.content2.DataResolver.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "httpwwwapicomDataSourceCommentcontentFunctionhttpwwwapicomDataSourceCommentcontentFunctionAppSyncFunction685EFA2A": Object { - "DependsOn": Array [ - "httpwwwapicomDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "httpwwwapicomDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "httpwwwapicomDataSourceCommentcontentFunction", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.content.DataResolver.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.content.DataResolver.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "httpwwwapicomDataSourceServiceRole20167D8C": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "httpwwwgooglecomDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "HttpConfig": Object { - "Endpoint": "http://www.google.com", - }, - "Name": "httpwwwgooglecomDataSource", - "ServiceRoleArn": Object { - "Fn::GetAtt": Array [ - "httpwwwgooglecomDataSourceServiceRole08261832", - "Arn", - ], - }, - "Type": "HTTP", - }, - "Type": "AWS::AppSync::DataSource", - }, - "httpwwwgooglecomDataSourceCommentevenMoreFunctionhttpwwwgooglecomDataSourceCommentevenMoreFunctionAppSyncFunction47773D49": Object { - "DependsOn": Array [ - "httpwwwgooglecomDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "httpwwwgooglecomDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "httpwwwgooglecomDataSourceCommentevenMoreFunction", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.evenMore.DataResolver.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Comment.evenMore.DataResolver.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "httpwwwgooglecomDataSourceServiceRole08261832": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - }, -} -`; diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-index-transformer-override.test.ts.snap b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-index-transformer-override.test.ts.snap deleted file mode 100644 index 69e5a6d87a..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-index-transformer-override.test.ts.snap +++ /dev/null @@ -1,397 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`it overrides expected resources 1`] = ` -Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "createSong", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "MutationcreateSonginit0FunctionMutationcreateSonginit0FunctionAppSyncFunction55782DDF", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QuerygetSongpostAuth0FunctionQuerygetSongpostAuth0FunctionAppSyncFunction30BEE102", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "MutationCreateSongDataResolverFnMutationCreateSongDataResolverFnAppSyncFunctionFC04B955", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"createSong\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "SongTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"deltaSyncTableTtl\\", 15)) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", -} -`; - -exports[`it overrides expected resources 2`] = ` -Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "getSong", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerygetSongpostAuth0FunctionQuerygetSongpostAuth0FunctionAppSyncFunction30BEE102", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QueryGetSongDataResolverFnQueryGetSongDataResolverFnAppSyncFunctionC7E7E88A", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Query\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"getSong\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "SongTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"deltaSyncTableTtl\\", 15)) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", -} -`; - -exports[`it overrides expected resources 3`] = ` -Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "listSongs", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerygetSongpostAuth0FunctionQuerygetSongpostAuth0FunctionAppSyncFunction30BEE102", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QueryListSongsDataResolverFnQueryListSongsDataResolverFnAppSyncFunctionD32DC12B", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Query\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"listSongs\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "SongTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"deltaSyncTableTtl\\", 15)) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", -} -`; - -exports[`it overrides expected resources 4`] = ` -Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "deleteSong", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerygetSongpostAuth0FunctionQuerygetSongpostAuth0FunctionAppSyncFunction30BEE102", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "MutationDeleteSongDataResolverFnMutationDeleteSongDataResolverFnAppSyncFunctionDE1E317E", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"deleteSong\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "SongTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"deltaSyncTableTtl\\", 15)) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", -} -`; - -exports[`it overrides expected resources 5`] = ` -Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "updateSong", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "MutationupdateSonginit0FunctionMutationupdateSonginit0FunctionAppSyncFunctionE35F0E12", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QuerygetSongpostAuth0FunctionQuerygetSongpostAuth0FunctionAppSyncFunction30BEE102", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "MutationUpdateSongDataResolverFnMutationUpdateSongDataResolverFnAppSyncFunction4ADCC009", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"updateSong\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "SongTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"deltaSyncTableTtl\\", 15)) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", -} -`; - -exports[`it overrides expected resources 6`] = ` -Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "syncSongs", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerysyncSongspreAuth0FunctionQuerysyncSongspreAuth0FunctionAppSyncFunction06967782", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QuerygetSongpostAuth0FunctionQuerygetSongpostAuth0FunctionAppSyncFunction30BEE102", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QuerySyncSongsDataResolverFnQuerySyncSongsDataResolverFnAppSyncFunction70698E3C", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Query\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"syncSongs\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "SongTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"deltaSyncTableTtl\\", 15)) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", -} -`; - -exports[`it overrides expected resources 7`] = ` -Object { - "DependsOn": Array [ - "SongIAMRole5755BC78", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DynamoDBConfig": Object { - "AwsRegion": Object { - "Ref": "AWS::Region", - }, - "DeltaSyncConfig": Object { - "BaseTableTTL": "20", - "DeltaSyncTableName": "SongTable", - "DeltaSyncTableTTL": "15", - }, - "TableName": Object { - "Ref": "SongTable", - }, - "Versioned": true, - }, - "Name": "SongTable", - "ServiceRoleArn": Object { - "Fn::GetAtt": Array [ - "SongIAMRole5755BC78", - "Arn", - ], - }, - "Type": "AMAZON_DYNAMODB", - }, - "Type": "AWS::AppSync::DataSource", -} -`; diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-predictions-transformer-override.test.ts.snap b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-predictions-transformer-override.test.ts.snap deleted file mode 100644 index d176583f43..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-predictions-transformer-override.test.ts.snap +++ /dev/null @@ -1,1749 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`it generates resources with overrides 1`] = ` -Object { - "PredictionsDirectiveStack": Object { - "Conditions": Object { - "HasEnvironmentParameter": Object { - "Fn::Not": Array [ - Object { - "Fn::Equals": Array [ - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - "NONE", - ], - }, - ], - }, - }, - "Parameters": Object { - "referencetotransformerrootstackGraphQLAPI20497F53ApiId": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentBucket7592718ARef": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref": Object { - "Type": "String", - }, - "referencetotransformerrootstackenv10C5A902Ref": Object { - "Type": "String", - }, - }, - "Resources": Object { - "LambdaDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "LambdaConfig": Object { - "LambdaFunctionArn": Object { - "Fn::GetAtt": Array [ - "predictionsLambda8B880A74", - "Arn", - ], - }, - }, - "Name": "LambdaDataSource", - "ServiceRoleArn": Object { - "Fn::GetAtt": Array [ - "predictionsIAMRole5BB74A99", - "Arn", - ], - }, - "Type": "AWS_LAMBDA", - }, - "Type": "AWS::AppSync::DataSource", - }, - "LambdaDataSourceServiceRole81BB3362": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "LambdaDataSourceServiceRoleDefaultPolicy00CC76B1": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "predictionsLambda8B880A74", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "predictionsLambda8B880A74", - "Arn", - ], - }, - ":*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "LambdaDataSourceServiceRoleDefaultPolicy00CC76B1", - "Roles": Array [ - Object { - "Ref": "LambdaDataSourceServiceRole81BB3362", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "PredictionsLambdaAccess4D9DA807": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "predictionsLambda8B880A74", - "Arn", - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "PredictionsLambdaAccess4D9DA807", - "Roles": Array [ - Object { - "Ref": "predictionsIAMRole5BB74A99", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "PredictionsStorageAccess68CD5140": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "s3:GetObject", - "Effect": "Allow", - "Resource": Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "arn:aws:s3:::myStorage\${hash}-\${env}/public/*", - Object { - "env": Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - "hash": Object { - "Fn::Select": Array [ - 3, - Object { - "Fn::Split": Array [ - "-", - Object { - "Ref": "AWS::StackName", - }, - ], - }, - ], - }, - }, - ], - }, - Object { - "Fn::Sub": Array [ - "arn:aws:s3:::myStorage\${hash}/public/*", - Object { - "hash": Object { - "Fn::Select": Array [ - 3, - Object { - "Fn::Split": Array [ - "-", - Object { - "Ref": "AWS::StackName", - }, - ], - }, - ], - }, - }, - ], - }, - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "PredictionsStorageAccess68CD5140", - "Roles": Array [ - Object { - "Ref": "predictionsIAMRole5BB74A99", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "QueryspeakTranslatedIdentifiedTextResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "speakTranslatedIdentifiedText", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "identifyTextFunctionidentifyTextFunctionAppSyncFunction7877885A", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "translateTextFunctiontranslateTextFunctionAppSyncFunction77C9D7A9", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "convertTextToSpeechFunctionconvertTextToSpeechFunctionAppSyncFunction15BC20B8", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - " -", - Array [ - Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "$util.qr($ctx.stash.put(\\"s3Bucket\\", \\"myStorage\${hash}-\${env}\\"))", - Object { - "env": Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - "hash": Object { - "Fn::Select": Array [ - 3, - Object { - "Fn::Split": Array [ - "-", - Object { - "Ref": "AWS::StackName", - }, - ], - }, - ], - }, - }, - ], - }, - Object { - "Fn::Sub": Array [ - "$util.qr($ctx.stash.put(\\"s3Bucket\\", \\"myStorage\${hash}\\"))", - Object { - "hash": Object { - "Fn::Select": Array [ - 3, - Object { - "Fn::Split": Array [ - "-", - Object { - "Ref": "AWS::StackName", - }, - ], - }, - ], - }, - }, - ], - }, - ], - }, - "$util.qr($ctx.stash.put(\\"isList\\", false)) -{}", - ], - ], - }, - "ResponseMappingTemplate": "## If the result is a list return the result as a list ** -#if( $ctx.stash.get(\\"isList\\") ) - #set( $result = $ctx.result.split(\\"[ ,]+\\") ) - $util.toJson($result) -#else - $util.toJson($ctx.result) -#end", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", - }, - "QueryspeakTranslatedLabelTextResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "speakTranslatedLabelText", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "identifyLabelsFunctionidentifyLabelsFunctionAppSyncFunction7C2A1E61", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "translateTextFunctiontranslateTextFunctionAppSyncFunction77C9D7A9", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "convertTextToSpeechFunctionconvertTextToSpeechFunctionAppSyncFunction15BC20B8", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": "mockTeplate", - "ResponseMappingTemplate": "## If the result is a list return the result as a list ** -#if( $ctx.stash.get(\\"isList\\") ) - #set( $result = $ctx.result.split(\\"[ ,]+\\") ) - $util.toJson($result) -#else - $util.toJson($ctx.result) -#end", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", - }, - "RekognitionDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "HttpConfig": Object { - "AuthorizationConfig": Object { - "AuthorizationType": "AWS_IAM", - "AwsIamConfig": Object { - "SigningRegion": Object { - "Fn::Sub": "\${AWS::Region}", - }, - "SigningServiceName": "rekognition", - }, - }, - "Endpoint": Object { - "Fn::Sub": "https://rekognition.\${AWS::Region}.amazonaws.com", - }, - }, - "Name": "RekognitionDataSource", - "ServiceRoleArn": Object { - "Fn::GetAtt": Array [ - "predictionsIAMRole5BB74A99", - "Arn", - ], - }, - "Type": "HTTP", - }, - "Type": "AWS::AppSync::DataSource", - }, - "RekognitionDataSourceServiceRole3628B5DB": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "TranslateDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "HttpConfig": Object { - "AuthorizationConfig": Object { - "AuthorizationType": "AWS_IAM", - "AwsIamConfig": Object { - "SigningRegion": Object { - "Fn::Sub": "\${AWS::Region}", - }, - "SigningServiceName": "translate", - }, - }, - "Endpoint": Object { - "Fn::Sub": "https://translate.\${AWS::Region}.amazonaws.com", - }, - }, - "Name": "TranslateDataSource", - "ServiceRoleArn": "mockArn", - "Type": "HTTP", - }, - "Type": "AWS::AppSync::DataSource", - }, - "TranslateDataSourceServiceRole2FE48B83": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "convertTextToSpeechFunctionconvertTextToSpeechFunctionAppSyncFunction15BC20B8": Object { - "DependsOn": Array [ - "LambdaDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "LambdaDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "convertTextToSpeechFunction", - "RequestMappingTemplate": "#set( $bucketName = $ctx.stash.get(\\"s3Bucket\\") ) -$util.qr($ctx.stash.put(\\"isList\\", false)) -#set( $text = $util.defaultIfNull($ctx.args.input.convertTextToSpeech.text, $ctx.prev.result) ) -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"Invoke\\", - \\"payload\\": $util.toJson({ - \\"uuid\\": \\"$util.autoId()\\", - \\"action\\": \\"convertTextToSpeech\\", - \\"voiceID\\": $ctx.args.input.convertTextToSpeech.voiceID, - \\"text\\": $text -}) -}", - "ResponseMappingTemplate": "#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type) -#end -#set( $response = $util.parseJson($ctx.result) ) -$util.toJson($ctx.result.url)", - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "identifyLabelsAccess7BFAF94B": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "rekognition:DetectLabels", - "Effect": "Allow", - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "identifyLabelsAccess7BFAF94B", - "Roles": Array [ - Object { - "Ref": "predictionsIAMRole5BB74A99", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "identifyLabelsFunctionidentifyLabelsFunctionAppSyncFunction7C2A1E61": Object { - "DependsOn": Array [ - "RekognitionDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "RekognitionDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "identifyLabelsFunction", - "RequestMappingTemplate": "#set( $bucketName = $ctx.stash.get(\\"s3Bucket\\") ) -#set( $identifyLabelKey = $ctx.args.input.identifyLabels.key ) -$util.qr($ctx.stash.put(\\"isList\\", true)) -#set( $identifyLabelsPayload = { - \\"version\\": \\"2018-05-29\\", - \\"method\\": \\"POST\\", - \\"resourcePath\\": \\"/\\", - \\"params\\": { - \\"body\\": { - \\"Image\\": { - \\"S3Object\\": { - \\"Bucket\\": \\"$bucketName\\", - \\"Name\\": \\"public/$identifyLabelKey\\" - } - }, - \\"MaxLabels\\": 10, - \\"MinConfidence\\": 55 - }, - \\"headers\\": { - \\"Content-Type\\": \\"application/x-amz-json-1.1\\", - \\"X-Amz-Target\\": \\"RekognitionService.DetectLabels\\" - } - } -} ) -$util.toJson($identifyLabelsPayload)", - "ResponseMappingTemplate": "#if( $ctx.error ) -$util.error($ctx.error.message) -#end -#if( $ctx.result.statusCode == 200 ) - #set( $labels = \\"\\" ) - #set( $result = $util.parseJson($ctx.result.body) ) - #foreach( $label in $result.Labels ) - #set( $labels = \\"$labels$label.Name, \\" ) - #end - $util.toJson($labels.replaceAll(\\", $\\", \\"\\")) -#else -$util.error($ctx.result.body) -#end", - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "identifyTextAccess5A2D7702": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "rekognition:DetectText", - "Effect": "Allow", - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "identifyTextAccess5A2D7702", - "Roles": Array [ - Object { - "Ref": "predictionsIAMRole5BB74A99", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "identifyTextFunctionidentifyTextFunctionAppSyncFunction7877885A": Object { - "DependsOn": Array [ - "RekognitionDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "RekognitionDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "identifyTextFunction", - "RequestMappingTemplate": "#set( $bucketName = $ctx.stash.get(\\"s3Bucket\\") ) -#set( $identityTextKey = $ctx.args.input.identifyText.key ) -#set( $identifyTextPayload = { - \\"version\\": \\"2018-05-29\\", - \\"method\\": \\"POST\\", - \\"resourcePath\\": \\"/\\", - \\"params\\": { - \\"body\\": { - \\"Image\\": { - \\"S3Object\\": { - \\"Bucket\\": \\"$bucketName\\", - \\"Name\\": \\"public/$identityTextKey\\" - } - } - }, - \\"headers\\": { - \\"Content-Type\\": \\"application/x-amz-json-1.1\\", - \\"X-Amz-Target\\": \\"RekognitionService.DetectText\\" - } - } -} ) -$util.toJson($identifyTextPayload)", - "ResponseMappingTemplate": "#if( $ctx.error ) -$util.error($ctx.error.message) -#end -#if( $ctx.result.statusCode == 200 ) - #set( $results = $util.parseJson($ctx.result.body) ) - #set( $finalResult = \\"\\" ) - #foreach( $item in $results.TextDetections ) - #if( $item.Type == \\"LINE\\" ) - #set( $finalResult = \\"$finalResult$item.DetectedText \\" ) - #end - #end -$util.toJson($finalResult.trim()) -#else -$utils.error($ctx.result.body) -#end", - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "predictionsIAMRole5BB74A99": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "RoleName": Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Join": Array [ - "-", - Array [ - "predictionsIAMRole", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - Object { - "Fn::Join": Array [ - "-", - Array [ - "predictionsIAMRole", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - ], - ], - }, - ], - }, - }, - "Type": "AWS::IAM::Role", - }, - "predictionsLambda8B880A74": Object { - "DependsOn": Array [ - "predictionsLambdaIAMRoleB8AC96D3", - ], - "Properties": Object { - "Code": Object { - "S3Bucket": Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "S3Key": Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/functions/predictionsLambdaFunction.zip", - ], - ], - }, - }, - "Handler": "predictionsLambda.handler", - "Role": Object { - "Fn::GetAtt": Array [ - "predictionsLambdaIAMRoleB8AC96D3", - "Arn", - ], - }, - "Runtime": "nodejs18.x", - "Timeout": 60, - }, - "Type": "AWS::Lambda::Function", - }, - "predictionsLambdaIAMRoleB8AC96D3": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "lambda.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "Policies": Array [ - Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "polly:SynthesizeSpeech", - "Effect": "Allow", - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "PollyAccess", - }, - ], - "RoleName": Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Join": Array [ - "-", - Array [ - "predictionsLambdaIAMRole", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - Object { - "Fn::Join": Array [ - "-", - Array [ - "predictionsLambdaIAMRole", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - ], - ], - }, - ], - }, - }, - "Type": "AWS::IAM::Role", - }, - "translateTextAccess74D3AE90": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "translate:TranslateText", - "Effect": "Allow", - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "translateTextAccess74D3AE90", - "Roles": Array [ - Object { - "Ref": "predictionsIAMRole5BB74A99", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "translateTextFunctiontranslateTextFunctionAppSyncFunction77C9D7A9": Object { - "DependsOn": Array [ - "TranslateDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "TranslateDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "translateTextFunction", - "RequestMappingTemplate": "#set( $text = $util.defaultIfNull($ctx.args.input.translateText.text, $ctx.prev.result) ) -#set( $translateTextPayload = { - \\"version\\": \\"2018-05-29\\", - \\"method\\": \\"POST\\", - \\"resourcePath\\": \\"/\\", - \\"params\\": { - \\"body\\": { - \\"SourceLanguageCode\\": $ctx.args.input.translateText.sourceLanguage, - \\"TargetLanguageCode\\": $ctx.args.input.translateText.targetLanguage, - \\"Text\\": $text - }, - \\"headers\\": { - \\"Content-Type\\": \\"application/x-amz-json-1.1\\", - \\"X-Amz-Target\\": \\"AWSShineFrontendService_20170701.TranslateText\\" - } - } -} ) -$util.toJson($translateTextPayload)", - "ResponseMappingTemplate": "#if( $ctx.error ) -$util.error($ctx.error.message) -#end -#if( $ctx.result.statusCode == 200 ) - #set( $result = $util.parseJson($ctx.result.body) ) -$util.toJson($result.TranslatedText) -#else -$util.error($ctx.result.body) -#end", - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - }, - }, -} -`; - -exports[`it skips override if override file does not exist 1`] = ` -Object { - "PredictionsDirectiveStack": Object { - "Conditions": Object { - "HasEnvironmentParameter": Object { - "Fn::Not": Array [ - Object { - "Fn::Equals": Array [ - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - "NONE", - ], - }, - ], - }, - }, - "Parameters": Object { - "referencetotransformerrootstackGraphQLAPI20497F53ApiId": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentBucket7592718ARef": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref": Object { - "Type": "String", - }, - "referencetotransformerrootstackenv10C5A902Ref": Object { - "Type": "String", - }, - }, - "Resources": Object { - "LambdaDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "LambdaConfig": Object { - "LambdaFunctionArn": Object { - "Fn::GetAtt": Array [ - "predictionsLambda8B880A74", - "Arn", - ], - }, - }, - "Name": "LambdaDataSource", - "ServiceRoleArn": Object { - "Fn::GetAtt": Array [ - "predictionsIAMRole5BB74A99", - "Arn", - ], - }, - "Type": "AWS_LAMBDA", - }, - "Type": "AWS::AppSync::DataSource", - }, - "LambdaDataSourceServiceRole81BB3362": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "LambdaDataSourceServiceRoleDefaultPolicy00CC76B1": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "predictionsLambda8B880A74", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "predictionsLambda8B880A74", - "Arn", - ], - }, - ":*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "LambdaDataSourceServiceRoleDefaultPolicy00CC76B1", - "Roles": Array [ - Object { - "Ref": "LambdaDataSourceServiceRole81BB3362", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "PredictionsLambdaAccess4D9DA807": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "predictionsLambda8B880A74", - "Arn", - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "PredictionsLambdaAccess4D9DA807", - "Roles": Array [ - Object { - "Ref": "predictionsIAMRole5BB74A99", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "PredictionsStorageAccess68CD5140": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "s3:GetObject", - "Effect": "Allow", - "Resource": Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "arn:aws:s3:::myStorage\${hash}-\${env}/public/*", - Object { - "env": Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - "hash": Object { - "Fn::Select": Array [ - 3, - Object { - "Fn::Split": Array [ - "-", - Object { - "Ref": "AWS::StackName", - }, - ], - }, - ], - }, - }, - ], - }, - Object { - "Fn::Sub": Array [ - "arn:aws:s3:::myStorage\${hash}/public/*", - Object { - "hash": Object { - "Fn::Select": Array [ - 3, - Object { - "Fn::Split": Array [ - "-", - Object { - "Ref": "AWS::StackName", - }, - ], - }, - ], - }, - }, - ], - }, - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "PredictionsStorageAccess68CD5140", - "Roles": Array [ - Object { - "Ref": "predictionsIAMRole5BB74A99", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "QueryspeakTranslatedIdentifiedTextResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "speakTranslatedIdentifiedText", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "identifyTextFunctionidentifyTextFunctionAppSyncFunction7877885A", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "translateTextFunctiontranslateTextFunctionAppSyncFunction77C9D7A9", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "convertTextToSpeechFunctionconvertTextToSpeechFunctionAppSyncFunction15BC20B8", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - " -", - Array [ - Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "$util.qr($ctx.stash.put(\\"s3Bucket\\", \\"myStorage\${hash}-\${env}\\"))", - Object { - "env": Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - "hash": Object { - "Fn::Select": Array [ - 3, - Object { - "Fn::Split": Array [ - "-", - Object { - "Ref": "AWS::StackName", - }, - ], - }, - ], - }, - }, - ], - }, - Object { - "Fn::Sub": Array [ - "$util.qr($ctx.stash.put(\\"s3Bucket\\", \\"myStorage\${hash}\\"))", - Object { - "hash": Object { - "Fn::Select": Array [ - 3, - Object { - "Fn::Split": Array [ - "-", - Object { - "Ref": "AWS::StackName", - }, - ], - }, - ], - }, - }, - ], - }, - ], - }, - "$util.qr($ctx.stash.put(\\"isList\\", false)) -{}", - ], - ], - }, - "ResponseMappingTemplate": "## If the result is a list return the result as a list ** -#if( $ctx.stash.get(\\"isList\\") ) - #set( $result = $ctx.result.split(\\"[ ,]+\\") ) - $util.toJson($result) -#else - $util.toJson($ctx.result) -#end", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", - }, - "QueryspeakTranslatedLabelTextResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "speakTranslatedLabelText", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "identifyLabelsFunctionidentifyLabelsFunctionAppSyncFunction7C2A1E61", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "translateTextFunctiontranslateTextFunctionAppSyncFunction77C9D7A9", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "convertTextToSpeechFunctionconvertTextToSpeechFunctionAppSyncFunction15BC20B8", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - " -", - Array [ - Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "$util.qr($ctx.stash.put(\\"s3Bucket\\", \\"myStorage\${hash}-\${env}\\"))", - Object { - "env": Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - "hash": Object { - "Fn::Select": Array [ - 3, - Object { - "Fn::Split": Array [ - "-", - Object { - "Ref": "AWS::StackName", - }, - ], - }, - ], - }, - }, - ], - }, - Object { - "Fn::Sub": Array [ - "$util.qr($ctx.stash.put(\\"s3Bucket\\", \\"myStorage\${hash}\\"))", - Object { - "hash": Object { - "Fn::Select": Array [ - 3, - Object { - "Fn::Split": Array [ - "-", - Object { - "Ref": "AWS::StackName", - }, - ], - }, - ], - }, - }, - ], - }, - ], - }, - "$util.qr($ctx.stash.put(\\"isList\\", false)) -{}", - ], - ], - }, - "ResponseMappingTemplate": "## If the result is a list return the result as a list ** -#if( $ctx.stash.get(\\"isList\\") ) - #set( $result = $ctx.result.split(\\"[ ,]+\\") ) - $util.toJson($result) -#else - $util.toJson($ctx.result) -#end", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", - }, - "RekognitionDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "HttpConfig": Object { - "AuthorizationConfig": Object { - "AuthorizationType": "AWS_IAM", - "AwsIamConfig": Object { - "SigningRegion": Object { - "Fn::Sub": "\${AWS::Region}", - }, - "SigningServiceName": "rekognition", - }, - }, - "Endpoint": Object { - "Fn::Sub": "https://rekognition.\${AWS::Region}.amazonaws.com", - }, - }, - "Name": "RekognitionDataSource", - "ServiceRoleArn": Object { - "Fn::GetAtt": Array [ - "predictionsIAMRole5BB74A99", - "Arn", - ], - }, - "Type": "HTTP", - }, - "Type": "AWS::AppSync::DataSource", - }, - "RekognitionDataSourceServiceRole3628B5DB": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "TranslateDataSource": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "HttpConfig": Object { - "AuthorizationConfig": Object { - "AuthorizationType": "AWS_IAM", - "AwsIamConfig": Object { - "SigningRegion": Object { - "Fn::Sub": "\${AWS::Region}", - }, - "SigningServiceName": "translate", - }, - }, - "Endpoint": Object { - "Fn::Sub": "https://translate.\${AWS::Region}.amazonaws.com", - }, - }, - "Name": "TranslateDataSource", - "ServiceRoleArn": Object { - "Fn::GetAtt": Array [ - "predictionsIAMRole5BB74A99", - "Arn", - ], - }, - "Type": "HTTP", - }, - "Type": "AWS::AppSync::DataSource", - }, - "TranslateDataSourceServiceRole2FE48B83": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "convertTextToSpeechFunctionconvertTextToSpeechFunctionAppSyncFunction15BC20B8": Object { - "DependsOn": Array [ - "LambdaDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "LambdaDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "convertTextToSpeechFunction", - "RequestMappingTemplate": "#set( $bucketName = $ctx.stash.get(\\"s3Bucket\\") ) -$util.qr($ctx.stash.put(\\"isList\\", false)) -#set( $text = $util.defaultIfNull($ctx.args.input.convertTextToSpeech.text, $ctx.prev.result) ) -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"Invoke\\", - \\"payload\\": $util.toJson({ - \\"uuid\\": \\"$util.autoId()\\", - \\"action\\": \\"convertTextToSpeech\\", - \\"voiceID\\": $ctx.args.input.convertTextToSpeech.voiceID, - \\"text\\": $text -}) -}", - "ResponseMappingTemplate": "#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type) -#end -#set( $response = $util.parseJson($ctx.result) ) -$util.toJson($ctx.result.url)", - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "identifyLabelsAccess7BFAF94B": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "rekognition:DetectLabels", - "Effect": "Allow", - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "identifyLabelsAccess7BFAF94B", - "Roles": Array [ - Object { - "Ref": "predictionsIAMRole5BB74A99", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "identifyLabelsFunctionidentifyLabelsFunctionAppSyncFunction7C2A1E61": Object { - "DependsOn": Array [ - "RekognitionDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "RekognitionDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "identifyLabelsFunction", - "RequestMappingTemplate": "#set( $bucketName = $ctx.stash.get(\\"s3Bucket\\") ) -#set( $identifyLabelKey = $ctx.args.input.identifyLabels.key ) -$util.qr($ctx.stash.put(\\"isList\\", true)) -#set( $identifyLabelsPayload = { - \\"version\\": \\"2018-05-29\\", - \\"method\\": \\"POST\\", - \\"resourcePath\\": \\"/\\", - \\"params\\": { - \\"body\\": { - \\"Image\\": { - \\"S3Object\\": { - \\"Bucket\\": \\"$bucketName\\", - \\"Name\\": \\"public/$identifyLabelKey\\" - } - }, - \\"MaxLabels\\": 10, - \\"MinConfidence\\": 55 - }, - \\"headers\\": { - \\"Content-Type\\": \\"application/x-amz-json-1.1\\", - \\"X-Amz-Target\\": \\"RekognitionService.DetectLabels\\" - } - } -} ) -$util.toJson($identifyLabelsPayload)", - "ResponseMappingTemplate": "#if( $ctx.error ) -$util.error($ctx.error.message) -#end -#if( $ctx.result.statusCode == 200 ) - #set( $labels = \\"\\" ) - #set( $result = $util.parseJson($ctx.result.body) ) - #foreach( $label in $result.Labels ) - #set( $labels = \\"$labels$label.Name, \\" ) - #end - $util.toJson($labels.replaceAll(\\", $\\", \\"\\")) -#else -$util.error($ctx.result.body) -#end", - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "identifyTextAccess5A2D7702": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "rekognition:DetectText", - "Effect": "Allow", - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "identifyTextAccess5A2D7702", - "Roles": Array [ - Object { - "Ref": "predictionsIAMRole5BB74A99", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "identifyTextFunctionidentifyTextFunctionAppSyncFunction7877885A": Object { - "DependsOn": Array [ - "RekognitionDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "RekognitionDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "identifyTextFunction", - "RequestMappingTemplate": "#set( $bucketName = $ctx.stash.get(\\"s3Bucket\\") ) -#set( $identityTextKey = $ctx.args.input.identifyText.key ) -#set( $identifyTextPayload = { - \\"version\\": \\"2018-05-29\\", - \\"method\\": \\"POST\\", - \\"resourcePath\\": \\"/\\", - \\"params\\": { - \\"body\\": { - \\"Image\\": { - \\"S3Object\\": { - \\"Bucket\\": \\"$bucketName\\", - \\"Name\\": \\"public/$identityTextKey\\" - } - } - }, - \\"headers\\": { - \\"Content-Type\\": \\"application/x-amz-json-1.1\\", - \\"X-Amz-Target\\": \\"RekognitionService.DetectText\\" - } - } -} ) -$util.toJson($identifyTextPayload)", - "ResponseMappingTemplate": "#if( $ctx.error ) -$util.error($ctx.error.message) -#end -#if( $ctx.result.statusCode == 200 ) - #set( $results = $util.parseJson($ctx.result.body) ) - #set( $finalResult = \\"\\" ) - #foreach( $item in $results.TextDetections ) - #if( $item.Type == \\"LINE\\" ) - #set( $finalResult = \\"$finalResult$item.DetectedText \\" ) - #end - #end -$util.toJson($finalResult.trim()) -#else -$utils.error($ctx.result.body) -#end", - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "predictionsIAMRole5BB74A99": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "RoleName": Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Join": Array [ - "-", - Array [ - "predictionsIAMRole", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - Object { - "Fn::Join": Array [ - "-", - Array [ - "predictionsIAMRole", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - ], - ], - }, - ], - }, - }, - "Type": "AWS::IAM::Role", - }, - "predictionsLambda8B880A74": Object { - "DependsOn": Array [ - "predictionsLambdaIAMRoleB8AC96D3", - ], - "Properties": Object { - "Code": Object { - "S3Bucket": Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "S3Key": Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/functions/predictionsLambdaFunction.zip", - ], - ], - }, - }, - "Handler": "predictionsLambda.handler", - "Role": Object { - "Fn::GetAtt": Array [ - "predictionsLambdaIAMRoleB8AC96D3", - "Arn", - ], - }, - "Runtime": "nodejs18.x", - "Timeout": 60, - }, - "Type": "AWS::Lambda::Function", - }, - "predictionsLambdaIAMRoleB8AC96D3": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "lambda.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "Policies": Array [ - Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "polly:SynthesizeSpeech", - "Effect": "Allow", - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "PollyAccess", - }, - ], - "RoleName": Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Join": Array [ - "-", - Array [ - "predictionsLambdaIAMRole", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - Object { - "Fn::Join": Array [ - "-", - Array [ - "predictionsLambdaIAMRole", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - ], - ], - }, - ], - }, - }, - "Type": "AWS::IAM::Role", - }, - "translateTextAccess74D3AE90": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "translate:TranslateText", - "Effect": "Allow", - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "translateTextAccess74D3AE90", - "Roles": Array [ - Object { - "Ref": "predictionsIAMRole5BB74A99", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "translateTextFunctiontranslateTextFunctionAppSyncFunction77C9D7A9": Object { - "DependsOn": Array [ - "TranslateDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "TranslateDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "translateTextFunction", - "RequestMappingTemplate": "#set( $text = $util.defaultIfNull($ctx.args.input.translateText.text, $ctx.prev.result) ) -#set( $translateTextPayload = { - \\"version\\": \\"2018-05-29\\", - \\"method\\": \\"POST\\", - \\"resourcePath\\": \\"/\\", - \\"params\\": { - \\"body\\": { - \\"SourceLanguageCode\\": $ctx.args.input.translateText.sourceLanguage, - \\"TargetLanguageCode\\": $ctx.args.input.translateText.targetLanguage, - \\"Text\\": $text - }, - \\"headers\\": { - \\"Content-Type\\": \\"application/x-amz-json-1.1\\", - \\"X-Amz-Target\\": \\"AWSShineFrontendService_20170701.TranslateText\\" - } - } -} ) -$util.toJson($translateTextPayload)", - "ResponseMappingTemplate": "#if( $ctx.error ) -$util.error($ctx.error.message) -#end -#if( $ctx.result.statusCode == 200 ) - #set( $result = $util.parseJson($ctx.result.body) ) -$util.toJson($result.TranslatedText) -#else -$util.error($ctx.result.body) -#end", - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - }, - }, -} -`; diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-primary-key-transformer-override.test.ts.snap b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-primary-key-transformer-override.test.ts.snap deleted file mode 100644 index c1e777f008..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/amplify-graphql-primary-key-transformer-override.test.ts.snap +++ /dev/null @@ -1,427 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`it overrides expected resources 1`] = ` -Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "createTest", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "MutationcreateTestinit0FunctionMutationcreateTestinit0FunctionAppSyncFunction82753130", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "MutationcreateTestpreAuth0FunctionMutationcreateTestpreAuth0FunctionAppSyncFunctionC0EB74A1", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QuerygetTestpostAuth0FunctionQuerygetTestpostAuth0FunctionAppSyncFunctionE9BFAF7A", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "MutationCreateTestDataResolverFnMutationCreateTestDataResolverFnAppSyncFunction005BA3A1", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"createTest\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "TestTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"deltaSyncTableTtl\\", 25)) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", -} -`; - -exports[`it overrides expected resources 2`] = ` -Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "getTest", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerygetTestpreAuth0FunctionQuerygetTestpreAuth0FunctionAppSyncFunction7DE868FF", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QuerygetTestpostAuth0FunctionQuerygetTestpostAuth0FunctionAppSyncFunctionE9BFAF7A", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QueryGetTestDataResolverFnQueryGetTestDataResolverFnAppSyncFunctionCB6458E5", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Query\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"getTest\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "TestTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"deltaSyncTableTtl\\", 25)) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", -} -`; - -exports[`it overrides expected resources 3`] = ` -Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "listTests", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerylistTestspreAuth0FunctionQuerylistTestspreAuth0FunctionAppSyncFunction3CA4A90C", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QuerygetTestpostAuth0FunctionQuerygetTestpostAuth0FunctionAppSyncFunctionE9BFAF7A", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QueryListTestsDataResolverFnQueryListTestsDataResolverFnAppSyncFunction177A117F", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Query\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"listTests\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "TestTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"deltaSyncTableTtl\\", 25)) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", -} -`; - -exports[`it overrides expected resources 4`] = ` -Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "deleteTest", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "MutationdeleteTestpreAuth0FunctionMutationdeleteTestpreAuth0FunctionAppSyncFunctionC68C5724", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QuerygetTestpostAuth0FunctionQuerygetTestpostAuth0FunctionAppSyncFunctionE9BFAF7A", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "MutationDeleteTestDataResolverFnMutationDeleteTestDataResolverFnAppSyncFunction9230CF9A", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"deleteTest\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "TestTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"deltaSyncTableTtl\\", 25)) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", -} -`; - -exports[`it overrides expected resources 5`] = ` -Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "updateTest", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "MutationupdateTestinit0FunctionMutationupdateTestinit0FunctionAppSyncFunctionC2375285", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "MutationcreateTestpreAuth0FunctionMutationcreateTestpreAuth0FunctionAppSyncFunctionC0EB74A1", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QuerygetTestpostAuth0FunctionQuerygetTestpostAuth0FunctionAppSyncFunctionE9BFAF7A", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "MutationUpdateTestDataResolverFnMutationUpdateTestDataResolverFnAppSyncFunction161162F8", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"updateTest\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "TestTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"deltaSyncTableTtl\\", 25)) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", -} -`; - -exports[`it overrides expected resources 6`] = ` -Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "syncTests", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerysyncTestspreAuth0FunctionQuerysyncTestspreAuth0FunctionAppSyncFunction6F326BAB", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QuerygetTestpostAuth0FunctionQuerygetTestpostAuth0FunctionAppSyncFunctionE9BFAF7A", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QuerySyncTestsDataResolverFnQuerySyncTestsDataResolverFnAppSyncFunction95B4DA0E", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Query\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"syncTests\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "TestTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"deltaSyncTableTtl\\", 25)) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", -} -`; - -exports[`it overrides expected resources 7`] = ` -Object { - "DependsOn": Array [ - "TestIAMRoleB964910C", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DynamoDBConfig": Object { - "AwsRegion": Object { - "Ref": "AWS::Region", - }, - "DeltaSyncConfig": Object { - "BaseTableTTL": "20", - "DeltaSyncTableName": "TestTable", - "DeltaSyncTableTTL": "25", - }, - "TableName": Object { - "Ref": "TestTable", - }, - "Versioned": true, - }, - "Name": "TestTable", - "ServiceRoleArn": Object { - "Fn::GetAtt": Array [ - "TestIAMRoleB964910C", - "Arn", - ], - }, - "Type": "AMAZON_DYNAMODB", - }, - "Type": "AWS::AppSync::DataSource", -} -`; diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/model-transformer-override.test.ts.snap b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/model-transformer-override.test.ts.snap deleted file mode 100644 index 853fb0e4a9..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/__snapshots__/model-transformer-override.test.ts.snap +++ /dev/null @@ -1,4467 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ModelTransformer: should not override model objects when override file does not exist 1`] = ` -Object { - "Conditions": Object { - "HasEnvironmentParameter": Object { - "Fn::Not": Array [ - Object { - "Fn::Equals": Array [ - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - "NONE", - ], - }, - ], - }, - "ShouldUsePayPerRequestBilling": Object { - "Fn::Equals": Array [ - Object { - "Ref": "DynamoDBBillingMode", - }, - "PAY_PER_REQUEST", - ], - }, - "ShouldUsePointInTimeRecovery": Object { - "Fn::Equals": Array [ - Object { - "Ref": "DynamoDBEnablePointInTimeRecovery", - }, - "true", - ], - }, - "ShouldUseServerSideEncryption": Object { - "Fn::Equals": Array [ - Object { - "Ref": "DynamoDBEnableServerSideEncryption", - }, - "true", - ], - }, - }, - "Outputs": Object { - "GetAttPostDataSourceName": Object { - "Description": "Your model DataSource name.", - "Export": Object { - "Name": Object { - "Fn::Join": Array [ - ":", - Array [ - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "GetAtt:PostDataSource:Name", - ], - ], - }, - }, - "Value": Object { - "Fn::GetAtt": Array [ - "PostDataSource", - "Name", - ], - }, - }, - "GetAttPostTableName": Object { - "Description": "Your DynamoDB table name.", - "Export": Object { - "Name": Object { - "Fn::Join": Array [ - ":", - Array [ - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "GetAtt:PostTable:Name", - ], - ], - }, - }, - "Value": Object { - "Ref": "PostTable", - }, - }, - "GetAttPostTableStreamArn": Object { - "Description": "Your DynamoDB table StreamArn.", - "Export": Object { - "Name": Object { - "Fn::Join": Array [ - ":", - Array [ - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "GetAtt:PostTable:StreamArn", - ], - ], - }, - }, - "Value": Object { - "Fn::GetAtt": Array [ - "PostTable", - "StreamArn", - ], - }, - }, - "transformerrootstackPostMutationcreatePostinit0FunctionMutationcreatePostinit0FunctionAppSyncFunctionB82DB57BFunctionId": Object { - "Value": Object { - "Fn::GetAtt": Array [ - "MutationcreatePostinit0FunctionMutationcreatePostinit0FunctionAppSyncFunction9E444A7F", - "FunctionId", - ], - }, - }, - "transformerrootstackPostMutationupdatePostinit0FunctionMutationupdatePostinit0FunctionAppSyncFunction148F70DDFunctionId": Object { - "Value": Object { - "Fn::GetAtt": Array [ - "MutationupdatePostinit0FunctionMutationupdatePostinit0FunctionAppSyncFunctionBAC7D532", - "FunctionId", - ], - }, - }, - "transformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId": Object { - "Value": Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - }, - "transformerrootstackPostSubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionAE3ECF1FFunctionId": Object { - "Value": Object { - "Fn::GetAtt": Array [ - "SubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionB4572868", - "FunctionId", - ], - }, - }, - }, - "Parameters": Object { - "DynamoDBBillingMode": Object { - "AllowedValues": Array [ - "PAY_PER_REQUEST", - "PROVISIONED", - ], - "Default": "PAY_PER_REQUEST", - "Description": "Configure @model types to create DynamoDB tables with PAY_PER_REQUEST or PROVISIONED billing modes.", - "Type": "String", - }, - "DynamoDBEnablePointInTimeRecovery": Object { - "AllowedValues": Array [ - "true", - "false", - ], - "Default": "false", - "Description": "Whether to enable Point in Time Recovery on the table.", - "Type": "String", - }, - "DynamoDBEnableServerSideEncryption": Object { - "AllowedValues": Array [ - "true", - "false", - ], - "Default": "true", - "Description": "Enable server side encryption powered by KMS.", - "Type": "String", - }, - "DynamoDBModelTableReadIOPS": Object { - "Default": 5, - "Description": "The number of read IOPS the table should support.", - "Type": "Number", - }, - "DynamoDBModelTableWriteIOPS": Object { - "Default": 5, - "Description": "The number of write IOPS the table should support.", - "Type": "Number", - }, - "referencetotransformerrootstackGraphQLAPI20497F53ApiId": Object { - "Type": "String", - }, - "referencetotransformerrootstackGraphQLAPINONEDS2BA9D1C8Name": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentBucket7592718ARef": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref": Object { - "Type": "String", - }, - "referencetotransformerrootstackenv10C5A902Ref": Object { - "Type": "String", - }, - }, - "Resources": Object { - "CreatePostResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "createPost", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "MutationcreatePostinit0FunctionMutationcreatePostinit0FunctionAppSyncFunction9E444A7F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "MutationCreatePostDataResolverFnMutationCreatePostDataResolverFnAppSyncFunctionE45E2000", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"createPost\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "PostTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", - }, - "DeletePostResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "deletePost", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "MutationDeletePostDataResolverFnMutationDeletePostDataResolverFnAppSyncFunction45B37C12", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"deletePost\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "PostTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", - }, - "GetPostResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "getPost", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QueryGetPostDataResolverFnQueryGetPostDataResolverFnAppSyncFunction06724190", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Query\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"getPost\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "PostTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", - }, - "ListPostResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "listPosts", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QueryListPostsDataResolverFnQueryListPostsDataResolverFnAppSyncFunction3D526AB7", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Query\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"listPosts\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "PostTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", - }, - "MutationCreatePostDataResolverFnMutationCreatePostDataResolverFnAppSyncFunctionE45E2000": Object { - "DependsOn": Array [ - "PostDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "PostDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "MutationCreatePostDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.createPost.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.createPost.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "MutationDeletePostDataResolverFnMutationDeletePostDataResolverFnAppSyncFunction45B37C12": Object { - "DependsOn": Array [ - "PostDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "PostDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "MutationDeletePostDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.deletePost.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.deletePost.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "MutationUpdatePostDataResolverFnMutationUpdatePostDataResolverFnAppSyncFunctionBF7D410D": Object { - "DependsOn": Array [ - "PostDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "PostDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "MutationUpdatePostDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.updatePost.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.updatePost.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "MutationcreatePostinit0FunctionMutationcreatePostinit0FunctionAppSyncFunction9E444A7F": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Ref": "referencetotransformerrootstackGraphQLAPINONEDS2BA9D1C8Name", - }, - "FunctionVersion": "2018-05-29", - "Name": "MutationcreatePostinit0Function", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.createPost.init.1.req.vtl", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson({})", - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "MutationupdatePostinit0FunctionMutationupdatePostinit0FunctionAppSyncFunctionBAC7D532": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Ref": "referencetotransformerrootstackGraphQLAPINONEDS2BA9D1C8Name", - }, - "FunctionVersion": "2018-05-29", - "Name": "MutationupdatePostinit0Function", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.updatePost.init.1.req.vtl", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson({})", - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "PostDataSource": Object { - "DependsOn": Array [ - "PostIAMRole83BF708F", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DynamoDBConfig": Object { - "AwsRegion": Object { - "Ref": "AWS::Region", - }, - "TableName": Object { - "Ref": "PostTable", - }, - }, - "Name": "PostTable", - "ServiceRoleArn": Object { - "Fn::GetAtt": Array [ - "PostIAMRole83BF708F", - "Arn", - ], - }, - "Type": "AMAZON_DYNAMODB", - }, - "Type": "AWS::AppSync::DataSource", - }, - "PostIAMRole83BF708F": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "Policies": Array [ - Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "dynamodb:BatchGetItem", - "dynamodb:BatchWriteItem", - "dynamodb:PutItem", - "dynamodb:DeleteItem", - "dynamodb:GetItem", - "dynamodb:Scan", - "dynamodb:Query", - "dynamodb:UpdateItem", - "dynamodb:ConditionCheckItem", - "dynamodb:DescribeTable", - "dynamodb:GetRecords", - "dynamodb:GetShardIterator", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::Sub": Array [ - "arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/\${tablename}", - Object { - "tablename": Object { - "Fn::Join": Array [ - "", - Array [ - "Post-", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "-", - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - }, - ], - }, - Object { - "Fn::Sub": Array [ - "arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/\${tablename}/*", - Object { - "tablename": Object { - "Fn::Join": Array [ - "", - Array [ - "Post-", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "-", - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - }, - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "DynamoDBAccess", - }, - ], - "RoleName": Object { - "Fn::Join": Array [ - "", - Array [ - "PostIAMRolebbce9b-", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "-", - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - }, - "Type": "AWS::IAM::Role", - }, - "PostTable": Object { - "DeletionPolicy": "Delete", - "Properties": Object { - "AttributeDefinitions": Array [ - Object { - "AttributeName": "id", - "AttributeType": "S", - }, - ], - "BillingMode": Object { - "Fn::If": Array [ - "ShouldUsePayPerRequestBilling", - "PAY_PER_REQUEST", - Object { - "Ref": "AWS::NoValue", - }, - ], - }, - "KeySchema": Array [ - Object { - "AttributeName": "id", - "KeyType": "HASH", - }, - ], - "PointInTimeRecoverySpecification": Object { - "Fn::If": Array [ - "ShouldUsePointInTimeRecovery", - Object { - "PointInTimeRecoveryEnabled": true, - }, - Object { - "Ref": "AWS::NoValue", - }, - ], - }, - "ProvisionedThroughput": Object { - "Fn::If": Array [ - "ShouldUsePayPerRequestBilling", - Object { - "Ref": "AWS::NoValue", - }, - Object { - "ReadCapacityUnits": Object { - "Ref": "DynamoDBModelTableReadIOPS", - }, - "WriteCapacityUnits": Object { - "Ref": "DynamoDBModelTableWriteIOPS", - }, - }, - ], - }, - "SSESpecification": Object { - "SSEEnabled": Object { - "Fn::If": Array [ - "ShouldUseServerSideEncryption", - true, - false, - ], - }, - }, - "StreamSpecification": Object { - "StreamViewType": "NEW_AND_OLD_IMAGES", - }, - "TableName": Object { - "Fn::Join": Array [ - "", - Array [ - "Post-", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "-", - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - }, - "Type": "AWS::DynamoDB::Table", - "UpdateReplacePolicy": "Delete", - }, - "QueryGetPostDataResolverFnQueryGetPostDataResolverFnAppSyncFunction06724190": Object { - "DependsOn": Array [ - "PostDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "PostDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "QueryGetPostDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.getPost.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.getPost.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "QueryListPostsDataResolverFnQueryListPostsDataResolverFnAppSyncFunction3D526AB7": Object { - "DependsOn": Array [ - "PostDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "PostDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "QueryListPostsDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.listPosts.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.listPosts.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Ref": "referencetotransformerrootstackGraphQLAPINONEDS2BA9D1C8Name", - }, - "FunctionVersion": "2018-05-29", - "Name": "QuerygetPostpostAuth0Function", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.getPost.postAuth.1.req.vtl", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson({})", - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "SubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionB4572868": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Ref": "referencetotransformerrootstackGraphQLAPINONEDS2BA9D1C8Name", - }, - "FunctionVersion": "2018-05-29", - "Name": "SubscriptionOnCreatePostDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Subscription.onCreatePost.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Subscription.onCreatePost.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "SubscriptiononCreatePostResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "onCreatePost", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "SubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionB4572868", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Subscription\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"onCreatePost\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"NONE\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) - -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Subscription", - }, - "Type": "AWS::AppSync::Resolver", - }, - "SubscriptiononDeletePostResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "onDeletePost", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "SubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionB4572868", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Subscription\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"onDeletePost\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"NONE\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) - -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Subscription", - }, - "Type": "AWS::AppSync::Resolver", - }, - "SubscriptiononUpdatePostResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "onUpdatePost", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "SubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionB4572868", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Subscription\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"onUpdatePost\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"NONE\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) - -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Subscription", - }, - "Type": "AWS::AppSync::Resolver", - }, - "UpdatePostResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "updatePost", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "MutationupdatePostinit0FunctionMutationupdatePostinit0FunctionAppSyncFunctionBAC7D532", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "MutationUpdatePostDataResolverFnMutationUpdatePostDataResolverFnAppSyncFunctionBF7D410D", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"updatePost\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "PostTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", - }, - }, -} -`; - -exports[`ModelTransformer: should not override model objects when override file does not exist 2`] = ` -Object { - "Conditions": Object { - "HasEnvironmentParameter": Object { - "Fn::Not": Array [ - Object { - "Fn::Equals": Array [ - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - "NONE", - ], - }, - ], - }, - "ShouldUsePayPerRequestBilling": Object { - "Fn::Equals": Array [ - Object { - "Ref": "DynamoDBBillingMode", - }, - "PAY_PER_REQUEST", - ], - }, - "ShouldUsePointInTimeRecovery": Object { - "Fn::Equals": Array [ - Object { - "Ref": "DynamoDBEnablePointInTimeRecovery", - }, - "true", - ], - }, - "ShouldUseServerSideEncryption": Object { - "Fn::Equals": Array [ - Object { - "Ref": "DynamoDBEnableServerSideEncryption", - }, - "true", - ], - }, - }, - "Outputs": Object { - "GetAttCommentDataSourceName": Object { - "Description": "Your model DataSource name.", - "Export": Object { - "Name": Object { - "Fn::Join": Array [ - ":", - Array [ - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "GetAtt:CommentDataSource:Name", - ], - ], - }, - }, - "Value": Object { - "Fn::GetAtt": Array [ - "CommentDataSource", - "Name", - ], - }, - }, - "GetAttCommentTableName": Object { - "Description": "Your DynamoDB table name.", - "Export": Object { - "Name": Object { - "Fn::Join": Array [ - ":", - Array [ - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "GetAtt:CommentTable:Name", - ], - ], - }, - }, - "Value": Object { - "Ref": "CommentTable", - }, - }, - "GetAttCommentTableStreamArn": Object { - "Description": "Your DynamoDB table StreamArn.", - "Export": Object { - "Name": Object { - "Fn::Join": Array [ - ":", - Array [ - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "GetAtt:CommentTable:StreamArn", - ], - ], - }, - }, - "Value": Object { - "Fn::GetAtt": Array [ - "CommentTable", - "StreamArn", - ], - }, - }, - }, - "Parameters": Object { - "DynamoDBBillingMode": Object { - "AllowedValues": Array [ - "PAY_PER_REQUEST", - "PROVISIONED", - ], - "Default": "PAY_PER_REQUEST", - "Description": "Configure @model types to create DynamoDB tables with PAY_PER_REQUEST or PROVISIONED billing modes.", - "Type": "String", - }, - "DynamoDBEnablePointInTimeRecovery": Object { - "AllowedValues": Array [ - "true", - "false", - ], - "Default": "false", - "Description": "Whether to enable Point in Time Recovery on the table.", - "Type": "String", - }, - "DynamoDBEnableServerSideEncryption": Object { - "AllowedValues": Array [ - "true", - "false", - ], - "Default": "true", - "Description": "Enable server side encryption powered by KMS.", - "Type": "String", - }, - "DynamoDBModelTableReadIOPS": Object { - "Default": 5, - "Description": "The number of read IOPS the table should support.", - "Type": "Number", - }, - "DynamoDBModelTableWriteIOPS": Object { - "Default": 5, - "Description": "The number of write IOPS the table should support.", - "Type": "Number", - }, - "referencetotransformerrootstackGraphQLAPI20497F53ApiId": Object { - "Type": "String", - }, - "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostMutationcreatePostinit0FunctionMutationcreatePostinit0FunctionAppSyncFunctionB82DB57BFunctionId": Object { - "Type": "String", - }, - "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostMutationupdatePostinit0FunctionMutationupdatePostinit0FunctionAppSyncFunction148F70DDFunctionId": Object { - "Type": "String", - }, - "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId": Object { - "Type": "String", - }, - "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostSubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionAE3ECF1FFunctionId": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentBucket7592718ARef": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref": Object { - "Type": "String", - }, - "referencetotransformerrootstackenv10C5A902Ref": Object { - "Type": "String", - }, - }, - "Resources": Object { - "CommentDataSource": Object { - "DependsOn": Array [ - "CommentIAMRoleD5EC5F51", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DynamoDBConfig": Object { - "AwsRegion": Object { - "Ref": "AWS::Region", - }, - "TableName": Object { - "Ref": "CommentTable", - }, - }, - "Name": "CommentTable", - "ServiceRoleArn": Object { - "Fn::GetAtt": Array [ - "CommentIAMRoleD5EC5F51", - "Arn", - ], - }, - "Type": "AMAZON_DYNAMODB", - }, - "Type": "AWS::AppSync::DataSource", - }, - "CommentIAMRoleD5EC5F51": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "Policies": Array [ - Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "dynamodb:BatchGetItem", - "dynamodb:BatchWriteItem", - "dynamodb:PutItem", - "dynamodb:DeleteItem", - "dynamodb:GetItem", - "dynamodb:Scan", - "dynamodb:Query", - "dynamodb:UpdateItem", - "dynamodb:ConditionCheckItem", - "dynamodb:DescribeTable", - "dynamodb:GetRecords", - "dynamodb:GetShardIterator", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::Sub": Array [ - "arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/\${tablename}", - Object { - "tablename": Object { - "Fn::Join": Array [ - "", - Array [ - "Comment-", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "-", - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - }, - ], - }, - Object { - "Fn::Sub": Array [ - "arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/\${tablename}/*", - Object { - "tablename": Object { - "Fn::Join": Array [ - "", - Array [ - "Comment-", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "-", - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - }, - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "DynamoDBAccess", - }, - ], - "RoleName": Object { - "Fn::Join": Array [ - "", - Array [ - "CommentIAMRole20388d-", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "-", - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - }, - "Type": "AWS::IAM::Role", - }, - "CommentTable": Object { - "DeletionPolicy": "Delete", - "Properties": Object { - "AttributeDefinitions": Array [ - Object { - "AttributeName": "id", - "AttributeType": "S", - }, - ], - "BillingMode": Object { - "Fn::If": Array [ - "ShouldUsePayPerRequestBilling", - "PAY_PER_REQUEST", - Object { - "Ref": "AWS::NoValue", - }, - ], - }, - "KeySchema": Array [ - Object { - "AttributeName": "id", - "KeyType": "HASH", - }, - ], - "PointInTimeRecoverySpecification": Object { - "Fn::If": Array [ - "ShouldUsePointInTimeRecovery", - Object { - "PointInTimeRecoveryEnabled": true, - }, - Object { - "Ref": "AWS::NoValue", - }, - ], - }, - "ProvisionedThroughput": Object { - "Fn::If": Array [ - "ShouldUsePayPerRequestBilling", - Object { - "Ref": "AWS::NoValue", - }, - Object { - "ReadCapacityUnits": Object { - "Ref": "DynamoDBModelTableReadIOPS", - }, - "WriteCapacityUnits": Object { - "Ref": "DynamoDBModelTableWriteIOPS", - }, - }, - ], - }, - "SSESpecification": Object { - "SSEEnabled": Object { - "Fn::If": Array [ - "ShouldUseServerSideEncryption", - true, - false, - ], - }, - }, - "StreamSpecification": Object { - "StreamViewType": "NEW_AND_OLD_IMAGES", - }, - "TableName": Object { - "Fn::Join": Array [ - "", - Array [ - "Comment-", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "-", - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - }, - "Type": "AWS::DynamoDB::Table", - "UpdateReplacePolicy": "Delete", - }, - "CreateCommentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "createComment", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostMutationcreatePostinit0FunctionMutationcreatePostinit0FunctionAppSyncFunctionB82DB57BFunctionId", - }, - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId", - }, - Object { - "Fn::GetAtt": Array [ - "MutationCreateCommentDataResolverFnMutationCreateCommentDataResolverFnAppSyncFunctionD019FFE0", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"createComment\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "CommentTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", - }, - "DeleteCommentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "deleteComment", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId", - }, - Object { - "Fn::GetAtt": Array [ - "MutationDeleteCommentDataResolverFnMutationDeleteCommentDataResolverFnAppSyncFunctionD661C8CB", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"deleteComment\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "CommentTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", - }, - "GetCommentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "getComment", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId", - }, - Object { - "Fn::GetAtt": Array [ - "QueryGetCommentDataResolverFnQueryGetCommentDataResolverFnAppSyncFunction8473E2B0", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Query\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"getComment\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "CommentTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", - }, - "ListCommentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "listComments", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId", - }, - Object { - "Fn::GetAtt": Array [ - "QueryListCommentsDataResolverFnQueryListCommentsDataResolverFnAppSyncFunction474D4A91", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Query\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"listComments\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "CommentTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", - }, - "MutationCreateCommentDataResolverFnMutationCreateCommentDataResolverFnAppSyncFunctionD019FFE0": Object { - "DependsOn": Array [ - "CommentDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "CommentDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "MutationCreateCommentDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.createComment.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.createComment.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "MutationDeleteCommentDataResolverFnMutationDeleteCommentDataResolverFnAppSyncFunctionD661C8CB": Object { - "DependsOn": Array [ - "CommentDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "CommentDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "MutationDeleteCommentDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.deleteComment.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.deleteComment.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "MutationUpdateCommentDataResolverFnMutationUpdateCommentDataResolverFnAppSyncFunctionB47372B5": Object { - "DependsOn": Array [ - "CommentDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "CommentDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "MutationUpdateCommentDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.updateComment.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.updateComment.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "QueryGetCommentDataResolverFnQueryGetCommentDataResolverFnAppSyncFunction8473E2B0": Object { - "DependsOn": Array [ - "CommentDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "CommentDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "QueryGetCommentDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.getComment.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.getComment.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "QueryListCommentsDataResolverFnQueryListCommentsDataResolverFnAppSyncFunction474D4A91": Object { - "DependsOn": Array [ - "CommentDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "CommentDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "QueryListCommentsDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.listComments.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.listComments.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "SubscriptiononCreateCommentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "onCreateComment", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId", - }, - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostSubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionAE3ECF1FFunctionId", - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Subscription\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"onCreateComment\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"NONE\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) - -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Subscription", - }, - "Type": "AWS::AppSync::Resolver", - }, - "SubscriptiononDeleteCommentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "onDeleteComment", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId", - }, - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostSubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionAE3ECF1FFunctionId", - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Subscription\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"onDeleteComment\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"NONE\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) - -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Subscription", - }, - "Type": "AWS::AppSync::Resolver", - }, - "SubscriptiononUpdateCommentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "onUpdateComment", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId", - }, - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostSubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionAE3ECF1FFunctionId", - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Subscription\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"onUpdateComment\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"NONE\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) - -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Subscription", - }, - "Type": "AWS::AppSync::Resolver", - }, - "UpdateCommentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "updateComment", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostMutationupdatePostinit0FunctionMutationupdatePostinit0FunctionAppSyncFunction148F70DDFunctionId", - }, - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId", - }, - Object { - "Fn::GetAtt": Array [ - "MutationUpdateCommentDataResolverFnMutationUpdateCommentDataResolverFnAppSyncFunctionB47372B5", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"updateComment\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "CommentTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", - }, - }, -} -`; - -exports[`ModelTransformer: should override model objects when given override config 1`] = ` -Object { - "Conditions": Object { - "HasEnvironmentParameter": Object { - "Fn::Not": Array [ - Object { - "Fn::Equals": Array [ - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - "NONE", - ], - }, - ], - }, - "ShouldUsePayPerRequestBilling": Object { - "Fn::Equals": Array [ - Object { - "Ref": "DynamoDBBillingMode", - }, - "PAY_PER_REQUEST", - ], - }, - "ShouldUsePointInTimeRecovery": Object { - "Fn::Equals": Array [ - Object { - "Ref": "DynamoDBEnablePointInTimeRecovery", - }, - "true", - ], - }, - "ShouldUseServerSideEncryption": Object { - "Fn::Equals": Array [ - Object { - "Ref": "DynamoDBEnableServerSideEncryption", - }, - "true", - ], - }, - }, - "Outputs": Object { - "GetAttPostDataSourceName": Object { - "Description": "Your model DataSource name.", - "Export": Object { - "Name": Object { - "Fn::Join": Array [ - ":", - Array [ - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "GetAtt:PostDataSource:Name", - ], - ], - }, - }, - "Value": Object { - "Fn::GetAtt": Array [ - "PostDataSource", - "Name", - ], - }, - }, - "GetAttPostTableName": Object { - "Description": "Your DynamoDB table name.", - "Export": Object { - "Name": Object { - "Fn::Join": Array [ - ":", - Array [ - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "GetAtt:PostTable:Name", - ], - ], - }, - }, - "Value": Object { - "Ref": "PostTable", - }, - }, - "GetAttPostTableStreamArn": Object { - "Description": "Your DynamoDB table StreamArn.", - "Export": Object { - "Name": Object { - "Fn::Join": Array [ - ":", - Array [ - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "GetAtt:PostTable:StreamArn", - ], - ], - }, - }, - "Value": Object { - "Fn::GetAtt": Array [ - "PostTable", - "StreamArn", - ], - }, - }, - "transformerrootstackPostMutationcreatePostinit0FunctionMutationcreatePostinit0FunctionAppSyncFunctionB82DB57BFunctionId": Object { - "Value": Object { - "Fn::GetAtt": Array [ - "MutationcreatePostinit0FunctionMutationcreatePostinit0FunctionAppSyncFunction9E444A7F", - "FunctionId", - ], - }, - }, - "transformerrootstackPostMutationupdatePostinit0FunctionMutationupdatePostinit0FunctionAppSyncFunction148F70DDFunctionId": Object { - "Value": Object { - "Fn::GetAtt": Array [ - "MutationupdatePostinit0FunctionMutationupdatePostinit0FunctionAppSyncFunctionBAC7D532", - "FunctionId", - ], - }, - }, - "transformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId": Object { - "Value": Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - }, - "transformerrootstackPostSubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionAE3ECF1FFunctionId": Object { - "Value": Object { - "Fn::GetAtt": Array [ - "SubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionB4572868", - "FunctionId", - ], - }, - }, - }, - "Parameters": Object { - "DynamoDBBillingMode": Object { - "AllowedValues": Array [ - "PAY_PER_REQUEST", - "PROVISIONED", - ], - "Default": "PAY_PER_REQUEST", - "Description": "Configure @model types to create DynamoDB tables with PAY_PER_REQUEST or PROVISIONED billing modes.", - "Type": "String", - }, - "DynamoDBEnablePointInTimeRecovery": Object { - "AllowedValues": Array [ - "true", - "false", - ], - "Default": "false", - "Description": "Whether to enable Point in Time Recovery on the table.", - "Type": "String", - }, - "DynamoDBEnableServerSideEncryption": Object { - "AllowedValues": Array [ - "true", - "false", - ], - "Default": "true", - "Description": "Enable server side encryption powered by KMS.", - "Type": "String", - }, - "DynamoDBModelTableReadIOPS": Object { - "Default": 5, - "Description": "The number of read IOPS the table should support.", - "Type": "Number", - }, - "DynamoDBModelTableWriteIOPS": Object { - "Default": 5, - "Description": "The number of write IOPS the table should support.", - "Type": "Number", - }, - "referencetotransformerrootstackGraphQLAPI20497F53ApiId": Object { - "Type": "String", - }, - "referencetotransformerrootstackGraphQLAPINONEDS2BA9D1C8Name": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentBucket7592718ARef": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref": Object { - "Type": "String", - }, - "referencetotransformerrootstackenv10C5A902Ref": Object { - "Type": "String", - }, - }, - "Resources": Object { - "CreatePostResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "createPost", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "MutationcreatePostinit0FunctionMutationcreatePostinit0FunctionAppSyncFunction9E444A7F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "MutationCreatePostDataResolverFnMutationCreatePostDataResolverFnAppSyncFunctionE45E2000", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"createPost\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "PostTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", - }, - "DeletePostResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "deletePost", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "MutationDeletePostDataResolverFnMutationDeletePostDataResolverFnAppSyncFunction45B37C12", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"deletePost\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "PostTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", - }, - "GetPostResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "getPost", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QueryGetPostDataResolverFnQueryGetPostDataResolverFnAppSyncFunction06724190", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Query\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"getPost\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "PostTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", - }, - "ListPostResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "listPosts", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QueryListPostsDataResolverFnQueryListPostsDataResolverFnAppSyncFunction3D526AB7", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Query\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"listPosts\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "PostTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", - }, - "MutationCreatePostDataResolverFnMutationCreatePostDataResolverFnAppSyncFunctionE45E2000": Object { - "DependsOn": Array [ - "PostDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "PostDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "MutationCreatePostDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.createPost.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.createPost.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "MutationDeletePostDataResolverFnMutationDeletePostDataResolverFnAppSyncFunction45B37C12": Object { - "DependsOn": Array [ - "PostDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "PostDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "MutationDeletePostDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.deletePost.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.deletePost.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "MutationUpdatePostDataResolverFnMutationUpdatePostDataResolverFnAppSyncFunctionBF7D410D": Object { - "DependsOn": Array [ - "PostDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "PostDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "MutationUpdatePostDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.updatePost.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.updatePost.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "MutationcreatePostinit0FunctionMutationcreatePostinit0FunctionAppSyncFunction9E444A7F": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Ref": "referencetotransformerrootstackGraphQLAPINONEDS2BA9D1C8Name", - }, - "FunctionVersion": "2018-05-29", - "Name": "MutationcreatePostinit0Function", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.createPost.init.1.req.vtl", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson({})", - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "MutationupdatePostinit0FunctionMutationupdatePostinit0FunctionAppSyncFunctionBAC7D532": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Ref": "referencetotransformerrootstackGraphQLAPINONEDS2BA9D1C8Name", - }, - "FunctionVersion": "2018-05-29", - "Name": "MutationupdatePostinit0Function", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.updatePost.init.1.req.vtl", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson({})", - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "PostDataSource": Object { - "DependsOn": Array [ - "PostIAMRole83BF708F", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DynamoDBConfig": Object { - "AwsRegion": Object { - "Ref": "AWS::Region", - }, - "TableName": Object { - "Ref": "PostTable", - }, - }, - "Name": "PostTable", - "ServiceRoleArn": Object { - "Fn::GetAtt": Array [ - "PostIAMRole83BF708F", - "Arn", - ], - }, - "Type": "AMAZON_DYNAMODB", - }, - "Type": "AWS::AppSync::DataSource", - }, - "PostIAMRole83BF708F": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "Policies": Array [ - Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "dynamodb:BatchGetItem", - "dynamodb:BatchWriteItem", - "dynamodb:PutItem", - "dynamodb:DeleteItem", - "dynamodb:GetItem", - "dynamodb:Scan", - "dynamodb:Query", - "dynamodb:UpdateItem", - "dynamodb:ConditionCheckItem", - "dynamodb:DescribeTable", - "dynamodb:GetRecords", - "dynamodb:GetShardIterator", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::Sub": Array [ - "arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/\${tablename}", - Object { - "tablename": Object { - "Fn::Join": Array [ - "", - Array [ - "Post-", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "-", - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - }, - ], - }, - Object { - "Fn::Sub": Array [ - "arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/\${tablename}/*", - Object { - "tablename": Object { - "Fn::Join": Array [ - "", - Array [ - "Post-", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "-", - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - }, - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "DynamoDBAccess", - }, - ], - "RoleName": Object { - "Fn::Join": Array [ - "", - Array [ - "PostIAMRolebbce9b-", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "-", - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - }, - "Type": "AWS::IAM::Role", - }, - "PostTable": Object { - "DeletionPolicy": "Delete", - "Properties": Object { - "AttributeDefinitions": Array [ - Object { - "AttributeName": "id", - "AttributeType": "S", - }, - ], - "BillingMode": "PROVISIONED", - "KeySchema": Array [ - Object { - "AttributeName": "id", - "KeyType": "HASH", - }, - ], - "PointInTimeRecoverySpecification": Object { - "Fn::If": Array [ - "ShouldUsePointInTimeRecovery", - Object { - "PointInTimeRecoveryEnabled": true, - }, - Object { - "Ref": "AWS::NoValue", - }, - ], - }, - "ProvisionedThroughput": Object { - "Fn::If": Array [ - "ShouldUsePayPerRequestBilling", - Object { - "Ref": "AWS::NoValue", - }, - Object { - "ReadCapacityUnits": Object { - "Ref": "DynamoDBModelTableReadIOPS", - }, - "WriteCapacityUnits": Object { - "Ref": "DynamoDBModelTableWriteIOPS", - }, - }, - ], - }, - "SSESpecification": Object { - "SSEEnabled": Object { - "Fn::If": Array [ - "ShouldUseServerSideEncryption", - true, - false, - ], - }, - }, - "StreamSpecification": Object { - "StreamViewType": "NEW_AND_OLD_IMAGES", - }, - "TableName": Object { - "Fn::Join": Array [ - "", - Array [ - "Post-", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "-", - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - }, - "Type": "AWS::DynamoDB::Table", - "UpdateReplacePolicy": "Delete", - }, - "QueryGetPostDataResolverFnQueryGetPostDataResolverFnAppSyncFunction06724190": Object { - "DependsOn": Array [ - "PostDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "PostDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "QueryGetPostDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.getPost.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.getPost.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "QueryListPostsDataResolverFnQueryListPostsDataResolverFnAppSyncFunction3D526AB7": Object { - "DependsOn": Array [ - "PostDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "PostDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "QueryListPostsDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.listPosts.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.listPosts.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Ref": "referencetotransformerrootstackGraphQLAPINONEDS2BA9D1C8Name", - }, - "FunctionVersion": "2018-05-29", - "Name": "QuerygetPostpostAuth0Function", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.getPost.postAuth.1.req.vtl", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson({})", - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "SubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionB4572868": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Ref": "referencetotransformerrootstackGraphQLAPINONEDS2BA9D1C8Name", - }, - "FunctionVersion": "2018-05-29", - "Name": "SubscriptionOnCreatePostDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Subscription.onCreatePost.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Subscription.onCreatePost.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "SubscriptiononCreatePostResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "onCreatePost", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "SubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionB4572868", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Subscription\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"onCreatePost\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"NONE\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) - -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Subscription", - }, - "Type": "AWS::AppSync::Resolver", - }, - "SubscriptiononDeletePostResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "onDeletePost", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "SubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionB4572868", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Subscription\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"onDeletePost\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"NONE\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) - -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Subscription", - }, - "Type": "AWS::AppSync::Resolver", - }, - "SubscriptiononUpdatePostResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "onUpdatePost", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "SubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionB4572868", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": "mockTemplate", - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Subscription", - }, - "Type": "AWS::AppSync::Resolver", - }, - "UpdatePostResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "updatePost", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "MutationupdatePostinit0FunctionMutationupdatePostinit0FunctionAppSyncFunctionBAC7D532", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "QuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunctionC72E5C0F", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "MutationUpdatePostDataResolverFnMutationUpdatePostDataResolverFnAppSyncFunctionBF7D410D", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"updatePost\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "PostTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", - }, - }, -} -`; - -exports[`ModelTransformer: should override model objects when given override config 2`] = ` -Object { - "Conditions": Object { - "HasEnvironmentParameter": Object { - "Fn::Not": Array [ - Object { - "Fn::Equals": Array [ - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - "NONE", - ], - }, - ], - }, - "ShouldUsePayPerRequestBilling": Object { - "Fn::Equals": Array [ - Object { - "Ref": "DynamoDBBillingMode", - }, - "PAY_PER_REQUEST", - ], - }, - "ShouldUsePointInTimeRecovery": Object { - "Fn::Equals": Array [ - Object { - "Ref": "DynamoDBEnablePointInTimeRecovery", - }, - "true", - ], - }, - "ShouldUseServerSideEncryption": Object { - "Fn::Equals": Array [ - Object { - "Ref": "DynamoDBEnableServerSideEncryption", - }, - "true", - ], - }, - }, - "Outputs": Object { - "GetAttCommentDataSourceName": Object { - "Description": "Your model DataSource name.", - "Export": Object { - "Name": Object { - "Fn::Join": Array [ - ":", - Array [ - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "GetAtt:CommentDataSource:Name", - ], - ], - }, - }, - "Value": Object { - "Fn::GetAtt": Array [ - "CommentDataSource", - "Name", - ], - }, - }, - "GetAttCommentTableName": Object { - "Description": "Your DynamoDB table name.", - "Export": Object { - "Name": Object { - "Fn::Join": Array [ - ":", - Array [ - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "GetAtt:CommentTable:Name", - ], - ], - }, - }, - "Value": Object { - "Ref": "CommentTable", - }, - }, - "GetAttCommentTableStreamArn": Object { - "Description": "Your DynamoDB table StreamArn.", - "Export": Object { - "Name": Object { - "Fn::Join": Array [ - ":", - Array [ - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "GetAtt:CommentTable:StreamArn", - ], - ], - }, - }, - "Value": Object { - "Fn::GetAtt": Array [ - "CommentTable", - "StreamArn", - ], - }, - }, - }, - "Parameters": Object { - "DynamoDBBillingMode": Object { - "AllowedValues": Array [ - "PAY_PER_REQUEST", - "PROVISIONED", - ], - "Default": "PAY_PER_REQUEST", - "Description": "Configure @model types to create DynamoDB tables with PAY_PER_REQUEST or PROVISIONED billing modes.", - "Type": "String", - }, - "DynamoDBEnablePointInTimeRecovery": Object { - "AllowedValues": Array [ - "true", - "false", - ], - "Default": "false", - "Description": "Whether to enable Point in Time Recovery on the table.", - "Type": "String", - }, - "DynamoDBEnableServerSideEncryption": Object { - "AllowedValues": Array [ - "true", - "false", - ], - "Default": "true", - "Description": "Enable server side encryption powered by KMS.", - "Type": "String", - }, - "DynamoDBModelTableReadIOPS": Object { - "Default": 5, - "Description": "The number of read IOPS the table should support.", - "Type": "Number", - }, - "DynamoDBModelTableWriteIOPS": Object { - "Default": 5, - "Description": "The number of write IOPS the table should support.", - "Type": "Number", - }, - "referencetotransformerrootstackGraphQLAPI20497F53ApiId": Object { - "Type": "String", - }, - "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostMutationcreatePostinit0FunctionMutationcreatePostinit0FunctionAppSyncFunctionB82DB57BFunctionId": Object { - "Type": "String", - }, - "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostMutationupdatePostinit0FunctionMutationupdatePostinit0FunctionAppSyncFunction148F70DDFunctionId": Object { - "Type": "String", - }, - "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId": Object { - "Type": "String", - }, - "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostSubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionAE3ECF1FFunctionId": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentBucket7592718ARef": Object { - "Type": "String", - }, - "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref": Object { - "Type": "String", - }, - "referencetotransformerrootstackenv10C5A902Ref": Object { - "Type": "String", - }, - }, - "Resources": Object { - "CommentDataSource": Object { - "DependsOn": Array [ - "CommentIAMRoleD5EC5F51", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DynamoDBConfig": Object { - "AwsRegion": Object { - "Ref": "AWS::Region", - }, - "TableName": Object { - "Ref": "CommentTable", - }, - }, - "Name": "CommentTable", - "ServiceRoleArn": Object { - "Fn::GetAtt": Array [ - "CommentIAMRoleD5EC5F51", - "Arn", - ], - }, - "Type": "AMAZON_DYNAMODB", - }, - "Type": "AWS::AppSync::DataSource", - }, - "CommentIAMRoleD5EC5F51": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "appsync.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "Policies": Array [ - Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "dynamodb:BatchGetItem", - "dynamodb:BatchWriteItem", - "dynamodb:PutItem", - "dynamodb:DeleteItem", - "dynamodb:GetItem", - "dynamodb:Scan", - "dynamodb:Query", - "dynamodb:UpdateItem", - "dynamodb:ConditionCheckItem", - "dynamodb:DescribeTable", - "dynamodb:GetRecords", - "dynamodb:GetShardIterator", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::Sub": Array [ - "arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/\${tablename}", - Object { - "tablename": Object { - "Fn::Join": Array [ - "", - Array [ - "Comment-", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "-", - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - }, - ], - }, - Object { - "Fn::Sub": Array [ - "arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/\${tablename}/*", - Object { - "tablename": Object { - "Fn::Join": Array [ - "", - Array [ - "Comment-", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "-", - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - }, - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "DynamoDBAccess", - }, - ], - "RoleName": Object { - "Fn::Join": Array [ - "", - Array [ - "CommentIAMRole20388d-", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "-", - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - }, - "Type": "AWS::IAM::Role", - }, - "CommentTable": Object { - "DeletionPolicy": "Delete", - "Properties": Object { - "AttributeDefinitions": Array [ - Object { - "AttributeName": "id", - "AttributeType": "S", - }, - ], - "BillingMode": "PROVISIONED", - "KeySchema": Array [ - Object { - "AttributeName": "id", - "KeyType": "HASH", - }, - ], - "PointInTimeRecoverySpecification": Object { - "Fn::If": Array [ - "ShouldUsePointInTimeRecovery", - Object { - "PointInTimeRecoveryEnabled": true, - }, - Object { - "Ref": "AWS::NoValue", - }, - ], - }, - "ProvisionedThroughput": Object { - "Fn::If": Array [ - "ShouldUsePayPerRequestBilling", - Object { - "Ref": "AWS::NoValue", - }, - Object { - "ReadCapacityUnits": Object { - "Ref": "DynamoDBModelTableReadIOPS", - }, - "WriteCapacityUnits": Object { - "Ref": "DynamoDBModelTableWriteIOPS", - }, - }, - ], - }, - "SSESpecification": Object { - "SSEEnabled": Object { - "Fn::If": Array [ - "ShouldUseServerSideEncryption", - true, - false, - ], - }, - }, - "StreamSpecification": Object { - "StreamViewType": "NEW_AND_OLD_IMAGES", - }, - "TableName": Object { - "Fn::Join": Array [ - "", - Array [ - "Comment-", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "-", - Object { - "Ref": "referencetotransformerrootstackenv10C5A902Ref", - }, - ], - ], - }, - }, - "Type": "AWS::DynamoDB::Table", - "UpdateReplacePolicy": "Delete", - }, - "CreateCommentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "createComment", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostMutationcreatePostinit0FunctionMutationcreatePostinit0FunctionAppSyncFunctionB82DB57BFunctionId", - }, - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId", - }, - Object { - "Fn::GetAtt": Array [ - "MutationCreateCommentDataResolverFnMutationCreateCommentDataResolverFnAppSyncFunctionD019FFE0", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"createComment\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "CommentTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", - }, - "DeleteCommentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "deleteComment", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId", - }, - Object { - "Fn::GetAtt": Array [ - "MutationDeleteCommentDataResolverFnMutationDeleteCommentDataResolverFnAppSyncFunctionD661C8CB", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"deleteComment\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "CommentTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", - }, - "GetCommentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "getComment", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId", - }, - Object { - "Fn::GetAtt": Array [ - "QueryGetCommentDataResolverFnQueryGetCommentDataResolverFnAppSyncFunction8473E2B0", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Query\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"getComment\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "CommentTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", - }, - "ListCommentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "listComments", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId", - }, - Object { - "Fn::GetAtt": Array [ - "QueryListCommentsDataResolverFnQueryListCommentsDataResolverFnAppSyncFunction474D4A91", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Query\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"listComments\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "CommentTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", - }, - "MutationCreateCommentDataResolverFnMutationCreateCommentDataResolverFnAppSyncFunctionD019FFE0": Object { - "DependsOn": Array [ - "CommentDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "CommentDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "MutationCreateCommentDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.createComment.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.createComment.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "MutationDeleteCommentDataResolverFnMutationDeleteCommentDataResolverFnAppSyncFunctionD661C8CB": Object { - "DependsOn": Array [ - "CommentDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "CommentDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "MutationDeleteCommentDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.deleteComment.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.deleteComment.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "MutationUpdateCommentDataResolverFnMutationUpdateCommentDataResolverFnAppSyncFunctionB47372B5": Object { - "DependsOn": Array [ - "CommentDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "CommentDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "MutationUpdateCommentDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.updateComment.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Mutation.updateComment.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "QueryGetCommentDataResolverFnQueryGetCommentDataResolverFnAppSyncFunction8473E2B0": Object { - "DependsOn": Array [ - "CommentDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "CommentDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "QueryGetCommentDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.getComment.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.getComment.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "QueryListCommentsDataResolverFnQueryListCommentsDataResolverFnAppSyncFunction474D4A91": Object { - "DependsOn": Array [ - "CommentDataSource", - ], - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "DataSourceName": Object { - "Fn::GetAtt": Array [ - "CommentDataSource", - "Name", - ], - }, - "FunctionVersion": "2018-05-29", - "Name": "QueryListCommentsDataResolverFn", - "RequestMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.listComments.req.vtl", - ], - ], - }, - "ResponseMappingTemplateS3Location": Object { - "Fn::Join": Array [ - "", - Array [ - "s3://", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentBucket7592718ARef", - }, - "/", - Object { - "Ref": "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref", - }, - "/resolvers/Query.listComments.res.vtl", - ], - ], - }, - }, - "Type": "AWS::AppSync::FunctionConfiguration", - }, - "SubscriptiononCreateCommentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "onCreateComment", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId", - }, - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostSubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionAE3ECF1FFunctionId", - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Subscription\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"onCreateComment\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"NONE\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) - -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Subscription", - }, - "Type": "AWS::AppSync::Resolver", - }, - "SubscriptiononDeleteCommentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "onDeleteComment", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId", - }, - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostSubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionAE3ECF1FFunctionId", - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Subscription\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"onDeleteComment\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"NONE\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) - -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Subscription", - }, - "Type": "AWS::AppSync::Resolver", - }, - "SubscriptiononUpdateCommentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "onUpdateComment", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId", - }, - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostSubscriptionOnCreatePostDataResolverFnSubscriptionOnCreatePostDataResolverFnAppSyncFunctionAE3ECF1FFunctionId", - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Subscription\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"onUpdateComment\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"NONE\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) - -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Subscription", - }, - "Type": "AWS::AppSync::Resolver", - }, - "UpdateCommentResolver": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "FieldName": "updateComment", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostMutationupdatePostinit0FunctionMutationupdatePostinit0FunctionAppSyncFunction148F70DDFunctionId", - }, - Object { - "Ref": "referencetotransformerrootstackPostNestedStackPostNestedStackResource45FCAC5EOutputstransformerrootstackPostQuerygetPostpostAuth0FunctionQuerygetPostpostAuth0FunctionAppSyncFunction052A79B2FunctionId", - }, - Object { - "Fn::GetAtt": Array [ - "MutationUpdateCommentDataResolverFnMutationUpdateCommentDataResolverFnAppSyncFunctionB47372B5", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - "", - Array [ - "$util.qr($ctx.stash.put(\\"typeName\\", \\"Mutation\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"updateComment\\")) -$util.qr($ctx.stash.put(\\"conditions\\", [])) -$util.qr($ctx.stash.put(\\"metadata\\", {})) -$util.qr($ctx.stash.metadata.put(\\"dataSourceType\\", \\"AMAZON_DYNAMODB\\")) -$util.qr($ctx.stash.metadata.put(\\"apiId\\", \\"", - Object { - "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId", - }, - "\\")) -$util.qr($ctx.stash.put(\\"connectionAttributes\\", {})) -$util.qr($ctx.stash.put(\\"tableName\\", \\"", - Object { - "Ref": "CommentTable", - }, - "\\")) -$util.qr($ctx.stash.put(\\"adminRoles\\", [])) -$util.toJson({})", - ], - ], - }, - "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)", - "TypeName": "Mutation", - }, - "Type": "AWS::AppSync::Resolver", - }, - }, -} -`; diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-function-transformer-override.test.ts b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-function-transformer-override.test.ts deleted file mode 100644 index 7c2e2a627b..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-function-transformer-override.test.ts +++ /dev/null @@ -1,56 +0,0 @@ -import * as path from 'path'; -import { stateManager } from '@aws-amplify/amplify-cli-core'; -import { parse } from 'graphql'; -import { FunctionTransformer } from '@aws-amplify/graphql-function-transformer'; -import { testTransform } from '@aws-amplify/graphql-transformer-test-utils'; -import { Construct } from 'constructs'; -import { applyFileBasedOverride } from '../../../graphql-transformer/override'; - -jest.spyOn(stateManager, 'getLocalEnvInfo').mockReturnValue({ envName: 'testEnvName' }); -jest.spyOn(stateManager, 'getProjectConfig').mockReturnValue({ projectName: 'testProjectName' }); - -test('it ovderrides the expected resources', () => { - const validSchema = ` - type Query { - echo(msg: String): String @function(name: "echofunction-\${env}") @function(name: "otherfunction") - } - `; - - const out = testTransform({ - schema: validSchema, - transformers: [new FunctionTransformer()], - overrideConfig: { - applyOverride: (scope: Construct) => applyFileBasedOverride(scope, path.join(__dirname, 'function-overrides')), - overrideFlag: true, - }, - }); - expect(out).toBeDefined(); - parse(out.schema); - expect(out.stacks).toBeDefined(); - const stack = out.stacks.FunctionDirectiveStack; - expect(stack).toBeDefined(); - expect(stack).toMatchSnapshot(); -}); - -test('it skips override if override file does not exist', () => { - const validSchema = ` - type Query { - echo(msg: String): String @function(name: "echofunction-\${env}") @function(name: "otherfunction") - } - `; - - const out = testTransform({ - schema: validSchema, - transformers: [new FunctionTransformer()], - overrideConfig: { - applyOverride: (scope: Construct) => applyFileBasedOverride(scope, path.join(__dirname, 'non-existing-override-directory')), - overrideFlag: true, - }, - }); - expect(out).toBeDefined(); - parse(out.schema); - expect(out.stacks).toBeDefined(); - const stack = out.stacks.FunctionDirectiveStack; - expect(stack).toBeDefined(); - expect(stack).toMatchSnapshot(); -}); diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-http-transformer-override.test.ts b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-http-transformer-override.test.ts deleted file mode 100644 index 3d2cf08e98..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-http-transformer-override.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -import path from 'path'; -import { testTransform } from '@aws-amplify/graphql-transformer-test-utils'; -import { parse } from 'graphql'; -import { stateManager } from '@aws-amplify/amplify-cli-core'; -import { HttpTransformer } from '@aws-amplify/graphql-http-transformer'; -import { Construct } from 'constructs'; -import { applyFileBasedOverride } from '../../../graphql-transformer/override'; - -jest.spyOn(stateManager, 'getLocalEnvInfo').mockReturnValue({ envName: 'testEnvName' }); -jest.spyOn(stateManager, 'getProjectConfig').mockReturnValue({ projectName: 'testProjectName' }); - -test('it generates the overrided resources', () => { - const validSchema = /* GraphQL */ ` - type Comment { - id: ID! - content: String @http(method: POST, url: "http://www.api.com/ping") - content2: String @http(method: PUT, url: "http://www.api.com/ping") - more: String @http(url: "http://api.com/ping/me/2") - evenMore: String @http(method: DELETE, url: "http://www.google.com/query/id") - stillMore: String @http(method: PATCH, url: "https://www.api.com/ping/id") - } - `; - const out = testTransform({ - schema: validSchema, - transformers: [new HttpTransformer()], - overrideConfig: { - applyOverride: (scope: Construct) => applyFileBasedOverride(scope, path.join(__dirname, 'http-overrides')), - overrideFlag: true, - }, - }); - expect(out).toBeDefined(); - expect(out.stacks).toBeDefined(); - parse(out.schema); - const stack = out.stacks.HttpStack; - expect(stack).toMatchSnapshot(); -}); - -test('it skips override if file does not exist', () => { - const validSchema = /* GraphQL */ ` - type Comment { - id: ID! - content: String @http(method: POST, url: "http://www.api.com/ping") - content2: String @http(method: PUT, url: "http://www.api.com/ping") - more: String @http(url: "http://api.com/ping/me/2") - evenMore: String @http(method: DELETE, url: "http://www.google.com/query/id") - stillMore: String @http(method: PATCH, url: "https://www.api.com/ping/id") - } - `; - const out = testTransform({ - schema: validSchema, - transformers: [new HttpTransformer()], - overrideConfig: { - applyOverride: (scope: Construct) => applyFileBasedOverride(scope, path.join(__dirname, 'non-existing-override-dir')), - overrideFlag: true, - }, - }); - expect(out).toBeDefined(); - expect(out.stacks).toBeDefined(); - parse(out.schema); - const stack = out.stacks.HttpStack; - expect(stack).toMatchSnapshot(); -}); diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-index-transformer-override.test.ts b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-index-transformer-override.test.ts deleted file mode 100644 index d13dc77093..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-index-transformer-override.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import * as path from 'path'; -import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; -import { ConflictHandlerType, SyncConfig } from '@aws-amplify/graphql-transformer-core'; -import { IndexTransformer } from '@aws-amplify/graphql-index-transformer'; -import { stateManager } from '@aws-amplify/amplify-cli-core'; -import { testTransform } from '@aws-amplify/graphql-transformer-test-utils'; -import { Construct } from 'constructs'; -import { applyFileBasedOverride } from '../../../graphql-transformer/override'; - -jest.spyOn(stateManager, 'getLocalEnvInfo').mockReturnValue({ envName: 'testEnvName' }); -jest.spyOn(stateManager, 'getProjectConfig').mockReturnValue({ projectName: 'testProjectName' }); - -test('it overrides expected resources', () => { - const validSchema = ` - type Song @model { - id: ID! - name: String! - genre: String! @index(name : "byGenre", queryField: "songInfoByGenre") - } - `; - const config: SyncConfig = { - ConflictDetection: 'VERSION', - ConflictHandler: ConflictHandlerType.AUTOMERGE, - }; - - const out = testTransform({ - schema: validSchema, - transformers: [new ModelTransformer(), new IndexTransformer()], - resolverConfig: { - project: config, - }, - overrideConfig: { - applyOverride: (scope: Construct) => applyFileBasedOverride(scope, path.join(__dirname, 'index-overrides')), - overrideFlag: true, - }, - }); - expect(out).toBeDefined(); - expect(out.stacks.Song.Resources!.CreateSongResolver).toMatchSnapshot(); - expect(out.stacks.Song.Resources!.GetSongResolver).toMatchSnapshot(); - expect(out.stacks.Song.Resources!.ListSongResolver).toMatchSnapshot(); - expect(out.stacks.Song.Resources!.DeleteSongResolver).toMatchSnapshot(); - expect(out.stacks.Song.Resources!.UpdateSongResolver).toMatchSnapshot(); - expect(out.stacks.Song.Resources!.SyncSongResolver).toMatchSnapshot(); - expect(out.stacks.Song.Resources!.SongDataSource).toMatchSnapshot(); -}); diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-predictions-transformer-override.test.ts b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-predictions-transformer-override.test.ts deleted file mode 100644 index be7fc3542e..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-predictions-transformer-override.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -import * as path from 'path'; -import { testTransform } from '@aws-amplify/graphql-transformer-test-utils'; -import { PredictionsTransformer } from '@aws-amplify/graphql-predictions-transformer'; -import { stateManager } from '@aws-amplify/amplify-cli-core'; -import { Construct } from 'constructs'; -import { applyFileBasedOverride } from '../../../graphql-transformer/override'; - -jest.spyOn(stateManager, 'getLocalEnvInfo').mockReturnValue({ envName: 'testEnvName' }); -jest.spyOn(stateManager, 'getProjectConfig').mockReturnValue({ projectName: 'testProjectName' }); - -test('it generates resources with overrides', () => { - const validSchema = /* GraphQL */ ` - type Query { - speakTranslatedIdentifiedText: String @predictions(actions: [identifyText, translateText, convertTextToSpeech]) - speakTranslatedLabelText: String @predictions(actions: [identifyLabels, translateText, convertTextToSpeech]) - } - `; - const out = testTransform({ - schema: validSchema, - transformers: [new PredictionsTransformer({ bucketName: 'myStorage${hash}-${env}' })], - overrideConfig: { - applyOverride: (scope: Construct) => applyFileBasedOverride(scope, path.join(__dirname, 'predictions-overrides')), - overrideFlag: true, - }, - }); - - expect(out).toBeDefined(); - expect(out.stacks).toMatchSnapshot(); -}); - -test('it skips override if override file does not exist', () => { - const validSchema = /* GraphQL */ ` - type Query { - speakTranslatedIdentifiedText: String @predictions(actions: [identifyText, translateText, convertTextToSpeech]) - speakTranslatedLabelText: String @predictions(actions: [identifyLabels, translateText, convertTextToSpeech]) - } - `; - const out = testTransform({ - schema: validSchema, - transformers: [new PredictionsTransformer({ bucketName: 'myStorage${hash}-${env}' })], - overrideConfig: { - applyOverride: (scope: Construct) => applyFileBasedOverride(scope, path.join(__dirname, 'non-existing-override-directory')), - overrideFlag: true, - }, - }); - - expect(out).toBeDefined(); - expect(out.stacks).toMatchSnapshot(); -}); diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-primary-key-transformer-override.test.ts b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-primary-key-transformer-override.test.ts deleted file mode 100644 index aec3a8cd79..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-primary-key-transformer-override.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -import * as path from 'path'; -import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; -import { ConflictHandlerType, SyncConfig } from '@aws-amplify/graphql-transformer-core'; -import { PrimaryKeyTransformer } from '@aws-amplify/graphql-index-transformer'; -import { stateManager } from '@aws-amplify/amplify-cli-core'; -import { testTransform } from '@aws-amplify/graphql-transformer-test-utils'; -import { Construct } from 'constructs'; -import { applyFileBasedOverride } from '../../../graphql-transformer/override'; - -jest.spyOn(stateManager, 'getLocalEnvInfo').mockReturnValue({ envName: 'testEnvName' }); -jest.spyOn(stateManager, 'getProjectConfig').mockReturnValue({ projectName: 'testProjectName' }); - -test('it overrides expected resources', () => { - const validSchema = ` - type Test @model { - email: String! @primaryKey - } - `; - const config: SyncConfig = { - ConflictDetection: 'VERSION', - ConflictHandler: ConflictHandlerType.AUTOMERGE, - }; - - const out = testTransform({ - schema: validSchema, - transformers: [new ModelTransformer(), new PrimaryKeyTransformer()], - resolverConfig: { - project: config, - }, - overrideConfig: { - applyOverride: (scope: Construct) => applyFileBasedOverride(scope, path.join(__dirname, 'primary-key-overrides')), - overrideFlag: true, - }, - }); - expect(out).toBeDefined(); - expect(out.stacks.Test.Resources!.CreateTestResolver).toMatchSnapshot(); - expect(out.stacks.Test.Resources!.GetTestResolver).toMatchSnapshot(); - expect(out.stacks.Test.Resources!.ListTestResolver).toMatchSnapshot(); - expect(out.stacks.Test.Resources!.DeleteTestResolver).toMatchSnapshot(); - expect(out.stacks.Test.Resources!.UpdateTestResolver).toMatchSnapshot(); - expect(out.stacks.Test.Resources!.SyncTestResolver).toMatchSnapshot(); - expect(out.stacks.Test.Resources!.TestDataSource).toMatchSnapshot(); -}); diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-searchable-transformer-override.test.ts b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-searchable-transformer-override.test.ts deleted file mode 100644 index fc6b8b9d55..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/amplify-graphql-searchable-transformer-override.test.ts +++ /dev/null @@ -1,103 +0,0 @@ -import * as path from 'path'; -import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; -import { testTransform } from '@aws-amplify/graphql-transformer-test-utils'; -import { Match, Template } from 'aws-cdk-lib/assertions'; -import { SearchableModelTransformer } from '@aws-amplify/graphql-searchable-transformer'; -import { stateManager } from '@aws-amplify/amplify-cli-core'; -import { Construct } from 'constructs'; -import { applyFileBasedOverride } from '../../../graphql-transformer/override'; - -jest.spyOn(stateManager, 'getLocalEnvInfo').mockReturnValue({ envName: 'testEnvName' }); -jest.spyOn(stateManager, 'getProjectConfig').mockReturnValue({ projectName: 'testProjectName' }); - -test('it overrides expected resources', () => { - const validSchema = ` - type Post @model @searchable { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - type Comment @model { - id: ID! - content: String! - } - `; - const out = testTransform({ - schema: validSchema, - transformers: [new ModelTransformer(), new SearchableModelTransformer()], - overrideConfig: { - applyOverride: (scope: Construct) => applyFileBasedOverride(scope, path.join(__dirname, 'searchable-overrides')), - overrideFlag: true, - }, - }); - expect(out).toBeDefined(); - const searchableStack = out.stacks.SearchableStack; - Template.fromJSON(searchableStack).hasResourceProperties('AWS::AppSync::DataSource', { - ApiId: { - Ref: Match.anyValue(), - }, - Name: 'OpenSearchDataSource', - Type: 'AMAZON_ELASTICSEARCH', - ElasticsearchConfig: { - AwsRegion: { - 'Fn::Select': [ - 3, - { - 'Fn::Split': [ - ':', - { - 'Fn::GetAtt': ['OpenSearchDomain', 'Arn'], - }, - ], - }, - ], - }, - Endpoint: { - 'Fn::Join': [ - '', - [ - 'https://', - { - 'Fn::GetAtt': ['OpenSearchDomain', 'DomainEndpoint'], - }, - ], - ], - }, - }, - ServiceRoleArn: 'mockArn', - }); - Template.fromJSON(searchableStack).hasResourceProperties('AWS::Elasticsearch::Domain', { - DomainName: Match.anyValue(), - EBSOptions: Match.anyValue(), - ElasticsearchClusterConfig: Match.anyValue(), - ElasticsearchVersion: '7.10', - EncryptionAtRestOptions: { - Enabled: true, - KmsKeyId: '1a2a3a4-1a2a-3a4a-5a6a-1a2a3a4a5a6a', - }, - DomainEndpointOptions: { - EnforceHTTPS: true, - }, - }); - Template.fromJSON(searchableStack).hasResourceProperties('AWS::AppSync::Resolver', { - ApiId: { - Ref: Match.anyValue(), - }, - FieldName: Match.anyValue(), - TypeName: 'Query', - Kind: 'PIPELINE', - PipelineConfig: { - Functions: [ - { - Ref: Match.anyValue(), - }, - { - 'Fn::GetAtt': [Match.anyValue(), 'FunctionId'], - }, - ], - }, - RequestMappingTemplate: 'mockTemplate', - ResponseMappingTemplate: '$util.toJson($ctx.prev.result)', - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/function-overrides/build/override.js b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/function-overrides/build/override.js deleted file mode 100644 index 854543d63e..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/function-overrides/build/override.js +++ /dev/null @@ -1,15 +0,0 @@ -function override(resource, amplifyProjectInfo) { - resource.function.lambdaDataSource['Echofunction'].serviceRoleArn = 'mockArn'; - resource.function.lambdaDataSource['Otherfunction'].serviceRoleArn = 'mockArn'; - // override resolver - resource.function.resolvers['queryEchoResolver'].requestMappingTemplate = 'mockTemplate'; - - if (amplifyProjectInfo.envName != 'testEnvName') { - throw new Error(`Unexpected envName: ${amplifyProjectInfo.envName}`); - } - - if (amplifyProjectInfo.projectName != 'testProjectName') { - throw new Error(`Unexpected envName: ${amplifyProjectInfo.envName}`); - } -} -exports.override = override; diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/http-overrides/build/override.js b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/http-overrides/build/override.js deleted file mode 100644 index 5c0eb81d8c..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/http-overrides/build/override.js +++ /dev/null @@ -1,29 +0,0 @@ -function override(resource, amplifyProjectInfo) { - resource.http.httpsDataSource['httpwwwapicom'].serviceRoleArn = 'mockArn'; - resource.http.httpsDataSource['httpwwwapicom'].httpConfig = { - endpoint: 'mockEndpoint', - }; - resource.http.httpsDataSource['httpapicom'].serviceRoleArn = 'mockArn'; - resource.http.httpsDataSource['httpapicom'].httpConfig = { - endpoint: 'mockEndpoint', - }; - resource.http.httpsDataSource['httpwwwgooglecom'].serviceRoleArn = 'mockArn'; - resource.http.httpsDataSource['httpwwwgooglecom'].httpConfig = { - endpoint: 'mockEndpoint', - }; - resource.http.httpsDataSource['httpswwwapicom'].serviceRoleArn = 'mockArn'; - resource.http.httpsDataSource['httpswwwapicom'].httpConfig = { - endpoint: 'mockEndpoint', - }; - // override resolver - resource.http.resolvers['commentContentResolver'].requestMappingTemplate = 'mockTemplate'; - - if (amplifyProjectInfo.envName != 'testEnvName') { - throw new Error(`Unexpected envName: ${amplifyProjectInfo.envName}`); - } - - if (amplifyProjectInfo.projectName != 'testProjectName') { - throw new Error(`Unexpected envName: ${amplifyProjectInfo.envName}`); - } -} -exports.override = override; diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/index-overrides/build/override.js b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/index-overrides/build/override.js deleted file mode 100644 index 0d00f108a1..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/index-overrides/build/override.js +++ /dev/null @@ -1,16 +0,0 @@ -function override(resource, amplifyProjectInfo) { - resource.models.Song.modelDatasource.dynamoDbConfig.deltaSyncConfig = { - deltaSyncTableTtl: '15', - baseTableTtl: '20', - deltaSyncTableName: 'SongTable', - }; - - if (amplifyProjectInfo.envName != 'testEnvName') { - throw new Error(`Unexpected envName: ${amplifyProjectInfo.envName}`); - } - - if (amplifyProjectInfo.projectName != 'testProjectName') { - throw new Error(`Unexpected envName: ${amplifyProjectInfo.envName}`); - } -} -exports.override = override; diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/model-overrides/build/override.js b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/model-overrides/build/override.js deleted file mode 100644 index 59b58f543a..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/model-overrides/build/override.js +++ /dev/null @@ -1,16 +0,0 @@ -function override(resource, amplifyProjectInfo) { - resource.api.GraphQLAPI.xrayEnabled = true; - resource.models['Post'].modelDDBTable.billingMode = 'PROVISIONED'; - resource.models['Comment'].modelDDBTable.billingMode = 'PROVISIONED'; - // override resolver - resource.models['Post'].resolvers['subscriptionOnUpdatePostResolver'].requestMappingTemplate = 'mockTemplate'; - - if (amplifyProjectInfo.envName != 'testEnvName') { - throw new Error(`Unexpected envName: ${amplifyProjectInfo.envName}`); - } - - if (amplifyProjectInfo.projectName != 'testProjectName') { - throw new Error(`Unexpected envName: ${amplifyProjectInfo.envName}`); - } -} -exports.override = override; diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/model-transformer-override.test.ts b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/model-transformer-override.test.ts deleted file mode 100644 index 3fca2ddfaa..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/model-transformer-override.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import path from 'path'; -import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; -import { testTransform } from '@aws-amplify/graphql-transformer-test-utils'; -import { stateManager } from '@aws-amplify/amplify-cli-core'; -import { Construct } from 'constructs'; -import { applyFileBasedOverride } from '../../../graphql-transformer/override'; - -jest.spyOn(stateManager, 'getLocalEnvInfo').mockReturnValue({ envName: 'testEnvName' }); -jest.spyOn(stateManager, 'getProjectConfig').mockReturnValue({ projectName: 'testProjectName' }); - -describe('ModelTransformer:', () => { - it('should override model objects when given override config', () => { - const validSchema = ` - type Post @model { - id: ID! - comments: [Comment] - } - type Comment @model{ - id: String! - text: String! - } - `; - const out = testTransform({ - schema: validSchema, - transformers: [new ModelTransformer()], - overrideConfig: { - applyOverride: (scope: Construct) => applyFileBasedOverride(scope, path.join(__dirname, 'model-overrides')), - overrideFlag: true, - }, - }); - expect(out).toBeDefined(); - const postStack = out.stacks.Post; - const commentStack = out.stacks.Comment; - - expect(postStack).toMatchSnapshot(); - expect(commentStack).toMatchSnapshot(); - }); - - it('should not override model objects when override file does not exist', () => { - const validSchema = ` - type Post @model { - id: ID! - comments: [Comment] - } - type Comment @model{ - id: String! - text: String! - } - `; - const out = testTransform({ - schema: validSchema, - transformers: [new ModelTransformer()], - overrideConfig: { - applyOverride: (scope: Construct) => applyFileBasedOverride(scope, path.join(__dirname, 'non-existing-override-directory')), - overrideFlag: true, - }, - }); - expect(out).toBeDefined(); - const postStack = out.stacks.Post; - const commentStack = out.stacks.Comment; - - expect(postStack).toMatchSnapshot(); - expect(commentStack).toMatchSnapshot(); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/predictions-overrides/build/override.js b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/predictions-overrides/build/override.js deleted file mode 100644 index a5d949bf2a..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/predictions-overrides/build/override.js +++ /dev/null @@ -1,13 +0,0 @@ -function override(resource, amplifyProjectInfo) { - resource.predictions.TranslateDataSource.serviceRoleArn = 'mockArn'; - resource.predictions.resolvers['querySpeakTranslatedLabelTextResolver'].requestMappingTemplate = 'mockTeplate'; - - if (amplifyProjectInfo.envName != 'testEnvName') { - throw new Error(`Unexpected envName: ${amplifyProjectInfo.envName}`); - } - - if (amplifyProjectInfo.projectName != 'testProjectName') { - throw new Error(`Unexpected envName: ${amplifyProjectInfo.envName}`); - } -} -exports.override = override; diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/primary-key-overrides/build/override.js b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/primary-key-overrides/build/override.js deleted file mode 100644 index 52a2d9c139..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/primary-key-overrides/build/override.js +++ /dev/null @@ -1,16 +0,0 @@ -function override(resource, amplifyProjectInfo) { - resource.models.Test.modelDatasource.dynamoDbConfig.deltaSyncConfig = { - deltaSyncTableTtl: '25', - baseTableTtl: '20', - deltaSyncTableName: 'TestTable', - }; - - if (amplifyProjectInfo.envName != 'testEnvName') { - throw new Error(`Unexpected envName: ${amplifyProjectInfo.envName}`); - } - - if (amplifyProjectInfo.projectName != 'testProjectName') { - throw new Error(`Unexpected envName: ${amplifyProjectInfo.envName}`); - } -} -exports.override = override; diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/searchable-overrides/build/override.js b/packages/amplify-category-api/src/__tests__/graphql-transformer/override/searchable-overrides/build/override.js deleted file mode 100644 index f94e2159f8..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/override/searchable-overrides/build/override.js +++ /dev/null @@ -1,19 +0,0 @@ -function override(resource, amplifyProjectInfo) { - resource.opensearch.OpenSearchDomain.encryptionAtRestOptions = { - enabled: true, - kmsKeyId: '1a2a3a4-1a2a-3a4a-5a6a-1a2a3a4a5a6a', - }; - resource.opensearch.OpenSearchDataSource.serviceRoleArn = 'mockArn'; - resource.opensearch.OpenSearchModelLambdaMapping['Post'].functionName = 'mockFunciton'; - // override resolver - resource.opensearch.resolvers['querySearchPostsResolver'].requestMappingTemplate = 'mockTemplate'; - - if (amplifyProjectInfo.envName != 'testEnvName') { - throw new Error(`Unexpected envName: ${amplifyProjectInfo.envName}`); - } - - if (amplifyProjectInfo.projectName != 'testProjectName') { - throw new Error(`Unexpected envName: ${amplifyProjectInfo.envName}`); - } -} -exports.override = override; diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/sandbox-mode-helpers.test.ts b/packages/amplify-category-api/src/__tests__/graphql-transformer/sandbox-mode-helpers.test.ts deleted file mode 100644 index 7e6e694126..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/sandbox-mode-helpers.test.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import chalk from 'chalk'; -import * as prompts from '@aws-amplify/amplify-prompts'; -import { - showSandboxModePrompts, - showGlobalSandboxModeWarning, - schemaHasSandboxModeEnabled, -} from '../../graphql-transformer/sandbox-mode-helpers'; -import * as apiKeyHelpers from '../../graphql-transformer/api-key-helpers'; - -let ctx; -let apiKeyPresent = true; - -describe('sandbox mode helpers', () => { - beforeEach(() => { - const envName = 'dev'; - const getEnvInfo = (): { envName: string } => ({ envName }); - ctx = { - amplify: { - getEnvInfo, - invokePluginMethod: jest.fn(), - }, - } as unknown as $TSContext; - - jest.spyOn(prompts.printer, 'info').mockImplementation(); - jest.spyOn(apiKeyHelpers, 'hasApiKey').mockResolvedValue(apiKeyPresent); - }); - - describe('showSandboxModePrompts', () => { - describe('missing api key', () => { - beforeAll(() => { - apiKeyPresent = false; - }); - - it('displays warning', async () => { - await showSandboxModePrompts(ctx); - - expect(prompts.printer.info).toBeCalledWith( - ` -⚠️ WARNING: Global Sandbox Mode has been enabled, which requires a valid API key. If -you'd like to disable, remove ${chalk.green('"input AMPLIFY { globalAuthRule: AuthRule = { allow: public } }"')} -from your GraphQL schema and run 'amplify push' again. If you'd like to proceed with -sandbox mode disabled, do not create an API Key. -`, - 'yellow', - ); - expect(ctx.amplify.invokePluginMethod).toBeCalledWith(ctx, 'api', undefined, 'promptToAddApiKey', [ctx]); - }); - }); - }); - - describe('showGlobalSandboxModeWarning', () => { - it('prints sandbox api key message', () => { - showGlobalSandboxModeWarning('mockLink'); - - expect(prompts.printer.info).toBeCalledWith( - ` -⚠️ WARNING: your GraphQL API currently allows public create, read, update, and delete access to all models via an API Key. To configure PRODUCTION-READY authorization rules, review: mockLink -`, - 'yellow', - ); - }); - }); - - describe('schemaHasSandboxModeEnabled', () => { - it('parses sandbox AMPLIFY input on schema', () => { - const schema = ` - input AMPLIFY { globalAuthRule: AuthRule = { allow: public } } - `; - - expect(schemaHasSandboxModeEnabled(schema, 'mockDocLink')).toEqual(true); - }); - - it('passes through when AMPLIFY input is not present', () => { - const schema = ` - type Todo @model { - id: ID! - content: String - } - `; - - expect(schemaHasSandboxModeEnabled(schema, 'mockDocLink')).toEqual(false); - }); - - describe('input AMPLIFY has incorrect values', () => { - it('allows "global_auth_rule"', () => { - const schema = ` - input AMPLIFY { global_auth_rule: AuthRule = { allow: public } } - `; - - expect(schemaHasSandboxModeEnabled(schema, 'mockDocLink')).toEqual(true); - }); - - it('guards for AuthRule', () => { - const schema = ` - input AMPLIFY { globalAuthRule: AuthenticationRule = { allow: public } } - `; - - expect(() => schemaHasSandboxModeEnabled(schema, 'mockLink')).toThrow( - Error('There was a problem with your auth configuration. Learn more about auth here: mockLink'), - ); - }); - - it('checks for "allow" field name', () => { - const schema = ` - input AMPLIFY { globalAuthRule: AuthRule = { allows: public } } - `; - - expect(() => schemaHasSandboxModeEnabled(schema, 'mockLink')).toThrow( - Error('There was a problem with your auth configuration. Learn more about auth here: mockLink'), - ); - }); - - it('checks for "public" value from "allow" field', () => { - const schema = ` - input AMPLIFY { globalAuthRule: AuthRule = { allow: private } } - `; - - expect(() => schemaHasSandboxModeEnabled(schema, 'mockLink')).toThrowError( - Error('There was a problem with your auth configuration. Learn more about auth here: mockLink'), - ); - }); - }); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/transform-graphql-schema-v2.test.ts b/packages/amplify-category-api/src/__tests__/graphql-transformer/transform-graphql-schema-v2.test.ts deleted file mode 100644 index f6ad0c1840..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/transform-graphql-schema-v2.test.ts +++ /dev/null @@ -1,245 +0,0 @@ -import { $TSContext, pathManager, ApiCategoryFacade } from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; -import { constructTransformerChain } from '@aws-amplify/graphql-transformer'; -import { DataSourceType, DynamoDBProvisionStrategy } from 'graphql-transformer-core'; -import { getUserOverridenSlots, transformGraphQLSchemaV2 } from '../../graphql-transformer/transform-graphql-schema-v2'; -import { generateTransformerOptions } from '../../graphql-transformer/transformer-options-v2'; -import { getAppSyncAPIName } from '../../provider-utils/awscloudformation/utils/amplify-meta-utils'; - -jest.mock('@aws-amplify/amplify-cli-core'); -jest.mock('@aws-amplify/amplify-prompts'); -jest.mock('graphql-transformer-core'); -jest.mock('../../graphql-transformer/transformer-options-v2'); -jest.mock('../../graphql-transformer/user-defined-slots'); -jest.mock('../../provider-utils/awscloudformation/utils/amplify-meta-utils'); - -describe('transformGraphQLSchemaV2', () => { - const printerMock = printer as jest.Mocked; - const pathManagerMock = pathManager as jest.Mocked; - const ApiCategoryFacadeMock = ApiCategoryFacade as jest.Mocked; - const generateTransformerOptionsMock = generateTransformerOptions as jest.Mock; - const getAppSyncAPINameMock = getAppSyncAPIName as jest.Mock; - - beforeEach(async () => { - jest.clearAllMocks(); - }); - - test('tranformer logs are passed up', async () => { - const contextMock = { - amplify: { - getEnvInfo: jest.fn(), - invokePluginMethod: jest.fn(), - getResourceStatus: jest.fn(() => ({ - resourcesToBeCreated: [ - { - service: 'AppSync', - providerPlugin: 'awscloudformation', - resourceName: 'mock resource', - category: 'api', - output: {}, - }, - ], - resourcesToBeUpdated: [], - allResources: [], - })), - getProjectMeta: jest.fn(() => ({ - providers: { - awscloudformation: { - Region: 'us-east-1', - }, - }, - })), - }, - parameters: { - options: { resourcesDir: 'resourceDir', projectDirectory: __dirname }, - }, - mergeResources: jest.fn(), - } as unknown as $TSContext; - pathManagerMock.getBackendDirPath.mockReturnValue('backenddir'); - pathManagerMock.getCurrentCloudBackendDirPath.mockReturnValue('currentcloudbackenddir'); - ApiCategoryFacadeMock.getTransformerVersion.mockReturnValue(Promise.resolve(2)); - - const schema = ` - type Todo @model @auth(rules: [{ allow: owner }]) { - content: String - } - `; - // Intentionally generating the V1 flavor of the project config to emulate the Gen1 CLI flow. This is fixed up in the transformer - const modelToDatasourceMap = new Map([ - [ - 'Todo', - { - dbType: 'DYNAMODB', - provisionDB: true, - provisionStrategy: DynamoDBProvisionStrategy.DEFAULT, - }, - ], - ]); - - generateTransformerOptionsMock.mockReturnValue({ - projectConfig: { - // schema that will generate auth warnings - schema, - config: { StackMapping: {} }, - modelToDatasourceMap, - }, - transformersFactory: constructTransformerChain(), - transformersFactoryArgs: {}, - dryRun: true, - projectDirectory: __dirname, - authConfig: { - additionalAuthenticationProviders: [], - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - }, - transformParameters: { - shouldDeepMergeDirectiveConfigDefaults: false, - useSubUsernameForDefaultIdentityClaim: false, - populateOwnerFieldForStaticGroupAuth: false, - secondaryKeyAsGSI: false, - enableAutoIndexQueryNames: false, - respectPrimaryKeyAttributesOnConnectionField: false, - }, - }); - getAppSyncAPINameMock.mockReturnValue(['testapi']); - - await transformGraphQLSchemaV2(contextMock, {}); - expect(printerMock.warn).toBeCalledWith( - " WARNING: Amplify CLI will change the default identity claim from 'username' to use 'sub::username'. To continue using only usernames, set 'identityClaim: \"username\"' on your 'owner' rules on your schema. The default will be officially switched with v9.0.0. To read more: https://docs.amplify.aws/cli/migration/identity-claim-changes/", - ); - expect(printerMock.warn).toBeCalledWith( - 'WARNING: owners may reassign ownership for the following model(s) and role(s): Todo: [owner]. If this is not intentional, you may want to apply field-level authorization rules to these fields. To read more: https://docs.amplify.aws/cli/graphql/authorization-rules/#per-user--owner-based-data-access.', - ); - }); -}); - -describe('getUserOverridenSlots', () => { - it('returns for empty request', () => { - expect(getUserOverridenSlots({})).toEqual([]); - }); - - it('returns for request mapping template', () => { - expect( - getUserOverridenSlots({ - 'Query.getTodo': [ - { - resolverTypeName: 'Query', - resolverFieldName: 'getTodo', - slotName: 'preAuth', - requestResolver: { - fileName: 'Query.getTodo.preAuth.1.req.vtl', - template: '$util.unauthorized()', - }, - }, - ], - }), - ).toEqual(['Query.getTodo.preAuth.1.req.vtl']); - }); - - it('returns for response mapping template', () => { - expect( - getUserOverridenSlots({ - 'Query.getTodo': [ - { - resolverTypeName: 'Query', - resolverFieldName: 'getTodo', - slotName: 'preAuth', - requestResolver: { - fileName: 'Query.getTodo.preAuth.1.res.vtl', - template: '$util.unauthorized()', - }, - }, - ], - }), - ).toEqual(['Query.getTodo.preAuth.1.res.vtl']); - }); - - it('returns for both requets and response mapping template', () => { - expect( - getUserOverridenSlots({ - 'Query.getTodo': [ - { - resolverTypeName: 'Query', - resolverFieldName: 'getTodo', - slotName: 'preAuth', - requestResolver: { - fileName: 'Query.getTodo.preAuth.1.req.vtl', - template: '$util.unauthorized()', - }, - }, - { - resolverTypeName: 'Query', - resolverFieldName: 'getTodo', - slotName: 'preAuth', - responseResolver: { - fileName: 'Query.getTodo.preAuth.1.res.vtl', - template: '$util.unauthorized()', - }, - }, - ], - }), - ).toEqual(['Query.getTodo.preAuth.1.req.vtl', 'Query.getTodo.preAuth.1.res.vtl']); - }); - - it('returns for multiple overridden resolvers', () => { - expect( - getUserOverridenSlots({ - 'Query.getTodo': [ - { - resolverTypeName: 'Query', - resolverFieldName: 'getTodo', - slotName: 'preAuth', - requestResolver: { - fileName: 'Query.getTodo.preAuth.1.req.vtl', - template: '$util.unauthorized()', - }, - }, - { - resolverTypeName: 'Query', - resolverFieldName: 'getTodo', - slotName: 'preAuth', - responseResolver: { - fileName: 'Query.getTodo.preAuth.1.res.vtl', - template: '$util.unauthorized()', - }, - }, - ], - 'Query.listTodos': [ - { - resolverTypeName: 'Query', - resolverFieldName: 'listTodos', - slotName: 'postDataLoad', - requestResolver: { - fileName: 'Query.listTodos.postDataLoad.1.req.vtl', - template: '$util.unauthorized()', - }, - }, - ], - }), - ).toEqual(['Query.getTodo.preAuth.1.req.vtl', 'Query.getTodo.preAuth.1.res.vtl', 'Query.listTodos.postDataLoad.1.req.vtl']); - }); - - // This doesn't seem to be what the system does, but type allows, so testing it. - it('returns when set on the same object', () => { - expect( - getUserOverridenSlots({ - 'Query.getTodo': [ - { - resolverTypeName: 'Query', - resolverFieldName: 'getTodo', - slotName: 'preAuth', - requestResolver: { - fileName: 'Query.getTodo.preAuth.1.req.vtl', - template: '$util.unauthorized()', - }, - responseResolver: { - fileName: 'Query.getTodo.preAuth.1.res.vtl', - template: '$util.unauthorized()', - }, - }, - ], - }), - ).toEqual(['Query.getTodo.preAuth.1.req.vtl', 'Query.getTodo.preAuth.1.res.vtl']); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/transformer-feature-flag-adapter.test.ts b/packages/amplify-category-api/src/__tests__/graphql-transformer/transformer-feature-flag-adapter.test.ts deleted file mode 100644 index 243bdc6562..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/transformer-feature-flag-adapter.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { FeatureFlags } from '@aws-amplify/amplify-cli-core'; -import { AmplifyCLIFeatureFlagAdapter } from '../../graphql-transformer/amplify-cli-feature-flag-adapter'; - -jest.mock('@aws-amplify/amplify-cli-core'); - -describe('AmplifyCLIFeatureFlagAdapter', () => { - const ff = new AmplifyCLIFeatureFlagAdapter(); - const transformerFeatureFlagPrefix = 'graphQLTransformer'; - - describe('getBoolean', () => { - test('getBoolean to return default value', () => { - (FeatureFlags.getBoolean).mockReturnValue(true); - const flagName = 'testFlag'; - expect(ff.getBoolean(flagName, true)).toEqual(true); - expect(FeatureFlags.getBoolean).toHaveBeenCalledWith(`${transformerFeatureFlagPrefix}.${flagName}`); - }); - - test('getBoolean should return defaultValue when the FF throw error', () => { - (FeatureFlags.getBoolean).mockImplementation(() => { - throw new Error('Error'); - }); - const flagName = 'testFlag'; - expect(ff.getBoolean(flagName, true)).toEqual(true); - expect(FeatureFlags.getBoolean).toHaveBeenCalledWith(`${transformerFeatureFlagPrefix}.${flagName}`); - }); - - test('getBoolean should throw error when defaultValue is missing and the FF throw error', () => { - (FeatureFlags.getBoolean).mockImplementation(() => { - throw new Error('Error'); - }); - const flagName = 'testFlag'; - expect(() => ff.getBoolean(flagName)).toThrowError(); - expect(FeatureFlags.getBoolean).toHaveBeenCalledWith(`${transformerFeatureFlagPrefix}.${flagName}`); - }); - }); - - describe('getNumber', () => { - test('getNumber to return default value', () => { - const expectedValue = 22; - (FeatureFlags.getNumber).mockReturnValue(expectedValue); - const flagName = 'testFlag'; - expect(ff.getNumber(flagName, 12)).toEqual(expectedValue); - expect(FeatureFlags.getNumber).toHaveBeenCalledWith(`${transformerFeatureFlagPrefix}.${flagName}`); - }); - - test('getNumber should return defaultValue when the FF throw error', () => { - (FeatureFlags.getNumber).mockImplementation(() => { - throw new Error('Error'); - }); - const flagName = 'testFlag'; - const expectedValue = 44; - expect(ff.getNumber(flagName, expectedValue)).toEqual(expectedValue); - expect(FeatureFlags.getNumber).toHaveBeenCalledWith(`${transformerFeatureFlagPrefix}.${flagName}`); - }); - - test('getNumber should throw error when defaultValue is missing and the FF throw error', () => { - (FeatureFlags.getNumber).mockImplementation(() => { - throw new Error('Error'); - }); - const flagName = 'testFlag'; - expect(() => ff.getNumber(flagName)).toThrowError(); - expect(FeatureFlags.getNumber).toHaveBeenCalledWith(`${transformerFeatureFlagPrefix}.${flagName}`); - }); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/transformer-options-v2.test.ts b/packages/amplify-category-api/src/__tests__/graphql-transformer/transformer-options-v2.test.ts deleted file mode 100644 index e94c5fb040..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/transformer-options-v2.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { suppressApiKeyGeneration } from '../../graphql-transformer/transformer-options-v2'; - -describe('suppressApiKeyGeneration', () => { - it('returns false if not defined in params', () => { - expect(suppressApiKeyGeneration({})).toEqual(false); - }); - - it('returns true if value is set to 1', () => { - expect(suppressApiKeyGeneration({ CreateAPIKey: 1 })).toEqual(false); - }); - - it('returns false if value is set to 0', () => { - expect(suppressApiKeyGeneration({ CreateAPIKey: 0 })).toEqual(true); - }); - - it('returns false if value is set to -1', () => { - expect(suppressApiKeyGeneration({ CreateAPIKey: -1 })).toEqual(true); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/user-defined-slots.test.ts b/packages/amplify-category-api/src/__tests__/graphql-transformer/user-defined-slots.test.ts deleted file mode 100644 index 7782408806..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/user-defined-slots.test.ts +++ /dev/null @@ -1,195 +0,0 @@ -import { SLOT_NAMES, parseUserDefinedSlots } from '../../graphql-transformer/user-defined-slots'; - -describe('user defined slots', () => { - describe('const SLOT_NAMES', () => { - it('has expected value', () => { - expect(SLOT_NAMES).toEqual( - new Set([ - 'init', - 'preAuth', - 'auth', - 'postAuth', - 'preDataLoad', - 'preUpdate', - 'preSubscribe', - 'postDataLoad', - 'postUpdate', - 'finish', - ]), - ); - }); - }); - - describe('parseUserDefinedSlots', () => { - it('creates the user defined slots map', () => { - const resolvers = { - 'Query.listTodos.auth.2.req.vtl': 'template 1', - 'Query.getTodo.auth.2.req.vtl': 'template 2', - 'Query.getTodo.postAuth.2.req.vtl': 'template 3', - 'Mutation.createTodo.auth.2.req.vtl': 'template 4', - }; - - expect(parseUserDefinedSlots(resolvers)).toEqual({ - 'Query.listTodos': [ - { - requestResolver: { - fileName: 'Query.listTodos.auth.2.req.vtl', - template: 'template 1', - }, - resolverTypeName: 'Query', - resolverFieldName: 'listTodos', - slotName: 'auth', - }, - ], - 'Query.getTodo': [ - { - requestResolver: { - fileName: 'Query.getTodo.auth.2.req.vtl', - template: 'template 2', - }, - resolverTypeName: 'Query', - resolverFieldName: 'getTodo', - slotName: 'auth', - }, - { - requestResolver: { - fileName: 'Query.getTodo.postAuth.2.req.vtl', - template: 'template 3', - }, - resolverTypeName: 'Query', - resolverFieldName: 'getTodo', - slotName: 'postAuth', - }, - ], - 'Mutation.createTodo': [ - { - requestResolver: { - fileName: 'Mutation.createTodo.auth.2.req.vtl', - template: 'template 4', - }, - resolverTypeName: 'Mutation', - resolverFieldName: 'createTodo', - slotName: 'auth', - }, - ], - }); - }); - - it('groups request and response resolvers in the same slot together', () => { - const resolvers = { - 'Query.getTodo.auth.1.req.vtl': 'request resolver 1', - 'Query.getTodo.auth.1.res.vtl': 'response resolver 1', - 'Mutation.createTodo.postAuth.2.req.vtl': 'request resolver 2', - 'Mutation.createTodo.postAuth.2.res.vtl': 'response resolver 2', - }; - - expect(parseUserDefinedSlots(resolvers)).toEqual({ - 'Query.getTodo': [ - { - requestResolver: { - fileName: 'Query.getTodo.auth.1.req.vtl', - template: 'request resolver 1', - }, - responseResolver: { - fileName: 'Query.getTodo.auth.1.res.vtl', - template: 'response resolver 1', - }, - resolverTypeName: 'Query', - resolverFieldName: 'getTodo', - slotName: 'auth', - }, - ], - 'Mutation.createTodo': [ - { - requestResolver: { - fileName: 'Mutation.createTodo.postAuth.2.req.vtl', - template: 'request resolver 2', - }, - responseResolver: { - fileName: 'Mutation.createTodo.postAuth.2.res.vtl', - template: 'response resolver 2', - }, - resolverTypeName: 'Mutation', - resolverFieldName: 'createTodo', - slotName: 'postAuth', - }, - ], - }); - }); - - it('orders multiple slot resolvers correctly', () => { - const resolvers = { - 'Query.getTodo.auth.3.req.vtl': 'request resolver 3', - 'Query.getTodo.auth.3.res.vtl': 'response resolver 3', - 'Query.getTodo.auth.1.req.vtl': 'request resolver 1', - 'Query.getTodo.auth.1.res.vtl': 'response resolver 1', - 'Query.getTodo.auth.2.req.vtl': 'request resolver 2', - 'Query.getTodo.auth.2.res.vtl': 'response resolver 2', - }; - - const result = parseUserDefinedSlots(resolvers); - expect(result).toEqual({ - 'Query.getTodo': [ - { - requestResolver: { - fileName: 'Query.getTodo.auth.1.req.vtl', - template: 'request resolver 1', - }, - responseResolver: { - fileName: 'Query.getTodo.auth.1.res.vtl', - template: 'response resolver 1', - }, - resolverTypeName: 'Query', - resolverFieldName: 'getTodo', - slotName: 'auth', - }, - { - requestResolver: { - fileName: 'Query.getTodo.auth.2.req.vtl', - template: 'request resolver 2', - }, - responseResolver: { - fileName: 'Query.getTodo.auth.2.res.vtl', - template: 'response resolver 2', - }, - resolverTypeName: 'Query', - resolverFieldName: 'getTodo', - slotName: 'auth', - }, - { - requestResolver: { - fileName: 'Query.getTodo.auth.3.req.vtl', - template: 'request resolver 3', - }, - responseResolver: { - fileName: 'Query.getTodo.auth.3.res.vtl', - template: 'response resolver 3', - }, - resolverTypeName: 'Query', - resolverFieldName: 'getTodo', - slotName: 'auth', - }, - ], - }); - }); - - it('excludes invalid slot names', () => { - const resolvers = { - 'Query.listTodos.beforeAuth.2.req.vtl': 'template 1', - 'Query.getTodo.beforeAuth.2.req.vtl': 'template 2', - 'Query.getTodo.afterAuth.2.req.vtl': 'template 3', - 'Mutation.createTodo.preCreate.2.req.vtl': 'template 4', - }; - - expect(parseUserDefinedSlots(resolvers)).toEqual({}); - }); - - it('exclused README file', () => { - const resolvers = { - 'README.md': 'read me', - }; - - expect(parseUserDefinedSlots(resolvers)).toEqual({}); - }); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/graphql-transformer/utils.test.ts b/packages/amplify-category-api/src/__tests__/graphql-transformer/utils.test.ts deleted file mode 100644 index 9069a3994f..0000000000 --- a/packages/amplify-category-api/src/__tests__/graphql-transformer/utils.test.ts +++ /dev/null @@ -1,338 +0,0 @@ -import * as path from 'path'; -import * as fs from 'fs-extra'; -import { $TSContext, CloudformationProviderFacade, pathManager, JSONUtilities } from '@aws-amplify/amplify-cli-core'; -import { mergeUserConfigWithTransformOutput, writeDeploymentToDisk, getAdminRoles } from '../../graphql-transformer/utils'; -import { TransformerProjectConfig } from '../../graphql-transformer/cdk-compat/project-config'; -import { DeploymentResources } from '../../graphql-transformer/cdk-compat/deployment-resources'; - -jest.mock('fs-extra'); -jest.mock('@aws-amplify/amplify-cli-core'); - -const fs_mock = fs as jest.Mocked; -const prePushCfnTemplateModifier_mock = jest.fn(); - -CloudformationProviderFacade.prePushCfnTemplateModifier = prePushCfnTemplateModifier_mock; - -fs_mock.readdirSync.mockReturnValue([]); - -describe('graphql transformer utils', () => { - let userConfig: TransformerProjectConfig; - let transformerOutput: DeploymentResources; - - beforeEach(() => { - transformerOutput = { - userOverriddenSlots: [], - resolvers: { - 'Query.listTodos.req.vtl': '## [Start] List Request. **\n' + '#set( $limit = $util.defaultIfNull($context.args.limit, 100) )\n', - }, - pipelineFunctions: {}, - functions: {}, - schema: '', - stackMapping: {}, - stacks: {}, - rootStack: { - Parameters: {}, - Resources: {}, - }, - } as DeploymentResources; - }); - - describe('writeDeploymentToDisk', () => { - it('executes the CFN pre-push processor on nested api stacks before writing to disk', async () => { - transformerOutput.stacks['TestStack'] = { Resources: { TestResource: { Type: 'testtest' } } }; - transformerOutput.resolvers = {}; - let hasTransformedTemplate = false; - let hasWrittenTransformedTemplate = false; - prePushCfnTemplateModifier_mock.mockImplementation(async () => { - hasTransformedTemplate = true; - }); - fs_mock.writeFileSync.mockImplementation((filepath) => { - if (typeof filepath === 'string' && filepath.includes(`${path.sep}stacks${path.sep}`)) { - if (hasTransformedTemplate) { - hasWrittenTransformedTemplate = true; - } else { - throw new Error('prePushCfnTemplateModifier was not applied to template before writing to disk'); - } - } - }); - - const context = { amplify: {} } as unknown as $TSContext; - await writeDeploymentToDisk(context, transformerOutput, path.join('test', 'deployment'), undefined, {}); - expect(hasWrittenTransformedTemplate).toBe(true); - }); - }); - - describe('mergeUserConfigWithTransformOutput', () => { - describe('has user created functions', () => { - beforeAll(() => { - userConfig = { - schema: '', - functions: { - userFn: 'userFn()', - }, - pipelineFunctions: {}, - resolvers: {}, - stacks: {}, - dataSourceStrategies: {}, - config: { Version: 5, ElasticsearchWarning: true }, - } as TransformerProjectConfig; - }); - - it('merges function with transform output functions', () => { - const { functions } = mergeUserConfigWithTransformOutput(userConfig, transformerOutput); - - expect(functions['userFn']).toEqual('userFn()'); - }); - }); - - describe('has user-created resolvers', () => { - beforeAll(() => { - userConfig = { - schema: '', - functions: {}, - pipelineFunctions: {}, - resolvers: { - 'Query.listTodos.req.vtl': '$util.unauthorized\n', - }, - stacks: {}, - dataSourceStrategies: {}, - config: { Version: 5, ElasticsearchWarning: true }, - } as TransformerProjectConfig; - }); - - it('merges the custom resolver with transformer output', () => { - const output = mergeUserConfigWithTransformOutput(userConfig, transformerOutput); - - expect(output.resolvers['Query.listTodos.req.vtl']).toEqual('$util.unauthorized\n'); - }); - }); - - describe('has user created pipeline function', () => { - beforeAll(() => { - userConfig = { - schema: '', - functions: {}, - pipelineFunctions: { - 'Query.listTodos.req.vtl': '$util.unauthorized\n', - }, - resolvers: {}, - stacks: {}, - dataSourceStrategies: {}, - config: { Version: 5, ElasticsearchWarning: true }, - } as TransformerProjectConfig; - }); - - it('merges custom pipeline function with transformer output', () => { - const { resolvers } = mergeUserConfigWithTransformOutput(userConfig, transformerOutput); - - expect(resolvers['Query.listTodos.req.vtl']).toEqual('$util.unauthorized\n'); - }); - }); - - describe('has user created stacks', () => { - beforeAll(() => { - userConfig = { - schema: '', - functions: {}, - pipelineFunctions: {}, - resolvers: {}, - stacks: { - 'CustomResources.json': { - Resources: { - QueryCommentsForTodoResolver: { - Type: 'AWS::AppSync::Resolver', - Properties: { - ApiId: { - Ref: 'AppSyncApiId', - }, - DataSourceName: 'CommentTable', - TypeName: 'Query', - FieldName: 'commentsForTodo', - RequestMappingTemplateS3Location: { - 'Fn::Sub': [ - 's3://${S3DeploymentBucket}/${S3DeploymentRootKey}/pipelineFunctions/Query.commentsForTodo.req.vtl', - { - S3DeploymentBucket: { - Ref: 'S3DeploymentBucket', - }, - S3DeploymentRootKey: { - Ref: 'S3DeploymentRootKey', - }, - }, - ], - }, - ResponseMappingTemplateS3Location: { - 'Fn::Sub': [ - 's3://${S3DeploymentBucket}/${S3DeploymentRootKey}/pipelineFunctions/Query.commentsForTodo.res.vtl', - { - S3DeploymentBucket: { - Ref: 'S3DeploymentBucket', - }, - S3DeploymentRootKey: { - Ref: 'S3DeploymentRootKey', - }, - }, - ], - }, - }, - }, - }, - Parameters: { - AppSyncApiId: { - Type: 'String', - Description: 'The id of the AppSync API associated with this project.', - }, - AppSyncApiName: { - Type: 'String', - Description: 'The name of the AppSync API', - Default: 'AppSyncSimpleTransform', - }, - env: { - Type: 'String', - Description: 'The environment name. e.g. Dev, Test, or Production', - Default: 'NONE', - }, - S3DeploymentBucket: { - Type: 'String', - Description: 'The S3 bucket containing all deployment assets for the project.', - }, - S3DeploymentRootKey: { - Type: 'String', - Description: 'An S3 key relative to the S3DeploymentBucket that points to the root\n' + 'of the deployment directory.', - }, - }, - }, - }, - dataSourceStrategies: {}, - config: { Version: 5, ElasticsearchWarning: true }, - } as unknown as TransformerProjectConfig; - }); - - it('merges custom pipeline function with transformer output', () => { - const { stacks } = mergeUserConfigWithTransformOutput(userConfig, transformerOutput); - - expect(stacks).toEqual({ - 'CustomResources.json': { - Resources: { - QueryCommentsForTodoResolver: { - Type: 'AWS::AppSync::Resolver', - Properties: { - ApiId: { - Ref: 'AppSyncApiId', - }, - DataSourceName: 'CommentTable', - TypeName: 'Query', - FieldName: 'commentsForTodo', - RequestMappingTemplateS3Location: { - 'Fn::Sub': [ - 's3://${S3DeploymentBucket}/${S3DeploymentRootKey}/pipelineFunctions/Query.commentsForTodo.req.vtl', - { - S3DeploymentBucket: { - Ref: 'S3DeploymentBucket', - }, - S3DeploymentRootKey: { - Ref: 'S3DeploymentRootKey', - }, - }, - ], - }, - ResponseMappingTemplateS3Location: { - 'Fn::Sub': [ - 's3://${S3DeploymentBucket}/${S3DeploymentRootKey}/pipelineFunctions/Query.commentsForTodo.res.vtl', - { - S3DeploymentBucket: { - Ref: 'S3DeploymentBucket', - }, - S3DeploymentRootKey: { - Ref: 'S3DeploymentRootKey', - }, - }, - ], - }, - }, - }, - }, - Parameters: { - AppSyncApiId: { - Type: 'String', - Description: 'The id of the AppSync API associated with this project.', - }, - AppSyncApiName: { - Type: 'String', - Description: 'The name of the AppSync API', - Default: 'AppSyncSimpleTransform', - }, - env: { - Type: 'String', - Description: 'The environment name. e.g. Dev, Test, or Production', - Default: 'NONE', - }, - S3DeploymentBucket: { - Type: 'String', - Description: 'The S3 bucket containing all deployment assets for the project.', - }, - S3DeploymentRootKey: { - Type: 'String', - Description: 'An S3 key relative to the S3DeploymentBucket that points to the root\n' + 'of the deployment directory.', - }, - }, - }, - }); - }); - }); - }); - - describe('read Admin role names from custom-roles.json', () => { - const pathManagerMock = pathManager as jest.Mocked; - pathManagerMock.getResourceDirectoryPath.mockReturnValue('mockdir'); - const mockContext = { - amplify: { - getEnvInfo: () => ({ - envName: 'test', - }), - getResourceStatus: () => ({ - allResources: [], - resourcesToBeDeleted: [], - }), - }, - } as unknown as $TSContext; - - it('should return empty array if custom-roles.json does not exist', async () => { - fs_mock.existsSync.mockReturnValueOnce(false); - const adminRoles = await getAdminRoles(mockContext, 'test'); - expect(adminRoles).toEqual([]); - }); - - it('should return empty array if custom-roles.json does not contain admin roles', async () => { - const JSONUtilitiesMock = JSONUtilities as jest.Mocked; - JSONUtilitiesMock.readJson.mockReturnValueOnce({ - adminRoleNames: [], - }); - fs_mock.existsSync.mockReturnValueOnce(true); - const adminRoles = await getAdminRoles(mockContext, 'test'); - expect(adminRoles).toEqual([]); - }); - - it('should return admin roles if present as array in custom-roles.json', async () => { - const JSONUtilitiesMock = JSONUtilities as jest.Mocked; - const testRole = 'my-custom-role'; - JSONUtilitiesMock.readJson.mockReturnValueOnce({ - adminRoleNames: [testRole], - }); - fs_mock.existsSync.mockReturnValueOnce(true); - const adminRoles = await getAdminRoles(mockContext, 'test'); - expect(adminRoles).toEqual([testRole]); - }); - - it('should return admin roles if present as string in custom-roles.json', async () => { - const JSONUtilitiesMock = JSONUtilities as jest.Mocked; - const testRole = 'my-custom-role'; - JSONUtilitiesMock.readJson.mockReturnValueOnce({ - adminRoleNames: testRole, - }); - fs_mock.existsSync.mockReturnValueOnce(true); - const adminRoles = await getAdminRoles(mockContext, 'test'); - expect(adminRoles).toEqual([testRole]); - }); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/index.test.ts b/packages/amplify-category-api/src/__tests__/index.test.ts deleted file mode 100644 index a536666506..0000000000 --- a/packages/amplify-category-api/src/__tests__/index.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { InvalidDirectiveError } from 'graphql-transformer-core'; -import { transformCategoryStack } from '../index'; - -jest.mock('path'); -jest.mock('@aws-amplify/amplify-cli-core', () => ({ - ...(jest.requireActual('@aws-amplify/amplify-cli-core') as Record), - pathManager: { - getBackendDirPath: jest.fn().mockReturnValue('mockbackendDirPath'), - findProjectRoot: jest.fn().mockReturnValue('mockProject'), - }, - stateManager: { - resourceInputsJsonExists: jest.fn().mockReturnValue(true), - }, - buildOverrideDir: jest.fn().mockRejectedValueOnce(new Error('mock build dir message')).mockResolvedValueOnce(true), - AmplifySupportedService: { - APPSYNC: 'AppSync', - }, - AmplifyCategories: { - API: 'api', - }, -})); - -const mockContext: $TSContext = { - amplify: { - invokePluginMethod: jest.fn().mockRejectedValue(new InvalidDirectiveError('mock invalid directive')), - }, - input: { - options: {}, - }, -} as unknown as $TSContext; -test('throws amplify exception when building overrides failed', async () => { - await expect(() => transformCategoryStack(mockContext, { service: 'AppSync' })).rejects.toThrowError( - expect.objectContaining({ - classification: 'ERROR', - name: 'InvalidOverrideError', - link: 'https://docs.amplify.aws/cli/graphql/override/', - message: 'mock build dir message', - }), - ); -}); - -test('throws amplify error when calling compile schema', async () => { - await expect(() => transformCategoryStack(mockContext, { service: 'AppSync' })).rejects.toThrowError( - expect.objectContaining({ - classification: 'ERROR', - name: 'InvalidDirectiveError', - message: 'mock invalid directive', - }), - ); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/cfn-api-artifact-handler.test.ts.snap b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/cfn-api-artifact-handler.test.ts.snap deleted file mode 100644 index 3b9aa6928f..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/cfn-api-artifact-handler.test.ts.snap +++ /dev/null @@ -1,52 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`create artifacts creates the transform.conf.json file 1`] = ` -Array [ - "backendDirPath/api/testApiName", - Object { - "ElasticsearchWarning": true, - "Version": undefined, - }, -] -`; - -exports[`update artifacts updates additional auth if not empty 1`] = ` -Object { - "additionalAuthenticationProviders": Array [ - Object { - "authenticationType": "AWS_IAM", - }, - Object { - "apiKeyConfig": Object { - "apiKeyExpirationDate": undefined, - "apiKeyExpirationDays": undefined, - "description": undefined, - }, - "authenticationType": "API_KEY", - }, - ], - "defaultAuthentication": Object { - "apiKeyConfig": Object { - "apiKeyExpirationDays": 7, - "description": "", - }, - "authenticationType": "API_KEY", - }, -} -`; - -exports[`update artifacts updates default auth if not empty 1`] = ` -Object { - "additionalAuthenticationProviders": Array [ - Object { - "authenticationType": "AMAZON_COGNITO_USER_POOLS", - "userPoolConfig": Object { - "userPoolId": "myUserPoolId", - }, - }, - ], - "defaultAuthentication": Object { - "authenticationType": "AWS_IAM", - }, -} -`; diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/ecs-apigw-stack.test.ts.snap b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/ecs-apigw-stack.test.ts.snap deleted file mode 100644 index dd8a08fecc..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/ecs-apigw-stack.test.ts.snap +++ /dev/null @@ -1,2595 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ecs stack should generate valid CFN template 1`] = ` -Object { - "Conditions": Object { - "isAuthCondition": Object { - "Fn::And": Array [ - Object { - "Fn::Equals": Array [ - false, - true, - ], - }, - Object { - "Fn::Not": Array [ - Object { - "Fn::Equals": Array [ - "", - "", - ], - }, - ], - }, - Object { - "Fn::Not": Array [ - Object { - "Fn::Equals": Array [ - "", - "", - ], - }, - ], - }, - ], - }, - }, - "Mappings": Object { - "ServiceprincipalMap": Object { - "af-south-1": Object { - "states": "states.af-south-1.amazonaws.com", - }, - "ap-east-1": Object { - "states": "states.ap-east-1.amazonaws.com", - }, - "ap-northeast-1": Object { - "states": "states.ap-northeast-1.amazonaws.com", - }, - "ap-northeast-2": Object { - "states": "states.ap-northeast-2.amazonaws.com", - }, - "ap-northeast-3": Object { - "states": "states.ap-northeast-3.amazonaws.com", - }, - "ap-south-1": Object { - "states": "states.ap-south-1.amazonaws.com", - }, - "ap-south-2": Object { - "states": "states.ap-south-2.amazonaws.com", - }, - "ap-southeast-1": Object { - "states": "states.ap-southeast-1.amazonaws.com", - }, - "ap-southeast-2": Object { - "states": "states.ap-southeast-2.amazonaws.com", - }, - "ap-southeast-3": Object { - "states": "states.ap-southeast-3.amazonaws.com", - }, - "ap-southeast-4": Object { - "states": "states.ap-southeast-4.amazonaws.com", - }, - "ca-central-1": Object { - "states": "states.ca-central-1.amazonaws.com", - }, - "cn-north-1": Object { - "states": "states.cn-north-1.amazonaws.com", - }, - "cn-northwest-1": Object { - "states": "states.cn-northwest-1.amazonaws.com", - }, - "eu-central-1": Object { - "states": "states.eu-central-1.amazonaws.com", - }, - "eu-central-2": Object { - "states": "states.eu-central-2.amazonaws.com", - }, - "eu-north-1": Object { - "states": "states.eu-north-1.amazonaws.com", - }, - "eu-south-1": Object { - "states": "states.eu-south-1.amazonaws.com", - }, - "eu-south-2": Object { - "states": "states.eu-south-2.amazonaws.com", - }, - "eu-west-1": Object { - "states": "states.eu-west-1.amazonaws.com", - }, - "eu-west-2": Object { - "states": "states.eu-west-2.amazonaws.com", - }, - "eu-west-3": Object { - "states": "states.eu-west-3.amazonaws.com", - }, - "il-central-1": Object { - "states": "states.il-central-1.amazonaws.com", - }, - "me-central-1": Object { - "states": "states.me-central-1.amazonaws.com", - }, - "me-south-1": Object { - "states": "states.me-south-1.amazonaws.com", - }, - "sa-east-1": Object { - "states": "states.sa-east-1.amazonaws.com", - }, - "us-east-1": Object { - "states": "states.us-east-1.amazonaws.com", - }, - "us-east-2": Object { - "states": "states.us-east-2.amazonaws.com", - }, - "us-gov-east-1": Object { - "states": "states.us-gov-east-1.amazonaws.com", - }, - "us-gov-west-1": Object { - "states": "states.us-gov-west-1.amazonaws.com", - }, - "us-iso-east-1": Object { - "states": "states.amazonaws.com", - }, - "us-iso-west-1": Object { - "states": "states.amazonaws.com", - }, - "us-isob-east-1": Object { - "states": "states.amazonaws.com", - }, - "us-west-1": Object { - "states": "states.us-west-1.amazonaws.com", - }, - "us-west-2": Object { - "states": "states.us-west-2.amazonaws.com", - }, - }, - }, - "Outputs": Object { - "ApiName": Object { - "Value": "testApi", - }, - "ClusterName": Object { - "Value": Object { - "Ref": "NetworkStackClusterName", - }, - }, - "ContainerNames": Object { - "Value": "testContainer", - }, - "PipelineName": Object { - "Value": Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Ref": "rootStackName", - }, - "-testApi-service-testExposedContainer-12345", - ], - ], - }, - }, - "RootUrl": Object { - "Value": Object { - "Fn::GetAtt": Array [ - "Api", - "ApiEndpoint", - ], - }, - }, - "ServiceName": Object { - "Value": "testApi-service-testExposedContainer-12345", - }, - }, - "Parameters": Object { - "NetworkStackCloudMapNamespaceId": Object { - "Type": "String", - }, - "NetworkStackClusterName": Object { - "Type": "String", - }, - "NetworkStackSubnetIds": Object { - "Type": "CommaDelimitedList", - }, - "NetworkStackVpcCidrBlock": Object { - "Type": "String", - }, - "NetworkStackVpcId": Object { - "Type": "String", - }, - "NetworkStackVpcLinkId": Object { - "Type": "String", - }, - "ParamZipPath": Object { - "Default": "", - "Type": "String", - }, - "awaiterS3Key": Object { - "Default": "custom-resource-pipeline-awaiter-18.zip", - "Type": "String", - }, - "deploymentBucketName": Object { - "Type": "String", - }, - "domain": Object { - "Default": "", - "Type": "String", - }, - "env": Object { - "Type": "String", - }, - "restrictAccess": Object { - "AllowedValues": Array [ - "true", - "false", - ], - "Default": "false", - "Type": "String", - }, - "rootStackName": Object { - "Type": "String", - }, - "storagepostsArn": Object { - "Type": "String", - }, - "storagepostsName": Object { - "Type": "String", - }, - "storagepostsStreamArn": Object { - "Type": "String", - }, - }, - "Resources": Object { - "ANYIntegration": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "Api", - }, - "ConnectionId": Object { - "Ref": "NetworkStackVpcLinkId", - }, - "ConnectionType": "VPC_LINK", - "IntegrationMethod": "ANY", - "IntegrationType": "HTTP_PROXY", - "IntegrationUri": Object { - "Fn::GetAtt": Array [ - "CloudmapService", - "Arn", - ], - }, - "PayloadFormatVersion": "1.0", - }, - "Type": "AWS::ApiGatewayV2::Integration", - }, - "Api": Object { - "Properties": Object { - "CorsConfiguration": Object { - "AllowHeaders": Array [ - "*", - ], - "AllowMethods": Array [ - "DELETE", - "GET", - "HEAD", - "OPTIONS", - "PATCH", - "POST", - "PUT", - ], - "AllowOrigins": Array [ - "*", - ], - }, - "Name": Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Ref": "rootStackName", - }, - "-testApi", - ], - ], - }, - "ProtocolType": "HTTP", - }, - "Type": "AWS::ApiGatewayV2::Api", - }, - "ApiPipelineCodeBuildProject117EE1BE": Object { - "Properties": Object { - "Artifacts": Object { - "Type": "CODEPIPELINE", - }, - "Cache": Object { - "Type": "NO_CACHE", - }, - "EncryptionKey": "alias/aws/s3", - "Environment": Object { - "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:4.0", - "ImagePullCredentialsType": "CODEBUILD", - "PrivilegedMode": true, - "Type": "LINUX_CONTAINER", - }, - "ServiceRole": Object { - "Fn::GetAtt": Array [ - "ApiPipelineCodeBuildProjectRoleCFB98631", - "Arn", - ], - }, - "Source": Object { - "Type": "CODEPIPELINE", - }, - }, - "Type": "AWS::CodeBuild::Project", - }, - "ApiPipelineCodeBuildProjectRoleCFB98631": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "codebuild.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "ApiPipelineCodeBuildProjectRoleDefaultPolicyAF1730E7": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":logs:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":log-group:/aws/codebuild/", - Object { - "Ref": "ApiPipelineCodeBuildProject117EE1BE", - }, - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":logs:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":log-group:/aws/codebuild/", - Object { - "Ref": "ApiPipelineCodeBuildProject117EE1BE", - }, - ":*", - ], - ], - }, - ], - }, - Object { - "Action": Array [ - "codebuild:CreateReportGroup", - "codebuild:CreateReport", - "codebuild:UpdateReport", - "codebuild:BatchPutTestCases", - "codebuild:BatchPutCodeCoverages", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":codebuild:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":report-group/", - Object { - "Ref": "ApiPipelineCodeBuildProject117EE1BE", - }, - "-*", - ], - ], - }, - }, - Object { - "Action": Array [ - "ecr:GetAuthorizationToken", - "ecr:BatchGetImage", - "ecr:GetDownloadUrlForLayer", - "ecr:InitiateLayerUpload", - "ecr:BatchCheckLayerAvailability", - "ecr:UploadLayerPart", - "ecr:CompleteLayerUpload", - "ecr:PutImage", - ], - "Effect": "Allow", - "Resource": "*", - }, - Object { - "Action": Array [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*", - "s3:PutObject", - "s3:PutObjectLegalHold", - "s3:PutObjectRetention", - "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":s3:::", - Object { - "Ref": "deploymentBucketName", - }, - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":s3:::", - Object { - "Ref": "deploymentBucketName", - }, - "/*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "ApiPipelineCodeBuildProjectRoleDefaultPolicyAF1730E7", - "Roles": Array [ - Object { - "Ref": "ApiPipelineCodeBuildProjectRoleCFB98631", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "ApiPipelinePipeline68596884": Object { - "DependsOn": Array [ - "ApiPipelinePipelineRoleDefaultPolicyB3AD67CF", - "ApiPipelinePipelineRole8C805448", - "Service", - ], - "Properties": Object { - "ArtifactStore": Object { - "Location": Object { - "Ref": "deploymentBucketName", - }, - "Type": "S3", - }, - "Name": Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Ref": "rootStackName", - }, - "-testApi-service-testExposedContainer-12345", - ], - ], - }, - "RoleArn": Object { - "Fn::GetAtt": Array [ - "ApiPipelinePipelineRole8C805448", - "Arn", - ], - }, - "Stages": Array [ - Object { - "Actions": Array [ - Object { - "ActionTypeId": Object { - "Category": "Source", - "Owner": "AWS", - "Provider": "S3", - "Version": "1", - }, - "Configuration": Object { - "S3Bucket": Object { - "Ref": "deploymentBucketName", - }, - "S3ObjectKey": Object { - "Ref": "ParamZipPath", - }, - }, - "Name": "Source", - "OutputArtifacts": Array [ - Object { - "Name": "SourceArtifact", - }, - ], - "RoleArn": Object { - "Fn::GetAtt": Array [ - "ApiPipelinePipelineSourceCodePipelineActionRole59037A7A", - "Arn", - ], - }, - "RunOrder": 1, - }, - ], - "Name": "Source", - }, - Object { - "Actions": Array [ - Object { - "ActionTypeId": Object { - "Category": "Build", - "Owner": "AWS", - "Provider": "CodeBuild", - "Version": "1", - }, - "Configuration": Object { - "EnvironmentVariables": Object { - "Fn::Join": Array [ - "", - Array [ - "[{\\"name\\":\\"AWS_ACCOUNT_ID\\",\\"type\\":\\"PLAINTEXT\\",\\"value\\":\\"", - Object { - "Ref": "AWS::AccountId", - }, - "\\"}]", - ], - ], - }, - "ProjectName": Object { - "Ref": "ApiPipelineCodeBuildProject117EE1BE", - }, - }, - "InputArtifacts": Array [ - Object { - "Name": "SourceArtifact", - }, - ], - "Name": "Build", - "OutputArtifacts": Array [ - Object { - "Name": "BuildArtifact", - }, - ], - "RoleArn": Object { - "Fn::GetAtt": Array [ - "ApiPipelinePipelineBuildCodePipelineActionRole04E6F13B", - "Arn", - ], - }, - "RunOrder": 1, - }, - ], - "Name": "Build", - }, - Object { - "Actions": Array [ - Object { - "ActionTypeId": Object { - "Category": "Invoke", - "Owner": "AWS", - "Provider": "Lambda", - "Version": "1", - }, - "Configuration": Object { - "FunctionName": Object { - "Ref": "PreDeployLambdaF7CAA99F", - }, - }, - "Name": "Predeploy", - "RoleArn": Object { - "Fn::GetAtt": Array [ - "ApiPipelinePipelinePredeployCodePipelineActionRole387C06F4", - "Arn", - ], - }, - "RunOrder": 1, - }, - ], - "Name": "Predeploy", - }, - Object { - "Actions": Array [ - Object { - "ActionTypeId": Object { - "Category": "Deploy", - "Owner": "AWS", - "Provider": "ECS", - "Version": "1", - }, - "Configuration": Object { - "ClusterName": Object { - "Ref": "NetworkStackClusterName", - }, - "ServiceName": "testApi-service-testExposedContainer-12345", - }, - "InputArtifacts": Array [ - Object { - "Name": "BuildArtifact", - }, - ], - "Name": "Deploy", - "RoleArn": Object { - "Fn::GetAtt": Array [ - "EcsDeployActionRole15B757E5", - "Arn", - ], - }, - "RunOrder": 1, - }, - ], - "Name": "Deploy", - }, - ], - }, - "Type": "AWS::CodePipeline::Pipeline", - }, - "ApiPipelinePipelineBuildCodePipelineActionRole04E6F13B": Object { - "DependsOn": Array [ - "Service", - ], - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::", - Object { - "Ref": "AWS::AccountId", - }, - ":root", - ], - ], - }, - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "ApiPipelinePipelineBuildCodePipelineActionRoleDefaultPolicy821C7A3A": Object { - "DependsOn": Array [ - "Service", - ], - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "codebuild:BatchGetBuilds", - "codebuild:StartBuild", - "codebuild:StopBuild", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "ApiPipelineCodeBuildProject117EE1BE", - "Arn", - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "ApiPipelinePipelineBuildCodePipelineActionRoleDefaultPolicy821C7A3A", - "Roles": Array [ - Object { - "Ref": "ApiPipelinePipelineBuildCodePipelineActionRole04E6F13B", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "ApiPipelinePipelinePredeployCodePipelineActionRole387C06F4": Object { - "DependsOn": Array [ - "Service", - ], - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::", - Object { - "Ref": "AWS::AccountId", - }, - ":root", - ], - ], - }, - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "ApiPipelinePipelinePredeployCodePipelineActionRoleDefaultPolicy715F96BC": Object { - "DependsOn": Array [ - "Service", - ], - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "lambda:ListFunctions", - "Effect": "Allow", - "Resource": "*", - }, - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "PreDeployLambdaF7CAA99F", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "PreDeployLambdaF7CAA99F", - "Arn", - ], - }, - ":*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "ApiPipelinePipelinePredeployCodePipelineActionRoleDefaultPolicy715F96BC", - "Roles": Array [ - Object { - "Ref": "ApiPipelinePipelinePredeployCodePipelineActionRole387C06F4", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "ApiPipelinePipelineRole8C805448": Object { - "DependsOn": Array [ - "Service", - ], - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "codepipeline.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "ApiPipelinePipelineRoleDefaultPolicyB3AD67CF": Object { - "DependsOn": Array [ - "Service", - ], - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*", - "s3:DeleteObject*", - "s3:PutObject", - "s3:PutObjectLegalHold", - "s3:PutObjectRetention", - "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":s3:::", - Object { - "Ref": "deploymentBucketName", - }, - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":s3:::", - Object { - "Ref": "deploymentBucketName", - }, - "/*", - ], - ], - }, - ], - }, - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "ApiPipelinePipelineSourceCodePipelineActionRole59037A7A", - "Arn", - ], - }, - }, - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "ApiPipelinePipelineBuildCodePipelineActionRole04E6F13B", - "Arn", - ], - }, - }, - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "ApiPipelinePipelinePredeployCodePipelineActionRole387C06F4", - "Arn", - ], - }, - }, - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": Object { - "Fn::GetAtt": Array [ - "EcsDeployActionRole15B757E5", - "Arn", - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "ApiPipelinePipelineRoleDefaultPolicyB3AD67CF", - "Roles": Array [ - Object { - "Ref": "ApiPipelinePipelineRole8C805448", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "ApiPipelinePipelineSourceCodePipelineActionRole59037A7A": Object { - "DependsOn": Array [ - "Service", - ], - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::", - Object { - "Ref": "AWS::AccountId", - }, - ":root", - ], - ], - }, - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "ApiPipelinePipelineSourceCodePipelineActionRoleDefaultPolicyE5B48B86": Object { - "DependsOn": Array [ - "Service", - ], - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":s3:::", - Object { - "Ref": "deploymentBucketName", - }, - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":s3:::", - Object { - "Ref": "deploymentBucketName", - }, - "/", - Object { - "Ref": "ParamZipPath", - }, - ], - ], - }, - ], - }, - Object { - "Action": Array [ - "s3:DeleteObject*", - "s3:PutObject", - "s3:PutObjectLegalHold", - "s3:PutObjectRetention", - "s3:PutObjectTagging", - "s3:PutObjectVersionTagging", - "s3:Abort*", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":s3:::", - Object { - "Ref": "deploymentBucketName", - }, - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":s3:::", - Object { - "Ref": "deploymentBucketName", - }, - "/*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "ApiPipelinePipelineSourceCodePipelineActionRoleDefaultPolicyE5B48B86", - "Roles": Array [ - Object { - "Ref": "ApiPipelinePipelineSourceCodePipelineActionRole59037A7A", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "Authorizer": Object { - "Condition": "isAuthCondition", - "Properties": Object { - "ApiId": Object { - "Ref": "Api", - }, - "AuthorizerType": "JWT", - "IdentitySource": Array [ - "$request.header.Authorization", - ], - "JwtConfiguration": Object { - "Audience": Array [], - "Issuer": Object { - "Fn::Join": Array [ - "", - Array [ - "https://cognito-idp.", - Object { - "Ref": "AWS::Region", - }, - ".amazonaws.com/", - ], - ], - }, - }, - "Name": "testApiAuthorizer", - }, - "Type": "AWS::ApiGatewayV2::Authorizer", - }, - "AwaiterCustomCompleteHandler21A45EDC": Object { - "DependsOn": Array [ - "AwaiterCustomCompleteHandlerServiceRoleDefaultPolicyB6596557", - "AwaiterCustomCompleteHandlerServiceRoleFFF75973", - ], - "Properties": Object { - "Code": Object { - "ZipFile": "const { CloudFormation } = require('@aws-sdk/client-cloudformation'); -const { CodePipeline } = require('@aws-sdk/client-codepipeline'); - -const stageName = 'Source'; -const actionName = 'Source'; - -const codePipeline = new CodePipeline(); -const cloudFormation = new CloudFormation(); - -exports.handler = async function({ RequestType, ResourceProperties, StackId }) { - const { pipelineName, artifactBucketName, artifactKey, deploymentMechanism } = ResourceProperties; - - console.log('Properties', ResourceProperties); - - switch (RequestType) { - case 'Delete': - return { IsComplete: true }; - case 'Update': - const [, StackName] = StackId.split('/'); - const { Stacks } = await cloudFormation.describeStacks({ StackName }); - const [{ StackStatus }] = Stacks; - - if (StackStatus.includes('ROLLBACK')) { - return { IsComplete: true }; - } - } - - let stages; - - try { - const { pipeline } = await codePipeline.getPipeline({ name: pipelineName }); - - ({ stages } = pipeline); - } catch (error) { - const { code } = error; - - switch (code) { - case 'PipelineNotFoundException': - console.warn(error); - - return { - IsComplete: false, - }; - default: - throw error; - } - } - - const stage = stages.find(({ name }) => name === stageName); - - if (stage === undefined) { - throw new Error(\`There is no stage named \\"\${stageName}\\" in the \\"\${pipelineName}\\" pipeline\`); - } - - const action = stage.actions.find(({ name }) => name === actionName); - - if (action === undefined) { - throw new Error(\`There is no action named \\"\${actionName}\\" in the \\"\${stageName}\\" stage of the \\"\${pipelineName}\\" pipeline\`); - } - - const { - configuration, - configuration: { S3Bucket, S3ObjectKey }, - } = action; - - if (deploymentMechanism === 'FULLY_MANAGED') { - if (S3Bucket !== artifactBucketName || S3ObjectKey !== artifactKey) { - console.warn( - \`Bucket \\"\${artifactBucketName}\\" and key \\"\${artifactKey}\\" dont match the \\"\${actionName}\\" action configuration \${JSON.stringify( - configuration, - )}\`, - ); - - return { - IsComplete: false, - }; - } - } - - let execution; - - try { - const { pipelineExecutionSummaries } = await codePipeline.listPipelineExecutions({ pipelineName }); - - [execution] = pipelineExecutionSummaries; - } catch (error) { - console.warn(error); - - return { - IsComplete: false, - }; - } - - console.log(execution); - - const { status } = execution || {}; - - let IsComplete = false; - - switch (status) { - case 'Failed': - case 'Stopped': - throw new Error(\\"The execution didn't succeed\\"); - case 'Succeeded': - IsComplete = true; - } - - return { IsComplete }; -}; -", - }, - "Handler": "index.handler", - "Role": Object { - "Fn::GetAtt": Array [ - "AwaiterCustomCompleteHandlerServiceRoleFFF75973", - "Arn", - ], - }, - "Runtime": "nodejs18.x", - "Timeout": 15, - }, - "Type": "AWS::Lambda::Function", - }, - "AwaiterCustomCompleteHandlerServiceRoleDefaultPolicyB6596557": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "codepipeline:GetPipeline", - "codepipeline:ListPipelineExecutions", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":codepipeline:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "ApiPipelinePipeline68596884", - }, - ], - ], - }, - }, - Object { - "Action": "cloudformation:DescribeStacks", - "Effect": "Allow", - "Resource": Object { - "Ref": "AWS::StackId", - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "AwaiterCustomCompleteHandlerServiceRoleDefaultPolicyB6596557", - "Roles": Array [ - Object { - "Ref": "AwaiterCustomCompleteHandlerServiceRoleFFF75973", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "AwaiterCustomCompleteHandlerServiceRoleFFF75973": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "lambda.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "ManagedPolicyArns": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", - ], - ], - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "AwaiterCustomEventHandler8B7CBA73": Object { - "DependsOn": Array [ - "AwaiterCustomEventHandlerServiceRoleCC4D5DBF", - ], - "Properties": Object { - "Code": Object { - "ZipFile": "exports.handler = async function({ RequestType, PhysicalResourceId, ResourceProperties }) { - switch (RequestType) { - case 'Delete': - case 'Update': - return { PhysicalResourceId }; - } - - const { pipelineName } = ResourceProperties; - - const result = { - PhysicalResourceId: \`pipelineawaiter-\${pipelineName}\`, - }; - - return result; -}; -", - }, - "Handler": "index.handler", - "Role": Object { - "Fn::GetAtt": Array [ - "AwaiterCustomEventHandlerServiceRoleCC4D5DBF", - "Arn", - ], - }, - "Runtime": "nodejs18.x", - "Timeout": 15, - }, - "Type": "AWS::Lambda::Function", - }, - "AwaiterCustomEventHandlerServiceRoleCC4D5DBF": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "lambda.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "ManagedPolicyArns": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", - ], - ], - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "AwaiterMyProviderframeworkisComplete18658065": Object { - "DependsOn": Array [ - "AwaiterMyProviderframeworkisCompleteServiceRoleDefaultPolicyA36828FB", - "AwaiterMyProviderframeworkisCompleteServiceRole2C6A7CF0", - ], - "Properties": Object { - "Code": Object { - "S3Bucket": Object { - "Ref": "deploymentBucketName", - }, - "S3Key": Object { - "Ref": "awaiterS3Key", - }, - }, - "Description": "AWS CDK resource provider framework - isComplete (testEcsStack/AwaiterMyProvider)", - "Environment": Object { - "Variables": Object { - "USER_IS_COMPLETE_FUNCTION_ARN": Object { - "Fn::GetAtt": Array [ - "AwaiterCustomCompleteHandler21A45EDC", - "Arn", - ], - }, - "USER_ON_EVENT_FUNCTION_ARN": Object { - "Fn::GetAtt": Array [ - "AwaiterCustomEventHandler8B7CBA73", - "Arn", - ], - }, - }, - }, - "Handler": "framework.isComplete", - "Role": Object { - "Fn::GetAtt": Array [ - "AwaiterMyProviderframeworkisCompleteServiceRole2C6A7CF0", - "Arn", - ], - }, - "Runtime": "nodejs18.x", - "Timeout": 900, - }, - "Type": "AWS::Lambda::Function", - }, - "AwaiterMyProviderframeworkisCompleteServiceRole2C6A7CF0": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "lambda.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "ManagedPolicyArns": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", - ], - ], - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "AwaiterMyProviderframeworkisCompleteServiceRoleDefaultPolicyA36828FB": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "AwaiterCustomEventHandler8B7CBA73", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "AwaiterCustomEventHandler8B7CBA73", - "Arn", - ], - }, - ":*", - ], - ], - }, - ], - }, - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "AwaiterCustomCompleteHandler21A45EDC", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "AwaiterCustomCompleteHandler21A45EDC", - "Arn", - ], - }, - ":*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "AwaiterMyProviderframeworkisCompleteServiceRoleDefaultPolicyA36828FB", - "Roles": Array [ - Object { - "Ref": "AwaiterMyProviderframeworkisCompleteServiceRole2C6A7CF0", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "AwaiterMyProviderframeworkonEventB703D418": Object { - "DependsOn": Array [ - "AwaiterMyProviderframeworkonEventServiceRoleDefaultPolicy41437CAE", - "AwaiterMyProviderframeworkonEventServiceRole3DA490A7", - ], - "Properties": Object { - "Code": Object { - "S3Bucket": Object { - "Ref": "deploymentBucketName", - }, - "S3Key": Object { - "Ref": "awaiterS3Key", - }, - }, - "Description": "AWS CDK resource provider framework - onEvent (testEcsStack/AwaiterMyProvider)", - "Environment": Object { - "Variables": Object { - "USER_IS_COMPLETE_FUNCTION_ARN": Object { - "Fn::GetAtt": Array [ - "AwaiterCustomCompleteHandler21A45EDC", - "Arn", - ], - }, - "USER_ON_EVENT_FUNCTION_ARN": Object { - "Fn::GetAtt": Array [ - "AwaiterCustomEventHandler8B7CBA73", - "Arn", - ], - }, - "WAITER_STATE_MACHINE_ARN": Object { - "Ref": "AwaiterMyProviderwaiterstatemachineCF09BEC8", - }, - }, - }, - "Handler": "framework.onEvent", - "Role": Object { - "Fn::GetAtt": Array [ - "AwaiterMyProviderframeworkonEventServiceRole3DA490A7", - "Arn", - ], - }, - "Runtime": "nodejs18.x", - "Timeout": 900, - }, - "Type": "AWS::Lambda::Function", - }, - "AwaiterMyProviderframeworkonEventServiceRole3DA490A7": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "lambda.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "ManagedPolicyArns": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", - ], - ], - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "AwaiterMyProviderframeworkonEventServiceRoleDefaultPolicy41437CAE": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "AwaiterCustomEventHandler8B7CBA73", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "AwaiterCustomEventHandler8B7CBA73", - "Arn", - ], - }, - ":*", - ], - ], - }, - ], - }, - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "AwaiterCustomCompleteHandler21A45EDC", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "AwaiterCustomCompleteHandler21A45EDC", - "Arn", - ], - }, - ":*", - ], - ], - }, - ], - }, - Object { - "Action": "states:StartExecution", - "Effect": "Allow", - "Resource": Object { - "Ref": "AwaiterMyProviderwaiterstatemachineCF09BEC8", - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "AwaiterMyProviderframeworkonEventServiceRoleDefaultPolicy41437CAE", - "Roles": Array [ - Object { - "Ref": "AwaiterMyProviderframeworkonEventServiceRole3DA490A7", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "AwaiterMyProviderframeworkonTimeoutCC4166A7": Object { - "DependsOn": Array [ - "AwaiterMyProviderframeworkonTimeoutServiceRoleDefaultPolicyCB302F22", - "AwaiterMyProviderframeworkonTimeoutServiceRole40F88C6A", - ], - "Properties": Object { - "Code": Object { - "S3Bucket": Object { - "Ref": "deploymentBucketName", - }, - "S3Key": Object { - "Ref": "awaiterS3Key", - }, - }, - "Description": "AWS CDK resource provider framework - onTimeout (testEcsStack/AwaiterMyProvider)", - "Environment": Object { - "Variables": Object { - "USER_IS_COMPLETE_FUNCTION_ARN": Object { - "Fn::GetAtt": Array [ - "AwaiterCustomCompleteHandler21A45EDC", - "Arn", - ], - }, - "USER_ON_EVENT_FUNCTION_ARN": Object { - "Fn::GetAtt": Array [ - "AwaiterCustomEventHandler8B7CBA73", - "Arn", - ], - }, - }, - }, - "Handler": "framework.onTimeout", - "Role": Object { - "Fn::GetAtt": Array [ - "AwaiterMyProviderframeworkonTimeoutServiceRole40F88C6A", - "Arn", - ], - }, - "Runtime": "nodejs18.x", - "Timeout": 900, - }, - "Type": "AWS::Lambda::Function", - }, - "AwaiterMyProviderframeworkonTimeoutServiceRole40F88C6A": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "lambda.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "ManagedPolicyArns": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", - ], - ], - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "AwaiterMyProviderframeworkonTimeoutServiceRoleDefaultPolicyCB302F22": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "AwaiterCustomEventHandler8B7CBA73", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "AwaiterCustomEventHandler8B7CBA73", - "Arn", - ], - }, - ":*", - ], - ], - }, - ], - }, - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "AwaiterCustomCompleteHandler21A45EDC", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "AwaiterCustomCompleteHandler21A45EDC", - "Arn", - ], - }, - ":*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "AwaiterMyProviderframeworkonTimeoutServiceRoleDefaultPolicyCB302F22", - "Roles": Array [ - Object { - "Ref": "AwaiterMyProviderframeworkonTimeoutServiceRole40F88C6A", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "AwaiterMyProviderwaiterstatemachineCF09BEC8": Object { - "DependsOn": Array [ - "AwaiterMyProviderwaiterstatemachineRoleDefaultPolicy17602DC1", - "AwaiterMyProviderwaiterstatemachineRoleD2CF7945", - ], - "Properties": Object { - "DefinitionString": Object { - "Fn::Join": Array [ - "", - Array [ - "{\\"StartAt\\":\\"framework-isComplete-task\\",\\"States\\":{\\"framework-isComplete-task\\":{\\"End\\":true,\\"Retry\\":[{\\"ErrorEquals\\":[\\"States.ALL\\"],\\"IntervalSeconds\\":10,\\"MaxAttempts\\":180,\\"BackoffRate\\":1}],\\"Catch\\":[{\\"ErrorEquals\\":[\\"States.ALL\\"],\\"Next\\":\\"framework-onTimeout-task\\"}],\\"Type\\":\\"Task\\",\\"Resource\\":\\"", - Object { - "Fn::GetAtt": Array [ - "AwaiterMyProviderframeworkisComplete18658065", - "Arn", - ], - }, - "\\"},\\"framework-onTimeout-task\\":{\\"End\\":true,\\"Type\\":\\"Task\\",\\"Resource\\":\\"", - Object { - "Fn::GetAtt": Array [ - "AwaiterMyProviderframeworkonTimeoutCC4166A7", - "Arn", - ], - }, - "\\"}}}", - ], - ], - }, - "RoleArn": Object { - "Fn::GetAtt": Array [ - "AwaiterMyProviderwaiterstatemachineRoleD2CF7945", - "Arn", - ], - }, - }, - "Type": "AWS::StepFunctions::StateMachine", - }, - "AwaiterMyProviderwaiterstatemachineRoleD2CF7945": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": Object { - "Fn::FindInMap": Array [ - "ServiceprincipalMap", - Object { - "Ref": "AWS::Region", - }, - "states", - ], - }, - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "AwaiterMyProviderwaiterstatemachineRoleDefaultPolicy17602DC1": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "AwaiterMyProviderframeworkisComplete18658065", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "AwaiterMyProviderframeworkisComplete18658065", - "Arn", - ], - }, - ":*", - ], - ], - }, - ], - }, - Object { - "Action": "lambda:InvokeFunction", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::GetAtt": Array [ - "AwaiterMyProviderframeworkonTimeoutCC4166A7", - "Arn", - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Fn::GetAtt": Array [ - "AwaiterMyProviderframeworkonTimeoutCC4166A7", - "Arn", - ], - }, - ":*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "AwaiterMyProviderwaiterstatemachineRoleDefaultPolicy17602DC1", - "Roles": Array [ - Object { - "Ref": "AwaiterMyProviderwaiterstatemachineRoleD2CF7945", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "CloudmapService": Object { - "Properties": Object { - "DnsConfig": Object { - "DnsRecords": Array [ - Object { - "TTL": 60, - "Type": "SRV", - }, - ], - "NamespaceId": Object { - "Ref": "NetworkStackCloudMapNamespaceId", - }, - "RoutingPolicy": "MULTIVALUE", - }, - "Name": "testApi", - }, - "Type": "AWS::ServiceDiscovery::Service", - }, - "DefaultRoute": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "Api", - }, - "AuthorizationScopes": Array [], - "AuthorizationType": Object { - "Fn::If": Array [ - "isAuthCondition", - "JWT", - "NONE", - ], - }, - "AuthorizerId": Object { - "Fn::If": Array [ - "isAuthCondition", - Object { - "Ref": "Authorizer", - }, - "", - ], - }, - "RouteKey": "$default", - "Target": Object { - "Fn::Join": Array [ - "", - Array [ - "integrations/", - Object { - "Ref": "ANYIntegration", - }, - ], - ], - }, - }, - "Type": "AWS::ApiGatewayV2::Route", - }, - "DeploymentAwaiter": Object { - "DeletionPolicy": "Delete", - "Properties": Object { - "ServiceToken": Object { - "Fn::GetAtt": Array [ - "AwaiterMyProviderframeworkonEventB703D418", - "Arn", - ], - }, - "artifactBucketName": Object { - "Ref": "deploymentBucketName", - }, - "artifactKey": Object { - "Ref": "ParamZipPath", - }, - "pipelineName": Object { - "Ref": "ApiPipelinePipeline68596884", - }, - }, - "Type": "AWS::CloudFormation::CustomResource", - "UpdateReplacePolicy": "Delete", - }, - "EcsDeployActionRole15B757E5": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "AWS": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::", - Object { - "Ref": "AWS::AccountId", - }, - ":root", - ], - ], - }, - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "EcsDeployActionRoleDefaultPolicy0BE60A75": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "ecs:TagResource", - "Effect": "Allow", - "Resource": "*", - }, - Object { - "Action": Array [ - "ecs:DescribeServices", - "ecs:DescribeTaskDefinition", - "ecs:DescribeTasks", - "ecs:ListTasks", - "ecs:RegisterTaskDefinition", - "ecs:UpdateService", - ], - "Effect": "Allow", - "Resource": "*", - }, - Object { - "Action": "iam:PassRole", - "Condition": Object { - "StringEqualsIfExists": Object { - "iam:PassedToService": Array [ - "ec2.amazonaws.com", - "ecs-tasks.amazonaws.com", - ], - }, - }, - "Effect": "Allow", - "Resource": "*", - }, - Object { - "Action": Array [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":s3:::", - Object { - "Ref": "deploymentBucketName", - }, - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":s3:::", - Object { - "Ref": "deploymentBucketName", - }, - "/*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "EcsDeployActionRoleDefaultPolicy0BE60A75", - "Roles": Array [ - Object { - "Ref": "EcsDeployActionRole15B757E5", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "OptionsRoute": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "Api", - }, - "RouteKey": "OPTIONS /{proxy+}", - "Target": Object { - "Fn::Join": Array [ - "", - Array [ - "integrations/", - Object { - "Ref": "ANYIntegration", - }, - ], - ], - }, - }, - "Type": "AWS::ApiGatewayV2::Route", - }, - "PreDeployLambdaF7CAA99F": Object { - "DependsOn": Array [ - "PreDeployLambdaServiceRoleDefaultPolicyD9F42A87", - "PreDeployLambdaServiceRole87EE44C9", - ], - "Properties": Object { - "Code": Object { - "ZipFile": "const { CodePipeline } = require('@aws-sdk/client-codepipeline'); -const { ECS } = require('@aws-sdk/client-ecs'); - -const codepipeline = new CodePipeline(); -const ecs = new ECS(); - -const { DESIRED_COUNT: desiredCountStr, CLUSTER_NAME: cluster, SERVICE_NAME: service } = process.env; - -const desiredCount = parseInt(desiredCountStr, 10); - -exports.handler = async function({ 'CodePipeline.job': { id: jobId } }) { - await ecs.updateService({ - service, - cluster, - desiredCount, - }); - - return await codepipeline.putJobSuccessResult({ jobId }); -}; -", - }, - "Environment": Object { - "Variables": Object { - "CLUSTER_NAME": Object { - "Ref": "NetworkStackClusterName", - }, - "DESIRED_COUNT": "1", - "SERVICE_NAME": "testApi-service-testExposedContainer-12345", - }, - }, - "Handler": "index.handler", - "Role": Object { - "Fn::GetAtt": Array [ - "PreDeployLambdaServiceRole87EE44C9", - "Arn", - ], - }, - "Runtime": "nodejs18.x", - "Timeout": 15, - }, - "Type": "AWS::Lambda::Function", - }, - "PreDeployLambdaServiceRole87EE44C9": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "lambda.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "ManagedPolicyArns": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", - ], - ], - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "PreDeployLambdaServiceRoleDefaultPolicyD9F42A87": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "ecs:UpdateService", - "Effect": "Allow", - "Resource": Object { - "Ref": "Service", - }, - }, - Object { - "Action": Array [ - "codepipeline:PutJobSuccessResult", - "codepipeline:PutJobFailureResult", - ], - "Effect": "Allow", - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "PreDeployLambdaServiceRoleDefaultPolicyD9F42A87", - "Roles": Array [ - Object { - "Ref": "PreDeployLambdaServiceRole87EE44C9", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "Service": Object { - "Properties": Object { - "Cluster": Object { - "Ref": "NetworkStackClusterName", - }, - "DesiredCount": 1, - "LaunchType": "FARGATE", - "NetworkConfiguration": Object { - "AwsvpcConfiguration": Object { - "AssignPublicIp": "ENABLED", - "SecurityGroups": Array [ - Object { - "Fn::GetAtt": Array [ - "ServiceSG", - "GroupId", - ], - }, - ], - "Subnets": Object { - "Ref": "NetworkStackSubnetIds", - }, - }, - }, - "ServiceName": "testApi-service-testExposedContainer-12345", - "ServiceRegistries": Array [ - Object { - "ContainerName": "testExposedContainer", - "ContainerPort": 12345, - "RegistryArn": Object { - "Fn::GetAtt": Array [ - "CloudmapService", - "Arn", - ], - }, - }, - ], - "TaskDefinition": Object { - "Ref": "TaskDefinition", - }, - }, - "Type": "AWS::ECS::Service", - }, - "ServiceSG": Object { - "Properties": Object { - "GroupDescription": "Service SecurityGroup", - "SecurityGroupEgress": Array [ - Object { - "CidrIp": "0.0.0.0/0", - "Description": "Allow all outbound traffic by default", - "IpProtocol": "-1", - }, - ], - "SecurityGroupIngress": Array [], - "VpcId": Object { - "Ref": "NetworkStackVpcId", - }, - }, - "Type": "AWS::EC2::SecurityGroup", - }, - "Stage": Object { - "Properties": Object { - "ApiId": Object { - "Ref": "Api", - }, - "AutoDeploy": true, - "StageName": "$default", - }, - "Type": "AWS::ApiGatewayV2::Stage", - }, - "TaskDefinition": Object { - "Properties": Object { - "ContainerDefinitions": Array [ - Object { - "Command": Array [], - "EntryPoint": Array [], - "Essential": true, - "HealthCheck": Object { - "Command": Array [ - "CMD-SHELL", - "foo", - ], - "Interval": 30, - "Retries": 3, - "StartPeriod": 0, - "Timeout": 5, - }, - "Image": "testImage", - "LogConfiguration": Object { - "LogDriver": "awslogs", - "Options": Object { - "awslogs-group": Object { - "Ref": "testContainerContainerLogGroupE42C53EF", - }, - "awslogs-region": Object { - "Ref": "AWS::Region", - }, - "awslogs-stream-prefix": "ecs", - }, - }, - "Name": "testContainer", - }, - ], - "Cpu": "512", - "ExecutionRoleArn": Object { - "Fn::GetAtt": Array [ - "TaskDefinitionExecutionRole8D61C2FB", - "Arn", - ], - }, - "Family": Object { - "Fn::Join": Array [ - "", - Array [ - Object { - "Ref": "rootStackName", - }, - "-testApi", - ], - ], - }, - "Memory": "1024", - "NetworkMode": "awsvpc", - "RequiresCompatibilities": Array [ - "FARGATE", - ], - "TaskRoleArn": Object { - "Fn::GetAtt": Array [ - "TaskDefinitionTaskRoleFD40A61D", - "Arn", - ], - }, - }, - "Type": "AWS::ECS::TaskDefinition", - }, - "TaskDefinitionExecutionRole8D61C2FB": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "ecs-tasks.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "TaskDefinitionExecutionRoleDefaultPolicy1F3406F5": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "logs:CreateLogStream", - "logs:PutLogEvents", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":logs:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":log-group:", - Object { - "Ref": "testContainerContainerLogGroupE42C53EF", - }, - ":*", - ], - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "TaskDefinitionExecutionRoleDefaultPolicy1F3406F5", - "Roles": Array [ - Object { - "Ref": "TaskDefinitionExecutionRole8D61C2FB", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "TaskDefinitionTaskRoleDefaultPolicy282E8624": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "dynamodb:Get*", - "dynamodb:BatchGetItem", - "dynamodb:List*", - "dynamodb:Describe*", - "dynamodb:Scan", - "dynamodb:Query", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Ref": "storagepostsArn", - }, - Object { - "Fn::Join": Array [ - "/", - Array [ - Object { - "Ref": "storagepostsArn", - }, - "index/*", - ], - ], - }, - ], - }, - Object { - "Action": "s3:ListBucket", - "Effect": "Allow", - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "TaskDefinitionTaskRoleDefaultPolicy282E8624", - "Roles": Array [ - Object { - "Ref": "TaskDefinitionTaskRoleFD40A61D", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "TaskDefinitionTaskRoleFD40A61D": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "ecs-tasks.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - }, - "Type": "AWS::IAM::Role", - }, - "testContainerContainerLogGroupE42C53EF": Object { - "DeletionPolicy": "Delete", - "Properties": Object { - "LogGroupName": Object { - "Fn::Join": Array [ - "", - Array [ - "/ecs/", - Object { - "Ref": "rootStackName", - }, - "-testApi-testContainer", - ], - ], - }, - "RetentionInDays": 30, - }, - "Type": "AWS::Logs::LogGroup", - "UpdateReplacePolicy": "Delete", - }, - }, -} -`; diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/legacy-add-resource.test.ts.snap b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/legacy-add-resource.test.ts.snap deleted file mode 100644 index d07d099e0c..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/legacy-add-resource.test.ts.snap +++ /dev/null @@ -1,17 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`legacy add resource sets policy resource name in paths object before copying template 1`] = ` -Object { - "paths": Array [ - Object { - "name": "/some/{path}/with/{params}", - "policyResourceName": "/some/*/with/*", - }, - Object { - "name": "another/path/without/params", - "policyResourceName": "another/path/without/params", - }, - ], - "resourceName": "mockResourceName", -} -`; diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/legacy-update-resource.test.ts.snap b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/legacy-update-resource.test.ts.snap deleted file mode 100644 index f44b0a4e9b..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/legacy-update-resource.test.ts.snap +++ /dev/null @@ -1,17 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`legacy update resource sets policy resource name in paths object before copying template 1`] = ` -Object { - "paths": Array [ - Object { - "name": "/some/{path}/with/{params}", - "policyResourceName": "/some/*/with/*", - }, - Object { - "name": "another/path/without/params", - "policyResourceName": "another/path/without/params", - }, - ], - "resourceName": "mockResourceName", -} -`; diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/api-input-manager/appsync-api-input-state.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/api-input-manager/appsync-api-input-state.test.ts deleted file mode 100644 index 7dbebe5d4c..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/api-input-manager/appsync-api-input-state.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { AppsyncApiInputState } from '../../../../provider-utils/awscloudformation/api-input-manager/appsync-api-input-state'; - -jest.mock('fs-extra'); - -jest.mock('@aws-amplify/amplify-cli-core', () => ({ - ...(jest.requireActual('@aws-amplify/amplify-cli-core') as {}), - pathManager: { - getBackendDirPath: jest.fn().mockReturnValue('mockbackendDirPath'), - findProjectRoot: jest.fn().mockReturnValue('mockProject'), - }, - JSONUtilities: { - parse: JSON.parse, - readJson: jest - .fn() - .mockReturnValueOnce({ - version: 1, - serviceConfiguration: { - apiName: 'authv2migration1', - serviceName: 'AppSync', - defaultAuthType: { - mode: 'AWS_IAM', - }, - conflictResolution: {}, - additionalAuthTypes: [ - { - mode: 'API_KEY', - expirationTime: 7, - keyDescription: '', - }, - ], - }, - }) - .mockReturnValueOnce({}), - }, -})); - -const mockContext: $TSContext = { - amplify: { - getCategoryPluginInfo: (_context: $TSContext, category: string) => { - return { - packageLocation: `@aws-amplify/amplify-category-${category}`, - }; - }, - }, - input: { - options: {}, - }, -} as unknown as $TSContext; - -test('Api Input State -> validate cli payload manual payload', async () => { - const resourceName = 'mockResource'; - const apiState = new AppsyncApiInputState(mockContext, resourceName); - expect(await apiState.isCLIInputsValid()).toBe(true); -}); - -test('Api Input State -> validate cli payload manual payload to throw error', async () => { - const resourceName = 'mockResource'; - const apiState = new AppsyncApiInputState(mockContext, resourceName); - expect(apiState.isCLIInputsValid()).rejects.toThrowError(); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/apigw-input-state.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/apigw-input-state.test.ts deleted file mode 100644 index c4345e19aa..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/apigw-input-state.test.ts +++ /dev/null @@ -1,239 +0,0 @@ -import { $TSContext, getMigrateResourceMessageForOverride, JSONUtilities, pathManager, stateManager } from '@aws-amplify/amplify-cli-core'; -import { prompter } from '@aws-amplify/amplify-prompts'; -import * as fs from 'fs-extra'; -import { ApigwInputState } from '../../../provider-utils/awscloudformation/apigw-input-state'; - -jest.mock('@aws-amplify/amplify-cli-core'); -jest.mock('fs-extra'); -jest.mock('path'); -jest.mock('../../../provider-utils/awscloudformation/cdk-stack-builder'); - -const fs_mock = fs as jest.Mocked; -const JSONUtilities_mock = JSONUtilities as jest.Mocked; -const pathManager_mock = pathManager as jest.Mocked; -const prompter_mock = prompter as jest.Mocked; -const stateManager_mock = stateManager as jest.Mocked; - -const context_mock = { - amplify: { - updateamplifyMetaAfterResourceAdd: jest.fn(), - updateamplifyMetaAfterResourceUpdate: jest.fn(), - }, -} as unknown as $TSContext; - -pathManager_mock.findProjectRoot = jest.fn().mockReturnValue('mockProjRoot'); - -describe('REST API input state', () => { - afterEach(() => jest.clearAllMocks()); - - it('generates expected artifacts when adding a REST API', async () => { - const mockApiPaths = { - '/mock': { - permissions: { - setting: 'open', - }, - lambdaFunction: 'mockLambda', - }, - }; - - const inputState = new ApigwInputState(context_mock); - await expect( - inputState.addApigwResource((async () => ({ answers: { paths: mockApiPaths, resourceName: 'mockApi' } } as any))(), {}), - ).resolves.toEqual('mockApi'); - - expect(stateManager_mock.setResourceInputsJson).toHaveBeenCalledWith('mockProjRoot', 'api', 'mockApi', { - version: 1, - paths: mockApiPaths, - }); - expect(stateManager_mock.setResourceParametersJson).toHaveBeenCalled(); - expect(context_mock.amplify.updateamplifyMetaAfterResourceAdd).toHaveBeenCalled(); - }); - - it('generates expected artifacts when updating a REST API', async () => { - const mockApiPaths = { - '/mock': { - permissions: { - setting: 'private', - auth: ['create', 'read'], - }, - lambdaFunction: 'mockLambda', - }, - }; - - const inputState = new ApigwInputState(context_mock); - await expect( - inputState.updateApigwResource((async () => ({ answers: { paths: mockApiPaths, resourceName: 'mockApi' } } as any))()), - ).resolves.toEqual('mockApi'); - - expect(stateManager_mock.setResourceInputsJson).toHaveBeenCalledWith('mockProjRoot', 'api', 'mockApi', { - version: 1, - paths: mockApiPaths, - }); - expect(stateManager_mock.setResourceParametersJson).toHaveBeenCalled(); - expect(context_mock.amplify.updateamplifyMetaAfterResourceUpdate).toHaveBeenCalled(); - }); - - it('generates expected artifacts when choosing to migrate a REST API', async () => { - const mockDeprecatedParams = { - paths: [ - { - name: '/mock', - lambdaFunction: 'mockLambda', - privacy: { - private: true, - auth: ['/GET'], - }, - policyResourceName: '/mock', - }, - ], - resourceName: 'mockApi', - apiName: 'mockApi', - functionArns: [ - { - lambdaFunction: 'mockLambda', - }, - ], - privacy: { - auth: 1, - unauth: 0, - authRoleName: 'mockauthRole', - unAuthRoleName: 'mockunauthRole', - }, - dependsOn: [ - { - category: 'function', - resourceName: 'mockLambda', - attributes: ['Name', 'Arn'], - }, - ], - }; - - const mockApiPaths = { - '/mock': { - permissions: { - setting: 'private', - auth: ['read'], - }, - lambdaFunction: 'mockLambda', - }, - }; - - prompter_mock.yesOrNo = jest.fn().mockResolvedValueOnce(true); // yes to migration - JSONUtilities_mock.readJson = jest.fn().mockReturnValueOnce(mockDeprecatedParams); - - const inputState = new ApigwInputState(context_mock); - await inputState.migrateApigwResource('mockApi'); - - expect(getMigrateResourceMessageForOverride).toHaveBeenCalled(); - expect(stateManager_mock.setResourceInputsJson).toHaveBeenCalledWith('mockProjRoot', 'api', 'mockApi', { - version: 1, - paths: mockApiPaths, - }); - expect(stateManager_mock.setResourceParametersJson).toHaveBeenCalled(); - expect(fs_mock.removeSync).toHaveBeenCalledTimes(3); - }); - - it('does nothing when choosing NOT to migrate a REST API', async () => { - const inputState = new ApigwInputState(context_mock); - - prompter_mock.yesOrNo = jest.fn().mockResolvedValueOnce(false); // no to migration - - await inputState.migrateApigwResource('mockApi'); - - expect(getMigrateResourceMessageForOverride).toHaveBeenCalled(); - expect(stateManager_mock.setResourceInputsJson).not.toHaveBeenCalled(); - expect(stateManager_mock.setResourceParametersJson).not.toHaveBeenCalled(); - expect(context_mock.amplify.updateamplifyMetaAfterResourceUpdate).not.toHaveBeenCalled(); - expect(fs_mock.removeSync).not.toHaveBeenCalled(); - }); - - it('generates expected artifacts when choosing to migrate an Admin Queries API', async () => { - prompter_mock.yesOrNo = jest.fn().mockResolvedValueOnce(true); // yes to migration - - const inputState = new ApigwInputState(context_mock); - await inputState.migrateAdminQueries({ - apiName: 'AdminQueries', - authResourceName: 'mockCognito', - functionName: 'mockLambda', - dependsOn: [], - }); - - expect(getMigrateResourceMessageForOverride).toHaveBeenCalled(); - expect(stateManager_mock.setResourceInputsJson).toHaveBeenCalled(); - expect(stateManager_mock.setResourceParametersJson).toHaveBeenCalled(); - expect(fs_mock.removeSync).toHaveBeenCalledTimes(2); - }); - - it('does nothing when choosing NOT to migrate an Admin Queries API', async () => { - const inputState = new ApigwInputState(context_mock); - - prompter_mock.yesOrNo = jest.fn().mockResolvedValueOnce(false); // no to migration - - await inputState.migrateAdminQueries({ - apiName: 'AdminQueries', - authResourceName: 'mockCognito', - functionName: 'mockLambda', - dependsOn: [], - }); - - expect(getMigrateResourceMessageForOverride).toHaveBeenCalled(); - expect(stateManager_mock.setResourceInputsJson).not.toHaveBeenCalled(); - expect(stateManager_mock.setResourceParametersJson).not.toHaveBeenCalled(); - expect(context_mock.amplify.updateamplifyMetaAfterResourceUpdate).not.toHaveBeenCalled(); - expect(fs_mock.removeSync).not.toHaveBeenCalled(); - }); - - it('generates expected artifacts when adding an Admin Queries API', async () => { - const inputState = new ApigwInputState(context_mock); - const mockApiPaths = { - '/{proxy+}': { - permissions: { - setting: 'private', - auth: ['create', 'read', 'update', 'delete'], - }, - lambdaFunction: 'mockLambda', - }, - }; - - await inputState.addAdminQueriesResource({ - apiName: 'AdminQueries', - authResourceName: 'mockCognito', - functionName: 'mockLambda', - dependsOn: [], - }); - - expect(stateManager_mock.setResourceInputsJson).toHaveBeenCalledWith('mockProjRoot', 'api', 'AdminQueries', { - version: 1, - paths: mockApiPaths, - }); - expect(stateManager_mock.setResourceParametersJson).toHaveBeenCalled(); - expect(context_mock.amplify.updateamplifyMetaAfterResourceAdd).toHaveBeenCalled(); - }); - - it('generates expected artifacts when updating an Admin Queries API', async () => { - const inputState = new ApigwInputState(context_mock); - const mockApiPaths = { - '/{proxy+}': { - permissions: { - setting: 'private', - auth: ['create', 'read', 'update', 'delete'], - }, - lambdaFunction: 'mockLambda', - }, - }; - - await inputState.updateAdminQueriesResource({ - apiName: 'AdminQueries', - authResourceName: 'mockCognito', - functionName: 'mockLambda', - dependsOn: [], - }); - - expect(stateManager_mock.setResourceInputsJson).toHaveBeenCalledWith('mockProjRoot', 'api', 'AdminQueries', { - version: 1, - paths: mockApiPaths, - }); - expect(stateManager_mock.setResourceParametersJson).toHaveBeenCalled(); - expect(context_mock.amplify.updateamplifyMetaAfterResourceUpdate).toHaveBeenCalled(); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cdk-stack-builder/__snapshots__/apigw-stack-builder.test.ts.snap b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cdk-stack-builder/__snapshots__/apigw-stack-builder.test.ts.snap deleted file mode 100644 index e835df7f13..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cdk-stack-builder/__snapshots__/apigw-stack-builder.test.ts.snap +++ /dev/null @@ -1,846 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`AmplifyApigwResourceStack addIamPolicyResourceForUserPoolGroup should generate correct IAM policies when {} is used in path 1`] = ` -Object { - "adminGroupbookisbnPolicy": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "execute-api:Invoke", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/POST/book/*", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/PUT/book/*", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/PATCH/book/*", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/GET/book/*", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/DELETE/book/*", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/POST/book/*/*", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/PUT/book/*/*", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/PATCH/book/*/*", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/GET/book/*/*", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/DELETE/book/*/*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "mockRestAPIName-bookisbn-admin-group-policy", - "Roles": Array [ - Object { - "Fn::Join": Array [ - "-", - Array [ - Object { - "Ref": "mockAuthRoleLogicalId", - }, - "adminGroupRole", - ], - ], - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "adminGroupitemsidfoobarPolicy": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "execute-api:Invoke", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/POST/items/*/foobar", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/PUT/items/*/foobar", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/PATCH/items/*/foobar", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/GET/items/*/foobar", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/DELETE/items/*/foobar", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/POST/items/*/foobar/*", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/PUT/items/*/foobar/*", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/PATCH/items/*/foobar/*", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/GET/items/*/foobar/*", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/DELETE/items/*/foobar/*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "mockRestAPIName-itemsidfoobar-admin-group-policy", - "Roles": Array [ - Object { - "Fn::Join": Array [ - "-", - Array [ - Object { - "Ref": "mockAuthRoleLogicalId", - }, - "adminGroupRole", - ], - ], - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "memberGroupbookisbnPolicy": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "execute-api:Invoke", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/GET/book/*", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/GET/book/*/*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "mockRestAPIName-bookisbn-member-group-policy", - "Roles": Array [ - Object { - "Fn::Join": Array [ - "-", - Array [ - Object { - "Ref": "mockAuthRoleLogicalId", - }, - "memberGroupRole", - ], - ], - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "memberGroupitemsidfoobarPolicy": Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "execute-api:Invoke", - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/GET/items/*/foobar", - ], - ], - }, - Object { - "Fn::Join": Array [ - "", - Array [ - "arn:aws:execute-api:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":", - Object { - "Ref": "mockRestAPIName", - }, - "/", - Object { - "Fn::If": Array [ - "ShouldNotCreateEnvResources", - "Prod", - Object { - "Ref": "env", - }, - ], - }, - "/GET/items/*/foobar/*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "mockRestAPIName-itemsidfoobar-member-group-policy", - "Roles": Array [ - Object { - "Fn::Join": Array [ - "-", - Array [ - Object { - "Ref": "mockAuthRoleLogicalId", - }, - "memberGroupRole", - ], - ], - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, -} -`; diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.test.ts deleted file mode 100644 index 2c82f100a1..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import * as cdk from 'aws-cdk-lib'; -import { Template } from 'aws-cdk-lib/assertions'; -import { AmplifyApigwResourceStack } from '../../../../provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder'; -import { CrudOperation, PermissionSetting } from '../../../../provider-utils/awscloudformation/cdk-stack-builder/types'; -import { convertCrudOperationsToCfnPermissions } from '../../../../provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-transform'; - -describe('AmplifyApigwResourceStack', () => { - test('generateStackResources should synthesize the way we expected', () => { - const app = new cdk.App(); - const amplifyApigwStack = new AmplifyApigwResourceStack(app, 'amplifyapigwstack', { - version: 1, - paths: { - '/path': { - lambdaFunction: 'lambdaFunction', - permissions: { - setting: PermissionSetting.OPEN, - }, - }, - }, - }); - amplifyApigwStack.generateStackResources('myapi'); - const template = Template.fromStack(amplifyApigwStack); - template.hasResourceProperties('AWS::ApiGateway::GatewayResponse', { - ResponseType: 'DEFAULT_4XX', - ResponseParameters: { - 'gatewayresponse.header.Access-Control-Allow-Origin': "'*'", - 'gatewayresponse.header.Access-Control-Allow-Headers': "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'", - 'gatewayresponse.header.Access-Control-Allow-Methods': "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'", - 'gatewayresponse.header.Access-Control-Expose-Headers': "'Date,X-Amzn-ErrorType'", - }, - RestApiId: { - Ref: 'myapi', - }, - }); - template.hasResourceProperties('AWS::ApiGateway::GatewayResponse', { - ResponseType: 'DEFAULT_5XX', - ResponseParameters: { - 'gatewayresponse.header.Access-Control-Allow-Origin': "'*'", - 'gatewayresponse.header.Access-Control-Allow-Headers': "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'", - 'gatewayresponse.header.Access-Control-Allow-Methods': "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'", - 'gatewayresponse.header.Access-Control-Expose-Headers': "'Date,X-Amzn-ErrorType'", - }, - RestApiId: { - Ref: 'myapi', - }, - }); - }); - test('addIamPolicyResourceForUserPoolGroup should generate correct IAM policies when {} is used in path', () => { - const app = new cdk.App(); - const mockResourceName = 'mockRestAPIName'; - const mockAuthRoleLogicalId = 'mockAuthRoleLogicalId'; - const cliInputs = { - version: 1, - paths: { - '/book/{isbn}': { - lambdaFunction: 'lambdaFunction1', - permissions: { - setting: PermissionSetting.PRIVATE, - groups: { - admin: [CrudOperation.CREATE, CrudOperation.UPDATE, CrudOperation.READ, CrudOperation.DELETE], - member: [CrudOperation.READ], - }, - }, - }, - '/items/{id}/foobar': { - lambdaFunction: 'lambdaFunction2', - permissions: { - setting: PermissionSetting.PRIVATE, - groups: { - admin: [CrudOperation.CREATE, CrudOperation.UPDATE, CrudOperation.READ, CrudOperation.DELETE], - member: [CrudOperation.READ], - }, - }, - }, - }, - }; - const amplifyApigwStack = new AmplifyApigwResourceStack(app, 'amplifyapigwstack', cliInputs); - const pathsWithUserPoolGroups = Object.entries(cliInputs.paths).filter(([_, path]) => !!path?.permissions?.groups); - for (const [pathName, path] of pathsWithUserPoolGroups) { - for (const [groupName, crudOps] of Object.entries(path.permissions.groups)) { - amplifyApigwStack.addIamPolicyResourceForUserPoolGroup( - mockResourceName, - mockAuthRoleLogicalId, - groupName, - pathName, - convertCrudOperationsToCfnPermissions(crudOps), - ); - } - } - - const template = Template.fromStack(amplifyApigwStack); - expect(template.findResources('AWS::IAM::Policy')).toMatchSnapshot(); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cfn-api-artifact-handler.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cfn-api-artifact-handler.test.ts deleted file mode 100644 index 910ef70473..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cfn-api-artifact-handler.test.ts +++ /dev/null @@ -1,393 +0,0 @@ -import * as path from 'path'; -import { $TSContext, pathManager } from '@aws-amplify/amplify-cli-core'; -import { AddApiRequest, UpdateApiRequest } from 'amplify-headless-interface'; -import { printer } from '@aws-amplify/amplify-prompts'; -import * as fs from 'fs-extra'; -import { writeTransformerConfiguration } from 'graphql-transformer-core'; -import _ from 'lodash'; -import { AppsyncApiInputState } from '../../../provider-utils/awscloudformation/api-input-manager/appsync-api-input-state'; -import { category } from '../../../category-constants'; -import { ApiArtifactHandler } from '../../../provider-utils/api-artifact-handler'; -import { rootAssetDir } from '../../../provider-utils/awscloudformation/aws-constants'; -import { getCfnApiArtifactHandler } from '../../../provider-utils/awscloudformation/cfn-api-artifact-handler'; -import { - authConfigHasApiKey, - getAppSyncAuthConfig, - getAppSyncResourceName, -} from '../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; - -const testAuthId = 'testAuthId'; - -jest.mock('fs-extra'); -const printerMock = printer as jest.Mocked; -printerMock.warn = jest.fn(); - -jest.mock('../../../provider-utils/awscloudformation/api-input-manager/appsync-api-input-state'); - -jest.mock('graphql-transformer-core', () => ({ - readTransformerConfiguration: jest.fn(async () => ({})), - writeTransformerConfiguration: jest.fn(), -})); - -jest.mock('../../../provider-utils/awscloudformation/utils/amplify-meta-utils', () => ({ - checkIfAuthExists: jest.fn().mockImplementation(() => testAuthId), - getAppSyncResourceName: jest.fn(() => testApiName), - getAppSyncAuthConfig: jest.fn(() => ({})), - authConfigHasApiKey: jest.fn(() => true), - getImportedAuthUserPoolId: jest.fn(() => undefined), -})); - -jest.mock('@aws-amplify/amplify-cli-core', () => ({ - ...(jest.requireActual('@aws-amplify/amplify-cli-core') as Record), - pathManager: { - getBackendDirPath: jest.fn().mockReturnValue('mockBackendDirPath'), - findProjectRoot: jest.fn().mockReturnValue('mockProject'), - }, - stateManager: { - getMeta: jest.fn().mockReturnValue({}), - getBackendConfig: jest.fn(), - }, - AmplifyCategories: { - API: 'api', - }, - AmplifySupportedService: { - APPSYNC: 'Appsync', - }, - JSONUtilities: { - readJson: jest.fn(), - writeJson: jest.fn(), - }, - isResourceNameUnique: jest.fn(), -})); - -const backendDirPathStub = 'backendDirPath'; -const testApiName = 'testApiName'; - -const pathManagerMock = pathManager as jest.Mocked; -pathManagerMock.getResourceDirectoryPath = jest.fn().mockReturnValue(`${backendDirPathStub}/api/${testApiName}`); - -const fsMock = fs as unknown as jest.Mocked; -const writeTransformerConfigurationMock = writeTransformerConfiguration as jest.MockedFunction; -const getAppSyncResourceNameMock = getAppSyncResourceName as jest.MockedFunction; -const getAppSyncAuthConfigMock = getAppSyncAuthConfig as jest.MockedFunction; -const authConfigHasApiKeyMock = authConfigHasApiKey as jest.MockedFunction; - -const contextStub = { - amplify: { - updateamplifyMetaAfterResourceAdd: jest.fn(), - updateamplifyMetaAfterResourceUpdate: jest.fn(), - updateBackendConfigAfterResourceUpdate: jest.fn(), - executeProviderUtils: jest.fn(), - copyBatch: jest.fn(), - }, -}; - -describe('create artifacts', () => { - let cfnApiArtifactHandler: ApiArtifactHandler; - const addRequestStub: AddApiRequest = { - version: 1, - serviceConfiguration: { - serviceName: 'AppSync', - apiName: testApiName, - transformSchema: 'my test schema', - defaultAuthType: { - mode: 'API_KEY', - expirationTime: 10, - keyDescription: 'api key description', - }, - }, - }; - beforeAll(() => { - fsMock.existsSync.mockImplementation(() => false); - getAppSyncResourceNameMock.mockImplementation(() => undefined); - }); - beforeEach(() => { - jest.clearAllMocks(); - cfnApiArtifactHandler = getCfnApiArtifactHandler(contextStub as unknown as $TSContext); - }); - - it('does not create a second API if one already exists', async () => { - getAppSyncResourceNameMock.mockImplementationOnce(() => testApiName); - return expect(cfnApiArtifactHandler.createArtifacts(addRequestStub)).rejects.toMatchInlineSnapshot( - '[ResourceAlreadyExistsError: GraphQL API testApiName already exists in the project]', - ); - }); - - it('creates the correct directories', async () => { - await cfnApiArtifactHandler.createArtifacts(addRequestStub); - expect(fsMock.ensureDirSync.mock.calls.length).toBe(1); - expect(fsMock.ensureDirSync.mock.calls[0][0]).toBe(path.join(backendDirPathStub, category, testApiName)); - expect(fsMock.mkdirSync.mock.calls.length).toBe(2); - expect(fsMock.mkdirSync.mock.calls[0][0]).toBe(path.join(backendDirPathStub, category, testApiName, 'resolvers')); - expect(fsMock.mkdirSync.mock.calls[1][0]).toBe(path.join(backendDirPathStub, category, testApiName, 'stacks')); - }); - - it('creates the transform.conf.json file', async () => { - await cfnApiArtifactHandler.createArtifacts(addRequestStub); - expect(writeTransformerConfigurationMock.mock.calls.length).toBe(2); - expect(writeTransformerConfigurationMock.mock.calls[0]).toMatchSnapshot(); - }); - - it('writes the default custom resources stack', async () => { - await cfnApiArtifactHandler.createArtifacts(addRequestStub); - expect(fsMock.copyFileSync.mock.calls.length).toBe(2); - expect(fsMock.copyFileSync.mock.calls[1]).toEqual([ - path.join(rootAssetDir, 'cloudformation-templates', 'defaultCustomResources.json'), - path.join(backendDirPathStub, category, addRequestStub.serviceConfiguration.apiName, 'stacks', 'CustomResources.json'), - ]); - }); - - it('creates correct cli-inputs', async () => { - jest.spyOn(AppsyncApiInputState.prototype, 'saveCLIInputPayload'); - await cfnApiArtifactHandler.createArtifacts(addRequestStub); - expect(AppsyncApiInputState.prototype.saveCLIInputPayload).toBeCalledWith({ - serviceConfiguration: { - apiName: 'testApiName', - defaultAuthType: { expirationTime: 10, keyDescription: 'api key description', mode: 'API_KEY' }, - serviceName: 'AppSync', - }, - version: 1, - }); - }); - - it('writes the selected template schema to project', async () => { - await cfnApiArtifactHandler.createArtifacts(addRequestStub); - expect(fsMock.writeFileSync.mock.calls.length).toBe(1); - expect(fsMock.writeFileSync.mock.calls[0]).toEqual([ - path.join(backendDirPathStub, category, addRequestStub.serviceConfiguration.apiName, 'schema.graphql'), - addRequestStub.serviceConfiguration.transformSchema, - ]); - }); - - it('executes compileSchema from the provider', async () => { - await cfnApiArtifactHandler.createArtifacts(addRequestStub); - expect(contextStub.amplify.executeProviderUtils.mock.calls.length).toBe(1); - expect(contextStub.amplify.executeProviderUtils.mock.calls[0][0]).toStrictEqual(contextStub); - expect(contextStub.amplify.executeProviderUtils.mock.calls[0][1]).toStrictEqual('awscloudformation'); - expect(contextStub.amplify.executeProviderUtils.mock.calls[0][2]).toStrictEqual('compileSchema'); - }); - - it('updates amplify meta', async () => { - await cfnApiArtifactHandler.createArtifacts(addRequestStub); - expect(contextStub.amplify.updateamplifyMetaAfterResourceAdd.mock.calls.length).toBe(1); - expect(contextStub.amplify.updateamplifyMetaAfterResourceAdd.mock.calls[0][0]).toStrictEqual(category); - expect(contextStub.amplify.updateamplifyMetaAfterResourceAdd.mock.calls[0][1]).toStrictEqual( - addRequestStub.serviceConfiguration.apiName, - ); - }); - - it('updates amplify meta with depends on auth if cognito specified', async () => { - const addRequestStubCognito = _.cloneDeep(addRequestStub); - addRequestStubCognito.serviceConfiguration.defaultAuthType = { - mode: 'AMAZON_COGNITO_USER_POOLS', - cognitoUserPoolId: testAuthId, - }; - await cfnApiArtifactHandler.createArtifacts(addRequestStubCognito); - expect(contextStub.amplify.updateamplifyMetaAfterResourceAdd).toHaveBeenCalledTimes(1); - expect(contextStub.amplify.updateamplifyMetaAfterResourceAdd.mock.calls[0][2].dependsOn).toEqual([ - { - category: 'auth', - resourceName: testAuthId, - attributes: ['UserPoolId'], - }, - ]); - }); - - it('returns the api name', async () => { - const result = await cfnApiArtifactHandler.createArtifacts(addRequestStub); - expect(result).toBe(addRequestStub.serviceConfiguration.apiName); - }); -}); - -describe('update artifacts', () => { - let cfnApiArtifactHandler: ApiArtifactHandler; - let updateRequestStub: UpdateApiRequest; - const updateRequestStubBase: UpdateApiRequest = { - version: 1, - serviceModification: { - serviceName: 'AppSync', - }, - }; - - beforeAll(() => { - getAppSyncResourceNameMock.mockImplementation(() => testApiName); - getAppSyncAuthConfigMock.mockImplementation(() => ({ - defaultAuthentication: { - authenticationType: 'API_KEY', - apiKeyConfig: { - apiKeyExpirationDays: 7, - description: '', - }, - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - userPoolConfig: { - userPoolId: 'myUserPoolId', - }, - }, - ], - })); - }); - - beforeEach(() => { - jest.clearAllMocks(); - updateRequestStub = _.cloneDeep(updateRequestStubBase); - cfnApiArtifactHandler = getCfnApiArtifactHandler(contextStub as unknown as $TSContext); - }); - - it('throws error if no GQL API in project', () => { - getAppSyncResourceNameMock.mockImplementationOnce(() => undefined); - return expect(cfnApiArtifactHandler.updateArtifacts(updateRequestStub)).rejects.toMatchInlineSnapshot( - '[NotImplementedError: Appsync API does not exist]', - ); - }); - - it('writes new schema if specified', async () => { - const newSchemaContents = 'a new schema'; - updateRequestStub.serviceModification.transformSchema = newSchemaContents; - jest.spyOn(AppsyncApiInputState.prototype, 'getCLIInputPayload').mockReturnValue({ - serviceConfiguration: { - apiName: 'testApiName', - defaultAuthType: { expirationTime: 10, keyDescription: 'api key description', mode: 'API_KEY' }, - serviceName: 'AppSync', - }, - version: 1, - }); - await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(fsMock.writeFileSync.mock.calls.length).toBe(1); - expect(fsMock.writeFileSync.mock.calls[0][1]).toBe(newSchemaContents); - }); - - it('updates default auth if not empty', async () => { - updateRequestStub.serviceModification.defaultAuthType = { mode: 'AWS_IAM' }; - jest.spyOn(AppsyncApiInputState.prototype, 'getCLIInputPayload').mockReturnValue({ - serviceConfiguration: { - apiName: 'testApiName', - defaultAuthType: { expirationTime: 10, keyDescription: 'api key description', mode: 'API_KEY' }, - serviceName: 'AppSync', - }, - version: 1, - }); - await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(contextStub.amplify.executeProviderUtils.mock.calls.length).toBe(1); - expect(contextStub.amplify.executeProviderUtils.mock.calls[0][3].authConfig).toMatchSnapshot(); - }); - - it('updates correct cli-inputs', async () => { - updateRequestStub.serviceModification.additionalAuthTypes = [{ mode: 'AWS_IAM' }, { mode: 'API_KEY' }]; - jest.spyOn(AppsyncApiInputState.prototype, 'saveCLIInputPayload'); - jest.spyOn(AppsyncApiInputState.prototype, 'cliInputFileExists').mockReturnValueOnce(true); - jest.spyOn(AppsyncApiInputState.prototype, 'getCLIInputPayload').mockReturnValue({ - serviceConfiguration: { - apiName: 'testApiName', - defaultAuthType: { expirationTime: 10, keyDescription: 'api key description', mode: 'API_KEY' }, - serviceName: 'AppSync', - }, - version: 1, - }); - await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(AppsyncApiInputState.prototype.saveCLIInputPayload).toBeCalledWith({ - serviceConfiguration: { - additionalAuthTypes: [{ mode: 'AWS_IAM' }, { mode: 'API_KEY' }], - apiName: 'testApiName', - defaultAuthType: { expirationTime: 10, keyDescription: 'api key description', mode: 'API_KEY' }, - serviceName: 'AppSync', - }, - version: 1, - }); - }); - - it('updates additional auth if not empty', async () => { - updateRequestStub.serviceModification.additionalAuthTypes = [{ mode: 'AWS_IAM' }, { mode: 'API_KEY' }]; - jest.spyOn(AppsyncApiInputState.prototype, 'getCLIInputPayload').mockReturnValue({ - serviceConfiguration: { - apiName: 'testApiName', - defaultAuthType: { expirationTime: 10, keyDescription: 'api key description', mode: 'API_KEY' }, - serviceName: 'AppSync', - }, - version: 1, - }); - - await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(contextStub.amplify.executeProviderUtils.mock.calls.length).toBe(1); - expect(contextStub.amplify.executeProviderUtils.mock.calls[0][3].authConfig).toMatchSnapshot(); - }); - - it('compiles the changes', async () => { - await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(contextStub.amplify.executeProviderUtils.mock.calls.length).toBe(1); - }); - - it('updates meta files after update', async () => { - await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(contextStub.amplify.updateamplifyMetaAfterResourceUpdate.mock.calls.length).toBe(2); - expect(contextStub.amplify.updateBackendConfigAfterResourceUpdate.mock.calls.length).toBe(2); - }); - - it('prints warning when adding API key auth', async () => { - authConfigHasApiKeyMock.mockImplementationOnce(() => false).mockImplementationOnce(() => true); - await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(printerMock.warn.mock.calls.length).toBe(2); - }); - - it('prints warning when removing API key auth', async () => { - authConfigHasApiKeyMock.mockImplementationOnce(() => true).mockImplementationOnce(() => false); - await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(printerMock.warn.mock.calls.length).toBe(3); - }); - - it('adds auth dependency if cognito auth specified', async () => { - getAppSyncAuthConfigMock.mockReturnValueOnce({ - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - userPoolConfig: { - userPoolId: testAuthId, - }, - }, - }); - await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(contextStub.amplify.updateamplifyMetaAfterResourceUpdate.mock.calls.length).toBe(2); - expect(contextStub.amplify.updateamplifyMetaAfterResourceUpdate.mock.calls[1][3]).toEqual([ - { - category: 'auth', - resourceName: testAuthId, - attributes: ['UserPoolId'], - }, - ]); - }); - - it('correctly updates the cli-inputs on an update that sets a NEW lambda for conflict resolution', async () => { - jest.spyOn(AppsyncApiInputState.prototype, 'saveCLIInputPayload'); - jest.spyOn(AppsyncApiInputState.prototype, 'cliInputFileExists').mockReturnValueOnce(true); - - updateRequestStub.serviceModification.conflictResolution = { - defaultResolutionStrategy: { - type: 'LAMBDA', - resolver: { - type: 'NEW', - }, - }, - }; - - await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - - const { objectContaining, stringContaining } = expect; - - expect(AppsyncApiInputState.prototype.saveCLIInputPayload).toHaveBeenCalledWith( - objectContaining({ - serviceConfiguration: objectContaining({ - conflictResolution: { - defaultResolutionStrategy: { - type: 'LAMBDA', - resolver: { - type: 'EXISTING', - name: stringContaining('syncConflictHandler'), - }, - }, - }, - }), - }), - ); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/convert-deprecated-apigw-paths.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/convert-deprecated-apigw-paths.test.ts deleted file mode 100644 index 1f8cd1e507..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/convert-deprecated-apigw-paths.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { JSONUtilities } from '@aws-amplify/amplify-cli-core'; - -jest.mock('@aws-amplify/amplify-cli-core'); - -const JSONUtilities_mock = JSONUtilities as jest.Mocked; - -import { convertDeperecatedRestApiPaths } from '../../../provider-utils/awscloudformation/convert-deprecated-apigw-paths'; - -describe('test apigw path migrate', () => { - it('migrates valid input successfully', async () => { - JSONUtilities_mock.readJson.mockReturnValueOnce({ - paths: [ - { - name: '/mockOpenPath', - lambdaFunction: 'mockOpenLambda', - privacy: { - open: true, - }, - }, - { - name: '/mockPrivatePath', - lambdaFunction: 'mockPrivateLambda', - privacy: { - auth: ['/GET', '/POST'], - private: true, - }, - }, - { - name: '/mockLegacyPath', - lambdaFunction: 'mockLegacyLambda', - privacy: { - auth: 'rw', - private: true, - }, - }, - ], - }); - - const convertedPaths = convertDeperecatedRestApiPaths('mockFileName.json', 'mock/file/path/mockFileName.json', 'mockApi'); - expect(convertedPaths).toMatchObject({ - '/mockOpenPath': { - permissions: { - setting: 'open', - }, - lambdaFunction: 'mockOpenLambda', - }, - '/mockPrivatePath': { - permissions: { - setting: 'private', - auth: ['read', 'create'], - }, - lambdaFunction: 'mockPrivateLambda', - }, - '/mockLegacyPath': { - permissions: { - setting: 'private', - auth: ['create', 'read', 'update', 'delete'], - }, - lambdaFunction: 'mockLegacyLambda', - }, - }); - }); - - it('throws on invalid input', async () => { - JSONUtilities_mock.readJson.mockReturnValueOnce({}); - expect(() => convertDeperecatedRestApiPaths('mockFileName.json', 'mock/file/path/mockFileName.json', 'mockApi')).toThrow(); - - JSONUtilities_mock.readJson.mockReturnValueOnce({ - paths: [], - }); - expect(() => convertDeperecatedRestApiPaths('mockFileName.json', 'mock/file/path/mockFileName.json', 'mockApi')).toThrow(); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/current-backend-state/searchable-node-to-node-encryption.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/current-backend-state/searchable-node-to-node-encryption.test.ts deleted file mode 100644 index ff1fbdeb61..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/current-backend-state/searchable-node-to-node-encryption.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { hasNodeToNodeEncryptionOptions } from '../../../../provider-utils/awscloudformation/current-backend-state/searchable-node-to-node-encryption'; - -describe('hasNodeToNodeEncryptionOptions', () => { - test('returns true if the search domain has NodeToNodeEncryptionOptions with value true', () => { - const definition = { - Resources: { - OpenSearchDomain: { - Properties: { - NodeToNodeEncryptionOptions: { - Enabled: true, - }, - }, - }, - }, - }; - - expect(hasNodeToNodeEncryptionOptions(definition)).toEqual(true); - }); - - test('returns false if the search domain has NodeToNodeEncryptionOptions with value false', () => { - const definition = { - Resources: { - OpenSearchDomain: { - Properties: { - NodeToNodeEncryptionOptions: { - Enabled: false, - }, - }, - }, - }, - }; - - expect(hasNodeToNodeEncryptionOptions(definition)).toEqual(false); - }); - - test('returns false if the search domain does not have NodeToNodeEncryptionOptions', () => { - const definition = { - Resources: { - OpenSearchDomain: { - Properties: {}, - }, - }, - }; - - expect(hasNodeToNodeEncryptionOptions(definition)).toEqual(false); - }); - - test('returns false if the search domain has NodeToNodeEncryptionOptions with unknown value', () => { - const definition = { - Resources: { - OpenSearchDomain: { - Properties: { - NodeToNodeEncryptionOptions: { - Enabled: '$Token-{145}', - }, - }, - }, - }, - }; - - expect(hasNodeToNodeEncryptionOptions(definition)).toEqual(false); - }); - - test('returns false if the no search domain is found', () => { - const definition = { - Resources: {}, - }; - - expect(hasNodeToNodeEncryptionOptions(definition)).toEqual(false); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/ecs-apigw-stack.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/ecs-apigw-stack.test.ts deleted file mode 100644 index 48849217ee..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/ecs-apigw-stack.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { App } from 'aws-cdk-lib'; -import Container from '../../../provider-utils/awscloudformation/docker-compose/ecs-objects/container'; -import { EcsStack } from '../../../provider-utils/awscloudformation/ecs-apigw-stack'; -import { API_TYPE } from '../../../provider-utils/awscloudformation/service-walkthroughs/containers-walkthrough'; - -describe('ecs stack', () => { - it('should generate valid CFN template', () => { - const app = new App(); - const ecsStack = new EcsStack(app, 'testEcsStack', { - apiName: 'testApi', - apiType: API_TYPE.REST, - categoryName: 'testCategory', - containers: [ - new Container(undefined, 'testContainer', [], undefined, undefined, undefined, undefined, 'testImage', { - command: 'foo', - }), - ], - currentStackName: 'testStack', - dependsOn: [ - { - attributes: ['Name', 'Arn', 'StreamArn'], - category: 'storage', - resourceName: 'posts', - }, - { - category: '', - resourceName: 'NetworkStack', - attributes: ['ClusterName', 'VpcId', 'VpcCidrBlock', 'SubnetIds', 'VpcLinkId', 'CloudMapNamespaceId'], - }, - ], - deploymentMechanism: undefined, - desiredCount: 1, - existingEcrRepositories: undefined, - exposedContainer: { - name: 'testExposedContainer', - port: 12345, - }, - isInitialDeploy: false, - restrictAccess: false, - taskPorts: [], - policies: [ - { - Effect: 'Allow', - Action: ['dynamodb:Get*', 'dynamodb:BatchGetItem', 'dynamodb:List*', 'dynamodb:Describe*', 'dynamodb:Scan', 'dynamodb:Query'], - Resource: [ - { - Ref: 'storagepostsArn', - }, - { - 'Fn::Join': [ - '/', - [ - { - Ref: 'storagepostsArn', - }, - 'index/*', - ], - ], - }, - ], - }, - { - Effect: 'Allow', - Action: 's3:ListBucket', - }, - ], - }); - - const cfn = ecsStack.toCloudFormation(); - expect(cfn).toBeDefined(); - const ecsDeployRolePolicy = findResourceWithPrefix(cfn, 'EcsDeployActionRoleDefaultPolicy'); - expect(ecsDeployRolePolicy).toBeDefined(); - expect(ecsDeployRolePolicy.Properties.PolicyDocument.Statement).toHaveLength(4); - expect(ecsDeployRolePolicy.Properties.PolicyDocument.Statement[0]).toMatchObject({ - Action: 'ecs:TagResource', - Effect: 'Allow', - Resource: '*', - }); - expect(cfn).toMatchSnapshot(); - }); - - const findResourceWithPrefix = (cfn: any, prefix: string) => { - for (const key in cfn.Resources) { - if (key.startsWith(prefix)) { - return cfn.Resources[key]; - } - } - }; -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-add-resource.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-add-resource.test.ts deleted file mode 100644 index 2fdda9d7e4..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-add-resource.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { legacyAddResource } from '../../../provider-utils/awscloudformation/legacy-add-resource'; -import { category } from '../../../category-constants'; - -jest.mock('fs-extra'); -jest.mock('@aws-amplify/amplify-cli-core', () => ({ - AmplifyCategories: { API: 'api' }, - isResourceNameUnique: jest.fn().mockReturnValue(true), - JSONUtilities: { - readJson: jest.fn(), - writeJson: jest.fn(), - }, - pathManager: { - getResourceDirectoryPath: jest.fn((_) => 'mock/backend/path'), - }, -})); - -describe('legacy add resource', () => { - const contextStub = { - amplify: { - updateamplifyMetaAfterResourceAdd: jest.fn(), - copyBatch: jest.fn(), - }, - }; - - it('sets policy resource name in paths object before copying template', async () => { - const stubWalkthroughPromise: Promise = Promise.resolve({ - answers: { - resourceName: 'mockResourceName', - paths: [ - { - name: '/some/{path}/with/{params}', - }, - { - name: 'another/path/without/params', - }, - ], - }, - }); - await legacyAddResource(stubWalkthroughPromise, contextStub as unknown as $TSContext, category, 'API Gateway', {}); - expect(contextStub.amplify.copyBatch.mock.calls[0][2]).toMatchSnapshot(); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-update-resource.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-update-resource.test.ts deleted file mode 100644 index 452c2dcd87..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-update-resource.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { legacyUpdateResource } from '../../../provider-utils/awscloudformation/legacy-update-resource'; -import { category } from '../../../category-constants'; - -jest.mock('fs-extra'); -jest.mock('@aws-amplify/amplify-cli-core', () => ({ - AmplifyCategories: { API: 'api' }, - JSONUtilities: { - readJson: jest.fn(), - writeJson: jest.fn(), - }, - pathManager: { - getResourceDirectoryPath: jest.fn((_) => 'mock/backend/path'), - }, -})); - -describe('legacy update resource', () => { - const contextStub = { - amplify: { - updateamplifyMetaAfterResourceUpdate: jest.fn(), - copyBatch: jest.fn(), - }, - }; - - it('sets policy resource name in paths object before copying template', async () => { - const stubWalkthroughPromise: Promise = Promise.resolve({ - answers: { - resourceName: 'mockResourceName', - paths: [ - { - name: '/some/{path}/with/{params}', - }, - { - name: 'another/path/without/params', - }, - ], - }, - }); - await legacyUpdateResource(stubWalkthroughPromise, contextStub as unknown as $TSContext, category, 'API Gateway'); - expect(contextStub.amplify.copyBatch.mock.calls[0][2]).toMatchSnapshot(); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/prompt-to-add-api-key.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/prompt-to-add-api-key.test.ts deleted file mode 100644 index 2841bc2ab7..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/prompt-to-add-api-key.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import * as prompts from '@aws-amplify/amplify-prompts'; -import { promptToAddApiKey } from '../../../provider-utils/awscloudformation/prompt-to-add-api-key'; -import * as walkthrough from '../../../provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough'; -import * as cfnApiArtifactHandler from '../../../provider-utils/awscloudformation/cfn-api-artifact-handler'; - -jest.mock('../../../provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough', () => ({ - askApiKeyQuestions: jest.fn(), -})); - -jest.mock('../../../provider-utils/awscloudformation/cfn-api-artifact-handler', () => ({ - getCfnApiArtifactHandler: jest.fn(() => { - return { updateArtifacts: jest.fn() }; - }), -})); - -jest.mock('@aws-amplify/amplify-prompts', () => ({ - prompter: { - confirmContinue: jest.fn().mockImplementation(() => true), - }, -})); - -describe('prompt to add Api Key', () => { - it('runs through expected user flow: print info, update files', async () => { - const envName = 'envone'; - const ctx = { - amplify: { - getEnvInfo() { - return { envName }; - }, - }, - } as unknown as $TSContext; - - jest.spyOn(prompts.prompter, 'confirmContinue'); - jest.spyOn(walkthrough, 'askApiKeyQuestions'); - jest.spyOn(cfnApiArtifactHandler, 'getCfnApiArtifactHandler'); - - await promptToAddApiKey(ctx); - - expect(prompts.prompter.confirmContinue).toHaveBeenCalledWith('Would you like to create an API Key?'); - expect(walkthrough.askApiKeyQuestions).toHaveBeenCalledTimes(1); - expect(cfnApiArtifactHandler.getCfnApiArtifactHandler).toHaveBeenCalledTimes(1); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/__snapshots__/appSync-walkthrough.test.ts.snap b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/__snapshots__/appSync-walkthrough.test.ts.snap deleted file mode 100644 index b477966287..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/__snapshots__/appSync-walkthrough.test.ts.snap +++ /dev/null @@ -1,14 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`correct Auth Config dont configure additional auth types 1`] = ` -Object { - "additionalAuthenticationProviders": Array [ - Object { - "authenticationType": "AMAZON_COGNITO_USER_POOLS", - }, - ], - "defaultAuthentication": Object { - "authenticationType": "AWS_IAM", - }, -} -`; diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.test.ts deleted file mode 100644 index 67f1ec32a7..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { getIAMPolicies } from '../../../../provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough'; - -test('getIAMPolicies', () => { - const output = getIAMPolicies('resourceName', ['read']); - expect(output.attributes).toStrictEqual(['ApiName', 'ApiId']); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.test.ts deleted file mode 100644 index afda63dc8e..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.test.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { $TSContext, FeatureFlags, pathManager, stateManager } from '@aws-amplify/amplify-cli-core'; -import { - askAdditionalAuthQuestions, - getIAMPolicies, -} from '../../../../provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough'; -import { authConfigHasApiKey, getAppSyncAuthConfig } from '../../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; - -jest.mock('../../../../provider-utils/awscloudformation/utils/amplify-meta-utils', () => ({ - getAppSyncAuthConfig: jest.fn(), - authConfigHasApiKey: jest.fn(), -})); -jest.mock('@aws-amplify/amplify-cli-core'); -const stateManager_mock = stateManager as jest.Mocked; -stateManager_mock.getMeta = jest.fn(); - -const pathManager_mock = pathManager as jest.Mocked; -pathManager_mock.getResourceDirectoryPath = jest.fn().mockReturnValue('mocked/resource/path'); - -const mockGetBoolean = FeatureFlags.getBoolean as jest.Mock; - -const authConfigHasApiKey_mock = authConfigHasApiKey as jest.MockedFunction; -const getAppSyncAuthConfig_mock = getAppSyncAuthConfig as jest.MockedFunction; -const confirmPromptFalse_mock = jest.fn(() => false); - -const context_stub = (prompt: jest.Mock) => - ({ - prompt: { - confirm: prompt, - }, - amplify: { - getProjectMeta: jest.fn(), - }, - } as unknown as $TSContext); - -type IAMArtifact = { - attributes: string[]; - policy: any; -}; - -describe('get IAM policies', () => { - beforeEach(() => { - jest.resetModules(); - }); - - it('does not include API key if none exists', async () => { - mockGetBoolean.mockImplementationOnce(() => true); - authConfigHasApiKey_mock.mockImplementationOnce(() => false); - const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query']); - expect(iamArtifact.attributes).toMatchInlineSnapshot(` - Array [ - "GraphQLAPIIdOutput", - "GraphQLAPIEndpointOutput", - ] - `); - expect(iamArtifact.policy.Resource[0]['Fn::Join'][1][6]).toMatch('/types/Query/*'); - }); - - it('includes API key if it exists', async () => { - mockGetBoolean.mockImplementationOnce(() => true); - authConfigHasApiKey_mock.mockImplementationOnce(() => true); - const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query']); - expect(iamArtifact.attributes).toMatchInlineSnapshot(` - Array [ - "GraphQLAPIIdOutput", - "GraphQLAPIEndpointOutput", - "GraphQLAPIKeyOutput", - ] - `); - expect(iamArtifact.policy.Resource[0]['Fn::Join'][1][6]).toMatch('/types/Query/*'); - }); - - it('policy path includes the new format for graphql operations', async () => { - mockGetBoolean.mockImplementationOnce(() => true); - authConfigHasApiKey_mock.mockImplementationOnce(() => false); - const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query', 'Mutate']); - expect(iamArtifact.attributes).toMatchInlineSnapshot(` - Array [ - "GraphQLAPIIdOutput", - "GraphQLAPIEndpointOutput", - ] - `); - expect(iamArtifact.policy.Resource[0]['Fn::Join'][1][6]).toMatch('/types/Query/*'); - expect(iamArtifact.policy.Resource[1]['Fn::Join'][1][6]).toMatch('/types/Mutate/*'); - }); - - it('policy path includes the old format for appsync api operations', async () => { - mockGetBoolean.mockImplementationOnce(() => false); - authConfigHasApiKey_mock.mockImplementationOnce(() => false); - const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['create', 'update']); - expect(iamArtifact.attributes).toMatchInlineSnapshot(` - Array [ - "GraphQLAPIIdOutput", - "GraphQLAPIEndpointOutput", - ] - `); - expect(iamArtifact.policy.Action).toHaveLength(4); - expect(iamArtifact.policy.Action).toEqual(['appsync:Create*', 'appsync:StartSchemaCreation', 'appsync:GraphQL', 'appsync:Update*']); - expect(iamArtifact.policy.Resource).toHaveLength(2); - expect(iamArtifact.policy.Resource[0]['Fn::Join'][1][6]).toMatch('/*'); - }); -}); - -describe('correct Auth Config', () => { - it('dont configure additional auth types', async () => { - const authConfig_mock = { - defaultAuthentication: { - authenticationType: 'AWS_IAM', - }, - additionalAuthenticationProviders: [], - }; - const defaultAuthType_mock = 'AWS_IAM'; - - const currentAuthConfig = { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - { - authenticationType: 'AWS_IAM', - }, - ], - }; - getAppSyncAuthConfig_mock.mockImplementationOnce(() => currentAuthConfig); - const authConfig = await askAdditionalAuthQuestions(context_stub(confirmPromptFalse_mock), authConfig_mock, defaultAuthType_mock); - expect(authConfig).toMatchSnapshot(); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/auth-config-to-app-sync-auth-type-bi-di-mapper.test.ts.snap b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/auth-config-to-app-sync-auth-type-bi-di-mapper.test.ts.snap deleted file mode 100644 index 3c18c0fa24..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/auth-config-to-app-sync-auth-type-bi-di-mapper.test.ts.snap +++ /dev/null @@ -1,73 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`AppSyncAuthType to authConfig maps AMAZON_COGNITO_USER_POOLS correctly 1`] = ` -Object { - "authenticationType": "AMAZON_COGNITO_USER_POOLS", - "userPoolConfig": Object { - "userPoolId": "someID", - }, -} -`; - -exports[`AppSyncAuthType to authConfig maps API_KEY correctly 1`] = ` -Object { - "apiKeyConfig": Object { - "apiKeyExpirationDate": undefined, - "apiKeyExpirationDays": 120, - "description": undefined, - }, - "authenticationType": "API_KEY", -} -`; - -exports[`AppSyncAuthType to authConfig maps AWS_IAM correctly 1`] = ` -Object { - "authenticationType": "AWS_IAM", -} -`; - -exports[`AppSyncAuthType to authConfig maps OPENID_CONNECT correctly 1`] = ` -Object { - "authenticationType": "OPENID_CONNECT", - "openIDConnectConfig": Object { - "authTTL": undefined, - "clientId": "client id", - "iatTTL": undefined, - "issuerUrl": "issuer url", - "name": "providerName", - }, -} -`; - -exports[`authConfig to AppSyncAuthType maps AMAZON_COGNITO_USER_POOLS auth correctly 1`] = ` -Object { - "cognitoUserPoolId": "userPoolId", - "mode": "AMAZON_COGNITO_USER_POOLS", -} -`; - -exports[`authConfig to AppSyncAuthType maps API_KEY auth correctly 1`] = ` -Object { - "apiKeyExpirationDate": undefined, - "expirationTime": 120, - "keyDescription": "api key description", - "mode": "API_KEY", -} -`; - -exports[`authConfig to AppSyncAuthType maps AWS_IAM auth correctly 1`] = ` -Object { - "mode": "AWS_IAM", -} -`; - -exports[`authConfig to AppSyncAuthType maps OPENID_CONNECT auth correclty 1`] = ` -Object { - "mode": "OPENID_CONNECT", - "openIDAuthTTL": "auth TTL", - "openIDClientID": "client id", - "openIDIatTTL": "iat TTL", - "openIDIssuerURL": "issuer url", - "openIDProviderName": "openid name", -} -`; diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/get-appsync-auth-config.test.ts.snap b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/get-appsync-auth-config.test.ts.snap deleted file mode 100644 index 4c0d5743e8..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/get-appsync-auth-config.test.ts.snap +++ /dev/null @@ -1,28 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`function with default and additional auth config 1`] = ` -Object { - "additionalAuthenticationProviders": Array [ - Object { - "apiKeyConfig": Object { - "apiKeyExpirationDate": undefined, - "apiKeyExpirationDays": 7, - "description": "", - }, - "authenticationType": "API_KEY", - }, - ], - "defaultAuthentication": Object { - "authenticationType": "AWS_IAM", - }, -} -`; - -exports[`function with default auth config 1`] = ` -Object { - "additionalAuthenticationProviders": Array [], - "defaultAuthentication": Object { - "authenticationType": "AWS_IAM", - }, -} -`; diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/resolver-config-to-conflict-resolution-bi-di-mapper.test.ts.snap b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/resolver-config-to-conflict-resolution-bi-di-mapper.test.ts.snap deleted file mode 100644 index 9668a5c86e..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/resolver-config-to-conflict-resolution-bi-di-mapper.test.ts.snap +++ /dev/null @@ -1,45 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`transform ConflictResolution to ResolverConfig maps properties correctly 1`] = ` -Object { - "models": Object { - "MyType": Object { - "ConflictDetection": "VERSION", - "ConflictHandler": "LAMBDA", - "LambdaConflictHandler": Object { - "lambdaArn": undefined, - "name": "someLambdaName", - "region": undefined, - }, - }, - }, - "project": Object { - "ConflictDetection": "VERSION", - "ConflictHandler": "AUTOMERGE", - }, -} -`; - -exports[`transform ConflictResolution to ResolverConfig throws when trying to convert new lambda resolution strategy 1`] = `"Tried to convert LambdaResolutionStrategy \\"NEW\\" to SyncConfig. New resources must be generated prior to this conversion and then replaced with a LambdaResolutionStrategy of type \\"EXISTING\\""`; - -exports[`transform ResolverConfig to ConflictResolution maps properties correctly 1`] = ` -Object { - "defaultResolutionStrategy": Object { - "type": "AUTOMERGE", - }, - "perModelResolutionStrategy": Array [ - Object { - "entityName": "MyType", - "resolutionStrategy": Object { - "resolver": Object { - "arn": undefined, - "name": "myLambdaConflictHandler", - "region": undefined, - "type": "EXISTING", - }, - "type": "LAMBDA", - }, - }, - ], -} -`; diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/service-walkthrough-result-to-add-api-request.test.ts.snap b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/service-walkthrough-result-to-add-api-request.test.ts.snap deleted file mode 100644 index 843fd5f5bc..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/service-walkthrough-result-to-add-api-request.test.ts.snap +++ /dev/null @@ -1,21 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`walkthrough result to AddApiRequest conversion maps properties correctly 1`] = ` -Object { - "serviceConfiguration": Object { - "additionalAuthTypes": Array [ - Object { - "mode": "AWS_IAM", - }, - ], - "apiName": "myApiName", - "conflictResolution": Object {}, - "defaultAuthType": Object { - "mode": "AWS_IAM", - }, - "serviceName": "AppSync", - "transformSchema": "mySchemaContent", - }, - "version": 1, -} -`; diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/amplify-meta-utils.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/amplify-meta-utils.test.ts deleted file mode 100644 index 0d61077095..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/amplify-meta-utils.test.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { stateManager } from '@aws-amplify/amplify-cli-core'; -import { - authConfigHasApiKey, - getAppSyncAPINames, - getAppSyncAPIName, - ensureNoAppSyncAPIExists, -} from '../../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; - -jest.mock('@aws-amplify/amplify-cli-core'); -const stateManager_mock = stateManager as jest.Mocked; - -describe('auth config has api key', () => { - it('returns true when default auth is api key', () => { - const authConfig = { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - }; - - expect(authConfigHasApiKey(authConfig)).toBe(true); - }); - - it('returns true when addtl auth contains api key', () => { - const authConfig = { - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - { - authenticationType: 'API_KEY', - }, - ], - }; - expect(authConfigHasApiKey(authConfig)).toBe(true); - }); - - it('returns false when no auth type is api key', () => { - const authConfig = { - defaultAuthentication: { - authenticationType: 'AWS_IAM', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'OTHER', - }, - { - authenticationType: 'OPENID', - }, - ], - }; - - expect(authConfigHasApiKey(authConfig)).toBe(false); - }); -}); - -describe('API resource information utils', () => { - afterAll(() => { - jest.clearAllMocks(); - }); - - const metaWithMultipleAPIs = { - api: { - api1: { - service: 'AppSync', - }, - api2: { - service: 'AppSync', - }, - }, - }; - - const metaWithNoAPI = {}; - - it('Returns all existing AppSync API names', () => { - stateManager_mock.getMeta = jest.fn().mockReturnValueOnce(metaWithMultipleAPIs); - expect(getAppSyncAPINames()).toEqual(['api1', 'api2']); - }); - - it('getAppSyncAPIName returns first API when there are multiple added', () => { - stateManager_mock.getMeta = jest.fn().mockReturnValueOnce(metaWithMultipleAPIs); - expect(getAppSyncAPIName()).toEqual('api1'); - }); - - it('getAppSyncAPIName throws when there is no API added', () => { - stateManager_mock.getMeta = jest.fn().mockReturnValueOnce(metaWithNoAPI); - expect(() => getAppSyncAPIName()).toThrowError( - 'You do not have AppSync API added. Use "amplify add api" or "amplify import api" to add one to your project.', - ); - }); - - it('ensureNoAppSyncAPIExists throws when there is an API added', () => { - stateManager_mock.getMeta = jest.fn().mockReturnValueOnce(metaWithMultipleAPIs); - expect(() => ensureNoAppSyncAPIExists()).toThrowError( - 'You already have an AppSync API named api1 in your project. Use the "amplify update api" command to update your existing AppSync API.', - ); - }); - - it('ensureNoAppSyncAPIExists does not throw when there is no API added', () => { - stateManager_mock.getMeta = jest.fn().mockReturnValueOnce(metaWithNoAPI); - expect(() => ensureNoAppSyncAPIExists()).not.toThrowError(); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper.test.ts deleted file mode 100644 index 74f2ca84d8..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper.test.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { - AppSyncAPIKeyAuthType, - AppSyncAWSIAMAuthType, - AppSyncCognitoUserPoolsAuthType, - AppSyncOpenIDConnectAuthType, -} from 'amplify-headless-interface'; -import { - authConfigToAppSyncAuthType, - appSyncAuthTypeToAuthConfig, -} from '../../../../provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; - -describe('authConfig to AppSyncAuthType', () => { - it('maps API_KEY auth correctly', () => { - const authConfig = { - authenticationType: 'API_KEY', - apiKeyConfig: { - apiKeyExpirationDays: 120, - description: 'api key description', - }, - }; - - expect(authConfigToAppSyncAuthType(authConfig)).toMatchSnapshot(); - }); - - it('maps AWS_IAM auth correctly', () => { - const authConfig = { - authenticationType: 'AWS_IAM', - }; - - expect(authConfigToAppSyncAuthType(authConfig)).toMatchSnapshot(); - }); - - it('maps AMAZON_COGNITO_USER_POOLS auth correctly', () => { - const authConfig = { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - userPoolConfig: { - userPoolId: 'userPoolId', - }, - }; - - expect(authConfigToAppSyncAuthType(authConfig)).toMatchSnapshot(); - }); - - it('maps OPENID_CONNECT auth correclty', () => { - const authConfig = { - authenticationType: 'OPENID_CONNECT', - openIDConnectConfig: { - name: 'openid name', - issuerUrl: 'issuer url', - clientId: 'client id', - authTTL: 'auth TTL', - iatTTL: 'iat TTL', - }, - }; - - expect(authConfigToAppSyncAuthType(authConfig)).toMatchSnapshot(); - }); - - it('returns undefined on undefined input', () => { - expect(authConfigToAppSyncAuthType(undefined)).toBeUndefined(); - }); -}); - -describe('AppSyncAuthType to authConfig', () => { - it('maps API_KEY correctly', () => { - const authType: AppSyncAPIKeyAuthType = { - mode: 'API_KEY', - expirationTime: 120, - }; - expect(appSyncAuthTypeToAuthConfig(authType)).toMatchSnapshot(); - }); - - it('maps AWS_IAM correctly', () => { - const authType: AppSyncAWSIAMAuthType = { - mode: 'AWS_IAM', - }; - expect(appSyncAuthTypeToAuthConfig(authType)).toMatchSnapshot(); - }); - - it('maps AMAZON_COGNITO_USER_POOLS correctly', () => { - const authType: AppSyncCognitoUserPoolsAuthType = { - mode: 'AMAZON_COGNITO_USER_POOLS', - cognitoUserPoolId: 'someID', - }; - expect(appSyncAuthTypeToAuthConfig(authType)).toMatchSnapshot(); - }); - - it('maps OPENID_CONNECT correctly', () => { - const authType: AppSyncOpenIDConnectAuthType = { - mode: 'OPENID_CONNECT', - openIDProviderName: 'providerName', - openIDClientID: 'client id', - openIDIssuerURL: 'issuer url', - }; - - expect(appSyncAuthTypeToAuthConfig(authType)).toMatchSnapshot(); - }); - - it('returns undefined on undefined input', () => { - expect(appSyncAuthTypeToAuthConfig(undefined)).toBeUndefined(); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/containers/set-existing-secret-arns.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/containers/set-existing-secret-arns.test.ts deleted file mode 100644 index 63a0ccbbd4..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/containers/set-existing-secret-arns.test.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { setExistingSecretArns } from '../../../../../provider-utils/awscloudformation/utils/containers/set-existing-secret-arns'; - -describe('set existing secret arns', () => { - it('does nothing if no template found', () => { - const secretMap = new Map(); - setExistingSecretArns(secretMap, {}); - expect(secretMap.size).toBe(0); - }); - - it('does nothing if template does not have secrets', () => { - const mockTemplate = { - Resources: { - TaskDefinition: { - Type: 'AWS::ECS::TaskDefinition', - Properties: { - ContainerDefinitions: [ - { - Secrets: [], - }, - ], - }, - }, - }, - }; - const secretMap = new Map(); - setExistingSecretArns(secretMap, mockTemplate); - expect(secretMap.size).toBe(0); - }); - - it('adds all secrets to secret map', () => { - const mockTemplate = { - Resources: { - TaskDefinition: { - Type: 'AWS::ECS::TaskDefinition', - Properties: { - ContainerDefinitions: [ - { - Secrets: [ - { - Name: 'SOMETHING', - ValueFrom: 'some:secretsmanager:arn', - }, - ], - }, - ], - }, - }, - }, - }; - const secretMap = new Map(); - setExistingSecretArns(secretMap, mockTemplate); - expect(secretMap.size).toBe(1); - expect(secretMap.entries().next().value).toMatchInlineSnapshot(` - Array [ - "SOMETHING", - "some:secretsmanager:arn", - ] - `); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/database-url.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/database-url.test.ts deleted file mode 100644 index af46db3a33..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/database-url.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { parseDatabaseUrl } from '../../../../provider-utils/awscloudformation/utils/database-url'; - -describe('parseDatabaseUrl', () => { - it('should parse a valid database url', () => { - const databaseUrl = 'mysql://username:password@localhost:3306/database'; - const expected = { - engine: 'mysql', - username: 'username', - password: 'password', - database: 'database', - host: 'localhost', - port: 3306, - }; - const actual = parseDatabaseUrl(databaseUrl); - expect(actual).toEqual(expected); - }); - - it('should parse a valid database url without port', () => { - const databaseUrl = 'mysql://username:password@localhost/database'; - const expected = { - engine: 'mysql', - username: 'username', - password: 'password', - database: 'database', - host: 'localhost', - port: NaN, - }; - const actual = parseDatabaseUrl(databaseUrl); - expect(actual).toEqual(expected); - }); - - it('should parse a valid database url without username and password', () => { - const databaseUrl = 'mysql://localhost:3306/database'; - const expected = { - engine: 'mysql', - username: '', - password: '', - database: 'database', - host: 'localhost', - port: 3306, - }; - const actual = parseDatabaseUrl(databaseUrl); - expect(actual).toEqual(expected); - }); - - it('should throw an error for an invalid database url', () => { - const databaseUrl = 'http://username:password@localhost:3306/database'; - expect(() => parseDatabaseUrl(databaseUrl)).toThrow('Invalid engine http.'); - }); - - it('should accept uppercase engine name', () => { - const databaseUrl = 'MySQL://username:password@localhost:3306/database'; - const expected = { - engine: 'mysql', - username: 'username', - password: 'password', - database: 'database', - host: 'localhost', - port: 3306, - }; - const actual = parseDatabaseUrl(databaseUrl); - expect(actual).toEqual(expected); - }); - - it('should return empty object for an invalid database url', () => { - const databaseUrl = '1234567890'; - const expected = {}; - const actual = parseDatabaseUrl(databaseUrl); - expect(actual).toEqual(expected); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/get-appsync-auth-config.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/get-appsync-auth-config.test.ts deleted file mode 100644 index 44bd44ce17..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/get-appsync-auth-config.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { getAuthConfig } from '../../../../provider-utils/awscloudformation/utils/get-appsync-auth-config'; - -const getCLIInputPayload_mock = jest - .fn() - .mockReturnValueOnce({ - version: 1, - serviceConfiguration: { - apiName: 'authv2migration1', - serviceName: 'AppSync', - defaultAuthType: { - mode: 'AWS_IAM', - }, - conflictResolution: {}, - additionalAuthTypes: [], - }, - }) - .mockReturnValueOnce({ - version: 1, - serviceConfiguration: { - apiName: 'authv2migration1', - serviceName: 'AppSync', - defaultAuthType: { - mode: 'AWS_IAM', - }, - conflictResolution: {}, - additionalAuthTypes: [ - { - mode: 'API_KEY', - expirationTime: 7, - keyDescription: '', - }, - ], - }, - }); - -jest.mock('../../../../provider-utils/awscloudformation/api-input-manager/appsync-api-input-state.ts', () => { - return { - AppsyncApiInputState: jest.fn().mockImplementation(() => { - return { - getCLIInputPayload: getCLIInputPayload_mock, - cliInputFileExists: jest.fn().mockReturnValue(true), - }; - }), - }; -}); - -const mockContext: $TSContext = { - amplify: { - getCategoryPluginInfo: (_context: $TSContext, category: string) => { - return { - packageLocation: `@aws-amplify/amplify-category-${category}`, - }; - }, - }, - input: { - options: {}, - }, -} as unknown as $TSContext; - -test('function with default auth config', async () => { - expect(await getAuthConfig(mockContext, 'mockapiResource')).toMatchSnapshot(); -}); - -test('function with default and additional auth config', async () => { - expect(await getAuthConfig(mockContext, 'mockapiResource')).toMatchSnapshot(); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/global-sandbox-mode.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/global-sandbox-mode.test.ts deleted file mode 100644 index 28716c527e..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/global-sandbox-mode.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineGlobalSandboxMode } from '../../../../provider-utils/awscloudformation/utils/global-sandbox-mode'; - -describe('global sandbox mode GraphQL directive', () => { - it('returns input AMPLIFY with code comment', () => { - expect(defineGlobalSandboxMode('mockLink')).toEqual(`# This "input" configures a global authorization rule to enable public access to -# all models in this schema. Learn more about authorization rules here: mockLink -input AMPLIFY { globalAuthRule: AuthRule = { allow: public } } # FOR TESTING ONLY!\n -`); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/migrate-api-override-resource.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/migrate-api-override-resource.test.ts deleted file mode 100644 index 115b910e1a..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/migrate-api-override-resource.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -import * as path from 'path'; -import { JSONUtilities } from '@aws-amplify/amplify-cli-core'; -import { migrateResourceToSupportOverride } from '../../../../provider-utils/awscloudformation/utils/migrate-api-override-resource'; - -jest.mock('@aws-amplify/amplify-prompts'); -jest.mock('fs-extra'); - -jest.mock('@aws-amplify/amplify-cli-core', () => ({ - ...(jest.requireActual('@aws-amplify/amplify-cli-core') as {}), - pathManager: { - findProjectRoot: jest.fn().mockReturnValue('somePath'), - getBackendDirPath: jest.fn().mockReturnValue('mockProjectPath'), - getResourceDirectoryPath: jest.fn().mockReturnValue('mockProjectPath'), - }, - stateManager: { - getMeta: jest.fn().mockReturnValue({ - api: { - apiunittests: { - service: 'AppSync', - providerPlugin: 'awscloudformation', - output: { - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - userPoolConfig: { - userPoolId: 'authapiunittests2778e848', - }, - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }, - }, - }, - }, - }), - }, - JSONUtilities: { - readJson: jest.fn().mockReturnValue({ - ResolverConfig: { - project: { - ConflictHandler: 'AUTOMERGE', - ConflictDetection: 'VERSION', - }, - }, - }), - writeJson: jest.fn(), - }, -})); -test('migrate resource', async () => { - const resourceName = 'apiunittests'; - migrateResourceToSupportOverride(resourceName); - const expectedPath = path.join('mockProjectPath', 'cli-inputs.json'); - const expectedPayload = { - version: 1, - serviceConfiguration: { - serviceName: 'AppSync', - defaultAuthType: { - mode: 'AMAZON_COGNITO_USER_POOLS', - cognitoUserPoolId: 'authapiunittests2778e848', - }, - additionalAuthTypes: [ - { - mode: 'AWS_IAM', - }, - ], - conflictResolution: { - defaultResolutionStrategy: { - type: 'AUTOMERGE', - }, - }, - apiName: 'apiunittests', - }, - }; - expect(JSONUtilities.writeJson).toBeCalledWith(expectedPath, expectedPayload); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rds-secrets/database-resources.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rds-secrets/database-resources.test.ts deleted file mode 100644 index 9f91c15639..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rds-secrets/database-resources.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { $TSContext, stateManager } from '@aws-amplify/amplify-cli-core'; -import { getParameterStoreSecretPath } from '@aws-amplify/graphql-transformer-core'; -import { getExistingConnectionSecrets } from '../../../../../provider-utils/awscloudformation/utils/rds-resources/database-resources'; - -const mockDatabase = 'mockdatabase'; -const mockAPIName = 'mockapi'; - -jest.mock('../../../../../provider-utils/awscloudformation/utils/rds-resources/ssmClient', () => ({ - SSMClient: { - getInstance: jest.fn().mockResolvedValue({ - getSecrets: jest.fn(), - setSecret: jest.fn(), - }), - }, -})); - -jest.mock('@aws-amplify/amplify-cli-core', () => { - const original = jest.requireActual('@aws-amplify/amplify-cli-core'); - return { - ...original, - stateManager: { - getAppID: jest.fn().mockReturnValue('fake-app-id'), - getCurrentEnvName: jest.fn().mockReturnValue('test'), - }, - }; -}); - -describe('Test database secrets management', () => { - const mockContext = {} as any as $TSContext; - - beforeEach(() => { - jest.clearAllMocks(); - }); - - afterAll(() => { - jest.resetAllMocks(); - }); - - it('Returns correct path for secrets in parameter store for a database', () => { - const appId = stateManager.getAppID(); - const envName = stateManager.getCurrentEnvName(); - const usernamePath = getParameterStoreSecretPath('username', mockDatabase, mockAPIName, envName, appId); - expect(usernamePath).toEqual('/amplify/fake-app-id/test/AMPLIFY_apimockapimockdatabase_username'); - - const passwordPath = getParameterStoreSecretPath('password', mockDatabase, mockAPIName, envName, appId); - expect(passwordPath).toEqual('/amplify/fake-app-id/test/AMPLIFY_apimockapimockdatabase_password'); - }); - - it('Returns undefined if secrets do not exist in parameter store for a database', async () => { - const fetchedSecrets = await getExistingConnectionSecrets(mockContext, mockDatabase, mockAPIName); - expect(fetchedSecrets).not.toBeDefined(); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rds-secrets/ssmClient.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rds-secrets/ssmClient.test.ts deleted file mode 100644 index c724c32ddd..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rds-secrets/ssmClient.test.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { SSMClient } from '../../../../../provider-utils/awscloudformation/utils/rds-resources/ssmClient'; -import aws from 'aws-sdk'; - -const secretName = 'mock-test-secret-name'; -const secretValue = 'mock-test-secret-value'; -const mockPutParameter = jest.fn(({ Name, Value, Type, Overwrite }) => { - return { promise: () => {} }; -}); -const mockDeleteParameter = jest.fn(({ Name }) => { - return { promise: () => {} }; -}); -const mockDeleteParameters = jest.fn(({ Names }) => { - return { promise: () => {} }; -}); -const mockGetParameters = jest.fn(({ Names }) => { - return { promise: () => Promise.resolve({ Parameters: [{ Name: secretName, Value: secretValue }] }) }; -}); - -jest.mock('aws-sdk', () => { - return { - config: { - // eslint-disable-next-line prefer-arrow/prefer-arrow-functions - update() { - return {}; - }, - }, - SSM: jest.fn(() => { - return { - putParameter: mockPutParameter, - deleteParameter: mockDeleteParameter, - deleteParameters: mockDeleteParameters, - getParameters: mockGetParameters, - }; - }), - }; -}); - -describe('SSM client configuration', () => { - const mockContext = { - amplify: { - invokePluginMethod: jest.fn().mockResolvedValue({ client: new aws.SSM() }), - }, - } as any as $TSContext; - - test('able to get the configured SSM instance via provider plugin', async () => { - const ssmClient = await SSMClient.getInstance(mockContext); - expect(ssmClient).toBeDefined(); - expect(mockContext.amplify.invokePluginMethod).toBeCalledTimes(1); - expect(mockContext.amplify.invokePluginMethod).toBeCalledWith(mockContext, 'awscloudformation', undefined, 'getConfiguredSSMClient', [ - mockContext, - ]); - }); - - test('able to set the secret value', async () => { - const ssmClient = await SSMClient.getInstance(mockContext); - - ssmClient.setSecret(secretName, secretValue); - expect(mockPutParameter).toBeCalledWith({ - Name: secretName, - Overwrite: true, - Type: 'SecureString', - Value: secretValue, - }); - }); - - test('able to get the secret value', async () => { - const ssmClient = await SSMClient.getInstance(mockContext); - const result = await ssmClient.getSecrets([secretName]); - - expect(mockGetParameters).toBeCalledWith({ - Names: [secretName], - WithDecryption: true, - }); - expect(result).toEqual([{ secretName: secretName, secretValue: secretValue }]); - }); - - test('able to delete the secret', async () => { - const ssmClient = await SSMClient.getInstance(mockContext); - ssmClient.deleteSecret(secretName); - expect(mockDeleteParameter).toBeCalledWith({ - Name: secretName, - }); - }); - - test('able to delete multiple secrets', async () => { - const ssmClient = await SSMClient.getInstance(mockContext); - ssmClient.deleteSecrets([secretName]); - expect(mockDeleteParameters).toBeCalledWith({ - Names: [secretName], - }); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rds-utils.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rds-utils.test.ts deleted file mode 100644 index 68e9dda34e..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rds-utils.test.ts +++ /dev/null @@ -1,192 +0,0 @@ -import { - DataSourceStrategiesProvider, - ModelDataSourceStrategy, - SQLLambdaModelDataSourceStrategy, -} from '@aws-amplify/graphql-transformer-interfaces'; -import { DDB_DEFAULT_DATASOURCE_STRATEGY, MYSQL_DB_TYPE } from '@aws-amplify/graphql-transformer-core'; -import { - checkForUnsupportedDirectives, - containsSqlModelOrDirective, -} from '../../../../provider-utils/awscloudformation/utils/rds-resources/utils'; - -describe('check for unsupported RDS directives', () => { - const dbConnectionConfig = { - databaseNameSsmPath: '/databaseNameSsmPath', - hostnameSsmPath: '/hostnameSsmPath', - portSsmPath: '/portSsmPath', - usernameSsmPath: '/usernameSsmPath', - passwordSsmPath: '/passwordSsmPath', - }; - - const dataSourceStrategies: Record = { - Post: { - name: 'mysqlstrategy', - dbType: MYSQL_DB_TYPE, - dbConnectionConfig, - }, - Tag: DDB_DEFAULT_DATASOURCE_STRATEGY, - }; - - const ddbDataSourceStrategies: Record = { - Post: DDB_DEFAULT_DATASOURCE_STRATEGY, - Tag: DDB_DEFAULT_DATASOURCE_STRATEGY, - }; - - const strategy: SQLLambdaModelDataSourceStrategy = { - name: 'strategy', - dbType: 'MYSQL', - dbConnectionConfig, - }; - - const sqlDirectiveDataSourceStrategies = [ - { - typeName: 'Query' as const, - fieldName: 'myCustomQuery', - strategy: strategy, - customSqlStatements: { - myCustomQuery: 'SELECT 1;', - myCustomMutation: 'UPDATE mytable SET id=1; SELECT 1;', - }, - }, - ]; - - const dataSourceStrategiesProvider: DataSourceStrategiesProvider = { dataSourceStrategies }; - const emptyProvider: DataSourceStrategiesProvider = { dataSourceStrategies: {} }; - - it('should throw error if searchable directive is present on a model', () => { - const schema = ` - type Post @model @searchable { - id: ID! - title: String! - } - `; - expect(() => checkForUnsupportedDirectives(schema, dataSourceStrategiesProvider)).toThrowErrorMatchingInlineSnapshot( - '"@searchable directive on type \\"Post\\" is not supported on a SQL datasource. Following directives are not supported on a SQL datasource: searchable, predictions, function, manyToMany, http, mapsTo"', - ); - }); - - it('should throw error if predictions directive is present on a query type field', () => { - const schema = ` - type Query { - recognizeTextFromImage: String @predictions(actions: [identifyText]) - } - `; - expect(() => checkForUnsupportedDirectives(schema, dataSourceStrategiesProvider)).toThrowErrorMatchingInlineSnapshot( - '"@predictions directive on type \\"Query\\" and field \\"recognizeTextFromImage\\" is not supported on a SQL datasource. Following directives are not supported on a SQL datasource: searchable, predictions, function, manyToMany, http, mapsTo"', - ); - }); - - it('should throw error if function directive is present on a field', () => { - const schema = ` - type Query { - echo(msg: String): String @function(name: "echofunction") - } - `; - expect(() => checkForUnsupportedDirectives(schema, dataSourceStrategiesProvider)).toThrowErrorMatchingInlineSnapshot( - '"@function directive on type \\"Query\\" and field \\"echo\\" is not supported on a SQL datasource. Following directives are not supported on a SQL datasource: searchable, predictions, function, manyToMany, http, mapsTo"', - ); - }); - - it('should throw error if manyToMany directive is present on a field', () => { - const schema = ` - type Post @model { - id: ID! - title: String! - content: String - tags: [Tag] @manyToMany(relationName: "PostTags") - } - - type Tag @model { - id: ID! - label: String! - posts: [Post] @manyToMany(relationName: "PostTags") - } - `; - expect(() => checkForUnsupportedDirectives(schema, dataSourceStrategiesProvider)).toThrowErrorMatchingInlineSnapshot( - '"@manyToMany directive on type \\"Post\\" and field \\"tags\\" is not supported on a SQL datasource. Following directives are not supported on a SQL datasource: searchable, predictions, function, manyToMany, http, mapsTo"', - ); - }); - - it('should throw error if http directive is present on a field', () => { - const schema = ` - type Post { - id: ID! - title: String - description: String - views: Int - } - - type Query { - listPosts: [Post] @http(url: "https://www.example.com/posts") - } - `; - expect(() => checkForUnsupportedDirectives(schema, dataSourceStrategiesProvider)).toThrowErrorMatchingInlineSnapshot( - '"@http directive on type \\"Query\\" and field \\"listPosts\\" is not supported on a SQL datasource. Following directives are not supported on a SQL datasource: searchable, predictions, function, manyToMany, http, mapsTo"', - ); - }); - - it('should throw error if mapsTo directive is present on a model', () => { - const schema = ` - type Post @model @mapsTo(name: "Article") { - id: ID! - title: String! - } - `; - expect(() => checkForUnsupportedDirectives(schema, dataSourceStrategiesProvider)).toThrowErrorMatchingInlineSnapshot( - '"@mapsTo directive on type \\"Post\\" is not supported on a SQL datasource. Following directives are not supported on a SQL datasource: searchable, predictions, function, manyToMany, http, mapsTo"', - ); - }); - - it('should not throw error if there are only DDB models', () => { - const schema = ` - type Post @model @mapsTo(name: "Article") { - id: ID! - title: String! - } - `; - const ddbProvider: DataSourceStrategiesProvider = { - dataSourceStrategies: { - Post: DDB_DEFAULT_DATASOURCE_STRATEGY, - }, - }; - expect(() => checkForUnsupportedDirectives(schema, ddbProvider)).not.toThrowError(); - }); - - it('early return if model_to_datasource map is empty or undefined', () => { - const schema = ` - type Post @model @mapsTo(name: "Article") { - id: ID! - title: String! - } - `; - expect(() => checkForUnsupportedDirectives(schema, emptyProvider)).not.toThrowError(); - }); - - it('early return for a schema with no models', () => { - const schema = ` - type Post { - id: ID! - title: String! - } - `; - expect(() => checkForUnsupportedDirectives(schema, emptyProvider)).not.toThrowError(); - }); - - it('early return if schema is empty or undefined', () => { - const schema = ''; - expect(() => checkForUnsupportedDirectives(schema, dataSourceStrategiesProvider)).not.toThrowError(); - }); - - it('containsSqlModelOrDirective should return true if there are sql models', () => { - expect(containsSqlModelOrDirective(dataSourceStrategies, undefined)).toBeTruthy(); - expect(containsSqlModelOrDirective(dataSourceStrategies, [])).toBeTruthy(); - expect(containsSqlModelOrDirective(emptyProvider.dataSourceStrategies, sqlDirectiveDataSourceStrategies)).toBeTruthy(); - expect(containsSqlModelOrDirective(ddbDataSourceStrategies, sqlDirectiveDataSourceStrategies)).toBeTruthy(); - }); - - it('containsSqlModelOrDirective should return false if there are no sql models', () => { - expect(containsSqlModelOrDirective(ddbDataSourceStrategies, undefined)).toBeFalsy(); - expect(containsSqlModelOrDirective(ddbDataSourceStrategies, [])).toBeFalsy(); - expect(containsSqlModelOrDirective(emptyProvider.dataSourceStrategies)).toBeFalsy(); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/resolver-config-to-conflict-resolution-bi-di-mapper.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/resolver-config-to-conflict-resolution-bi-di-mapper.test.ts deleted file mode 100644 index 8b0229db50..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/resolver-config-to-conflict-resolution-bi-di-mapper.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { ConflictResolution } from 'amplify-headless-interface'; -import { ResolverConfig, ConflictHandlerType } from 'graphql-transformer-core'; -import { - conflictResolutionToResolverConfig, - resolverConfigToConflictResolution, -} from '../../../../provider-utils/awscloudformation/utils/resolver-config-to-conflict-resolution-bi-di-mapper'; - -describe('transform ConflictResolution to ResolverConfig', () => { - it('maps properties correctly', () => { - const conflictResolution: ConflictResolution = { - defaultResolutionStrategy: { - type: 'AUTOMERGE', - }, - perModelResolutionStrategy: [ - { - entityName: 'MyType', - resolutionStrategy: { - type: 'LAMBDA', - resolver: { - type: 'EXISTING', - name: 'someLambdaName', - }, - }, - }, - ], - }; - expect(conflictResolutionToResolverConfig(conflictResolution)).toMatchSnapshot(); - }); - - it('throws when trying to convert new lambda resolution strategy', () => { - const conflictResolution: ConflictResolution = { - defaultResolutionStrategy: { - type: 'LAMBDA', - resolver: { - type: 'NEW', - }, - }, - }; - - expect(() => conflictResolutionToResolverConfig(conflictResolution)).toThrowErrorMatchingSnapshot(); - }); - - it('returns an empty object when ConflictResolution is not present', () => { - expect(conflictResolutionToResolverConfig(undefined)).toEqual(undefined); - }); -}); - -describe('transform ResolverConfig to ConflictResolution', () => { - it('maps properties correctly', () => { - const resolverConfig: ResolverConfig = { - project: { - ConflictHandler: ConflictHandlerType.AUTOMERGE, - ConflictDetection: 'VERSION', - }, - models: { - MyType: { - ConflictHandler: ConflictHandlerType.LAMBDA, - ConflictDetection: 'VERSION', - LambdaConflictHandler: { - name: 'myLambdaConflictHandler', - }, - }, - }, - }; - - expect(resolverConfigToConflictResolution(resolverConfig)).toMatchSnapshot(); - }); - - it('returns an empty object when ResolverConfig is not present', () => { - expect(resolverConfigToConflictResolution(undefined)).toEqual({}); - }); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rest-api-path-utils.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rest-api-path-utils.test.ts deleted file mode 100644 index 6facce6d56..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rest-api-path-utils.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { - validatePathName, - checkForPathOverlap, - formatCFNPathParamsForExpressJs, -} from '../../../../provider-utils/awscloudformation/utils/rest-api-path-utils'; - -const stubOtherPaths = ['/other/path', '/sub/path', '/path/{with}/{params}']; - -test('validatePathName_validPath', () => { - expect(validatePathName('/some/path')).toBe(true); - expect(validatePathName('/path/{with}/{params}')).toBe(true); - expect(validatePathName('/')).toBe(true); -}); - -test('validatePath_empty', () => { - expect(validatePathName('')).toStrictEqual('The path must not be empty'); -}); - -test('validatePathName_noLeadingSlash', () => { - expect(validatePathName('no/leading/slash')).toStrictEqual('The path must begin with / e.g. /items'); -}); - -test('validatePathName_hasTrailingSlash', () => { - expect(validatePathName('/has/trailing/slash/')).toStrictEqual('The path must not end with /'); -}); - -test('validatePathName_invalidCharacters', () => { - // setup - const errorMessage = - 'Each path part must use characters a-z A-Z 0-9 - and must not be empty.\nOptionally, a path part can be surrounded by { } to denote a path parameter.'; - - // test - expect(validatePathName('/invalid+/{char}')).toStrictEqual(errorMessage); - expect(validatePathName('/invalid/{char@}')).toStrictEqual(errorMessage); - expect(validatePathName('/invalid/{param')).toStrictEqual(errorMessage); -}); - -test('checkForPathOverlap_subPathMatch', () => { - expect(checkForPathOverlap('/sub/path/match', stubOtherPaths)).toEqual({ - higherOrderPath: '/sub/path', - lowerOrderPath: '/sub/path/match', - }); -}); - -test('checkForPathOverlap_subPathParamsMatch', () => { - expect(checkForPathOverlap('/path/{with-different}/{params}', stubOtherPaths)).toEqual({ - higherOrderPath: '/path/{with}/{params}', - lowerOrderPath: '/path/{with-different}/{params}', - }); -}); - -test('checkForPathOverlap_subPathParamsNoMatch', () => { - expect(checkForPathOverlap('/path/{with-non-ovelapping-params}', stubOtherPaths)).toEqual(false); - expect(checkForPathOverlap('/path/{with}/non-overlapping-params', stubOtherPaths)).toEqual(false); - expect(checkForPathOverlap('/path/{with}/non/overlapping/params', stubOtherPaths)).toEqual(false); -}); - -test('checkForPathOverlap_pathMatch', () => { - expect(checkForPathOverlap(stubOtherPaths[0], stubOtherPaths)).toEqual({ - higherOrderPath: stubOtherPaths[0], - lowerOrderPath: stubOtherPaths[0], - }); -}); - -test('formatCFNPathParamsForExpressJs', () => { - expect(formatCFNPathParamsForExpressJs('/')).toStrictEqual('/'); - expect(formatCFNPathParamsForExpressJs('/path')).toStrictEqual('/path'); - expect(formatCFNPathParamsForExpressJs('/path/{param}')).toStrictEqual('/path/:param'); - expect(formatCFNPathParamsForExpressJs('/path/{param}/suffix')).toStrictEqual('/path/:param/suffix'); -}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/service-walkthrough-result-to-add-api-request.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/service-walkthrough-result-to-add-api-request.test.ts deleted file mode 100644 index 1e3b3f7ce7..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/service-walkthrough-result-to-add-api-request.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { AppSyncAuthType, ConflictResolution } from 'amplify-headless-interface'; -import { serviceWalkthroughResultToAddApiRequest } from '../../../../provider-utils/awscloudformation/utils/service-walkthrough-result-to-add-api-request'; - -jest.mock('../../../../provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper', () => ({ - authConfigToAppSyncAuthType: jest.fn((): AppSyncAuthType => ({ mode: 'AWS_IAM' })), -})); -jest.mock('../../../../provider-utils/awscloudformation/utils/resolver-config-to-conflict-resolution-bi-di-mapper', () => ({ - resolverConfigToConflictResolution: jest.fn((): ConflictResolution => ({})), -})); - -describe('walkthrough result to AddApiRequest conversion', () => { - it('maps properties correctly', () => { - const walkthroughResultStub = { - answers: { - apiName: 'myApiName', - }, - schemaContent: 'mySchemaContent', - output: { - authConfig: { - defaultAuthentication: 'defaultAuth', - additionalAuthenticationProviders: ['otherAuth'], - }, - }, - }; - const result = serviceWalkthroughResultToAddApiRequest(walkthroughResultStub); - expect(result).toMatchSnapshot(); - }); -}); diff --git a/packages/amplify-category-api/src/category-constants.ts b/packages/amplify-category-api/src/category-constants.ts deleted file mode 100644 index 4daed8c297..0000000000 --- a/packages/amplify-category-api/src/category-constants.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { AmplifyCategories } from '@aws-amplify/amplify-cli-core'; - -export const ADMIN_QUERIES_NAME = 'AdminQueries'; -export const NETWORK_STACK_LOGICAL_ID = 'NetworkStack'; -export const category = AmplifyCategories.API; -export const PREVIEW_BANNER = 'This feature is in preview and is not recommended to use with production systems.'; diff --git a/packages/amplify-category-api/src/category-utils/context-util.ts b/packages/amplify-category-api/src/category-utils/context-util.ts deleted file mode 100644 index d69933eb2c..0000000000 --- a/packages/amplify-category-api/src/category-utils/context-util.ts +++ /dev/null @@ -1,70 +0,0 @@ -import path from 'path'; -import { $TSContext, AmplifyCategories, pathManager } from '@aws-amplify/amplify-cli-core'; - -import fs from 'fs-extra'; -import { PROVIDER_NAME } from '../graphql-transformer/constants'; - -export const APPSYNC_RESOURCE_SERVICE = 'AppSync'; - -/** - * ContextUtil - * Some values are calculated on the basis of the context and options that come - * from the Amplify CLI, this class/singleton help calculate and cache those values - * for reference - */ -export class ContextUtil { - private resourceDir: string; - - /** - * Get the resource directory as used by the API category for GraphQL - * @param context the context from the CLI - * @param options the options from the CLI - */ - getResourceDir = async (context: $TSContext, options: any): Promise => { - if (this.resourceDir) { - return this.resourceDir; - } - let { resourceDir } = options; - const { forceCompile } = options; - const backEndDir = pathManager.getBackendDirPath(); - const { resourcesToBeCreated, resourcesToBeUpdated, allResources } = await context.amplify.getResourceStatus(AmplifyCategories.API); - let resources = resourcesToBeCreated.concat(resourcesToBeUpdated); - - // When build folder is missing include the API - // to be compiled without the backend/api//build - // cloud formation push will fail even if there is no changes in the GraphQL API - // https://github.com/aws-amplify/amplify-console/issues/10 - const resourceNeedCompile = allResources - .filter((r) => !resources.includes(r)) - .filter((r) => { - const buildDir = path.normalize(path.join(backEndDir, AmplifyCategories.API, r.resourceName, 'build')); - return !fs.existsSync(buildDir); - }); - resources = resources.concat(resourceNeedCompile); - - if (forceCompile) { - resources = resources.concat(allResources); - } - resources = resources.filter((resource) => resource.service === APPSYNC_RESOURCE_SERVICE); - if (!resourceDir) { - // There can only be one appsync resource - if (!resources.length) { - // No appsync resource to update/add - return undefined; - } - if (resources.length > 0) { - const resource = resources[0]; - if (resource.providerPlugin !== PROVIDER_NAME) { - return undefined; - } - const { category } = resource; - const { resourceName } = resource; - resourceDir = path.normalize(path.join(backEndDir, category, resourceName)); - } - } - this.resourceDir = resourceDir; - return resourceDir; - }; -} - -export const contextUtil = new ContextUtil(); diff --git a/packages/amplify-category-api/src/category-utils/is-datastore-enabled.ts b/packages/amplify-category-api/src/category-utils/is-datastore-enabled.ts deleted file mode 100644 index 1649b74381..0000000000 --- a/packages/amplify-category-api/src/category-utils/is-datastore-enabled.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { isDataStoreEnabled as isDataStoreEnabledAtDirectory } from 'graphql-transformer-core'; -import { contextUtil } from './context-util'; - -/** - * Given an input Amplify context retrieve the resource directory (we use forceCompile in order to check unchanged packages as well) - * and return whether or not the customer has conflict resolution enabled on their project. - * @param context the amplify context to extract project directories from - * @returns true if customer has conflict resolution enabled on their project - */ -export const isDataStoreEnabled = async (context: $TSContext): Promise => { - const resourceDirectory = await contextUtil.getResourceDir(context, { forceCompile: true }); - return isDataStoreEnabledAtDirectory(resourceDirectory); -}; diff --git a/packages/amplify-category-api/src/category-utils/schema-reader.ts b/packages/amplify-category-api/src/category-utils/schema-reader.ts deleted file mode 100644 index 8e18aa201d..0000000000 --- a/packages/amplify-category-api/src/category-utils/schema-reader.ts +++ /dev/null @@ -1,87 +0,0 @@ -import path from 'path'; -import * as fs from 'fs-extra'; -import { DocumentNode, parse } from 'graphql'; -import { $TSContext, AmplifyError, ApiCategoryFacade } from '@aws-amplify/amplify-cli-core'; -import { constructTransform } from '@aws-amplify/graphql-transformer'; -import { SCHEMA_DIR_NAME, SCHEMA_FILENAME } from '../graphql-transformer/constants'; -import { generateTransformerOptions } from '../graphql-transformer/transformer-options-v2'; -import { contextUtil } from './context-util'; - -/** - * SchemaReader is a utility point to consolidate and abstract GraphQL Schema reading - * The readSchema method provides a flag to read the un-processed (original) schema - * if desired, but by default the intent of the SchemaReader is to use the preProcess - * utility of the V2 transformer - */ -export class SchemaReader { - private schemaPath: string; - - private schemaDocument: DocumentNode; - - private preProcessedSchemaDocument: DocumentNode; - - getSchemaPath = async (resourceDir: string): Promise => { - if (this.schemaPath) { - return this.schemaPath; - } - const schemaFilePath = path.normalize(path.join(resourceDir, SCHEMA_FILENAME)); - const schemaDirPath = path.normalize(path.join(resourceDir, SCHEMA_DIR_NAME)); - - if (fs.pathExistsSync(schemaFilePath)) { - this.schemaPath = schemaFilePath; - } else if (fs.pathExistsSync(schemaDirPath)) { - this.schemaPath = schemaDirPath; - } else { - throw new AmplifyError('ApiCategorySchemaNotFoundError', { - message: 'No schema found', - resolution: `Your graphql schema should be in either ${schemaFilePath} or ${schemaDirPath}`, - }); - } - return this.schemaPath; - }; - - invalidateCachedSchema = (): void => { - this.schemaPath = null; - this.schemaDocument = null; - this.preProcessedSchemaDocument = null; - }; - - readSchema = async (context: $TSContext, options: any, usePreProcessing = true): Promise => { - const preProcessSchema = usePreProcessing && (await ApiCategoryFacade.getTransformerVersion(context)) === 2; - if (!this.schemaDocument) { - const fileContentsList = new Array>(); - const resourceDir = await contextUtil.getResourceDir(context, options); - const schemaPath = await this.getSchemaPath(resourceDir); - - const stats = fs.statSync(schemaPath); - if (stats.isDirectory()) { - fs.readdirSync(schemaPath).forEach((fileName) => { - fileContentsList.push(fs.readFile(path.join(schemaPath, fileName))); - }); - } else { - fileContentsList.push(fs.readFile(schemaPath)); - } - - if (!fileContentsList.length) { - throw new AmplifyError('ApiCategorySchemaNotFoundError', { - message: 'No schema found', - resolution: `Your graphql schema should be in ${schemaPath}`, - }); - } - - const bufferList = await Promise.all(fileContentsList); - const fullSchema = bufferList.map((buff) => buff.toString()).join('\n'); - this.schemaDocument = parse(fullSchema); - } - - if (preProcessSchema && !this.preProcessedSchemaDocument) { - const transformerOptions = await generateTransformerOptions(context, options); - const transform = constructTransform(transformerOptions); - this.preProcessedSchemaDocument = transform.preProcessSchema(this.schemaDocument); - } - - return preProcessSchema ? this.preProcessedSchemaDocument : this.schemaDocument; - }; -} - -export const schemaReader = new SchemaReader(); diff --git a/packages/amplify-category-api/src/category-utils/show-auth-acm.ts b/packages/amplify-category-api/src/category-utils/show-auth-acm.ts deleted file mode 100644 index e5f0dab216..0000000000 --- a/packages/amplify-category-api/src/category-utils/show-auth-acm.ts +++ /dev/null @@ -1,150 +0,0 @@ -import * as path from 'path'; -import { - AccessControlMatrix, - AuthRule, - ModelOperation, - MODEL_OPERATIONS, - DEFAULT_GROUPS_FIELD, - DEFAULT_GROUP_CLAIM, - DEFAULT_OWNER_FIELD, - getAuthDirectiveRules, -} from '@aws-amplify/graphql-auth-transformer'; -import { $TSContext, stateManager, pathManager, FeatureFlags } from '@aws-amplify/amplify-cli-core'; -import { parse, ObjectTypeDefinitionNode, DirectiveNode, FieldDefinitionNode } from 'graphql'; -import { printer } from '@aws-amplify/amplify-prompts'; -import { DirectiveWrapper } from '@aws-amplify/graphql-transformer-core'; -import { readProjectSchema } from 'graphql-transformer-core'; -import { getTransformerVersion } from '../graphql-transformer'; - -export const showApiAuthAcm = async (context: $TSContext, modelName: string): Promise => { - const providerPlugin = await import(context.amplify.getProviderPlugins(context)?.awscloudformation); - const transformerVersion = await getTransformerVersion(context); - - if (transformerVersion < 2) { - printer.error('This command requires version two or greater of the GraphQL transformer.'); - return; - } - - const apiNames = Object.entries(stateManager.getMeta()?.api || {}) - .filter(([, apiResource]) => (apiResource as any).service === 'AppSync') - .map(([name]) => name); - - if (apiNames.length === 0) { - printer.info('No GraphQL API configured in the project. To add a GraphQL API run `amplify add api`.'); - return; - } - - if (apiNames.length > 1) { - // this condition should never hit as we only allow a single GraphQL API per project. - printer.error( - 'You have multiple GraphQL APIs in the project. Only one GraphQL API is allowed per project. Run `amplify remove api` to remove an API.', - ); - return; - } - - // Do a full schema compilation to make sure we are not printing an ACM for an invalid schema - try { - await providerPlugin.compileSchema(context, { - forceCompile: true, - }); - } catch (error) { - printer.warn('ACM generation requires a valid schema, the provided schema is invalid.'); - - if (error.name) { - printer.error(`${error.name}: ${error.message?.trim()}`); - } else { - printer.error(`An error has occurred during schema compilation: ${error.message?.trim()}`); - } - - return; - } - - const apiName = apiNames[0]; - const apiResourceDir = path.join(pathManager.getBackendDirPath(), 'api', apiName); - const { schema } = await readProjectSchema(apiResourceDir); - - printACM(schema, modelName); -}; - -export function printACM(sdl: string, nodeName: string) { - const schema = parse(sdl); - const type = schema.definitions.find( - (node) => - node.kind === 'ObjectTypeDefinition' && node.name.value === nodeName && node?.directives?.find((dir) => dir.name.value === 'model'), - ) as ObjectTypeDefinitionNode; - if (!type) { - throw new Error(`Model "${nodeName}" does not exist.`); - } else { - const fields: string[] = type.fields!.map((field: FieldDefinitionNode) => field.name.value); - const acm = new AccessControlMatrix({ name: type.name.value, operations: MODEL_OPERATIONS, resources: fields }); - const parentAuthDirective = type.directives?.find((dir) => dir.name.value === 'auth'); - if (parentAuthDirective) { - const authRules: AuthRule[] = getAuthDirectiveRules(new DirectiveWrapper(parentAuthDirective), { - isField: false, - deepMergeArguments: FeatureFlags.getBoolean('graphqltransformer.shouldDeepMergeDirectiveConfigDefaults'), - }); - convertModelRulesToRoles(acm, authRules); - } - for (const fieldNode of type.fields || []) { - const fieldAuthDir = fieldNode.directives?.find((dir) => dir.name.value === 'auth') as DirectiveNode; - if (fieldAuthDir) { - if (parentAuthDirective) { - acm.resetAccessForResource(fieldNode.name.value); - } - const authRules: AuthRule[] = getAuthDirectiveRules(new DirectiveWrapper(fieldAuthDir)); - convertModelRulesToRoles(acm, authRules, fieldNode.name.value); - } - } - const truthTable = acm.getAcmPerRole(); - - if (truthTable.size === 0) { - printer.warn(`No auth rules have been configured for the "${type.name.value}" model.`); - } - - for (const [role, acm] of truthTable) { - console.group(role); - console.table(acm); - console.groupEnd(); - } - } -} - -function convertModelRulesToRoles(acm: AccessControlMatrix, authRules: AuthRule[], field?: string) { - for (const rule of authRules) { - const operations: ModelOperation[] = rule.operations || MODEL_OPERATIONS; - if (rule.groups && !rule.groupsField) { - rule.groups.forEach((group) => { - const roleName = `${rule.provider}:staticGroup:${group}`; - acm.setRole({ role: roleName, resource: field, operations }); - }); - } else { - let roleName: string; - switch (rule.provider) { - case 'apiKey': - roleName = 'apiKey:public'; - break; - case 'iam': - roleName = `iam:${rule.allow}`; - break; - case 'oidc': - case 'userPools': - if (rule.allow === 'groups') { - const groupsField = rule.groupsField || DEFAULT_GROUPS_FIELD; - const groupsClaim = rule.groupClaim || DEFAULT_GROUP_CLAIM; - roleName = `${rule.provider}:dynamicGroup:${groupsClaim}:${groupsField}`; - } else if (rule.allow === 'owner') { - const ownerField = rule.ownerField || DEFAULT_OWNER_FIELD; - roleName = `${rule.provider}:owner:${ownerField}`; - } else if (rule.allow === 'private') { - roleName = `${rule.provider}:${rule.allow}`; - } else { - throw new Error(`Could not create a role from ${JSON.stringify(rule)}`); - } - break; - default: - throw new Error(`Could not create a role from ${JSON.stringify(rule)}`); - } - acm.setRole({ role: roleName, resource: field, operations }); - } - } -} diff --git a/packages/amplify-category-api/src/commands/api.ts b/packages/amplify-category-api/src/commands/api.ts deleted file mode 100644 index 2b27b10f51..0000000000 --- a/packages/amplify-category-api/src/commands/api.ts +++ /dev/null @@ -1,76 +0,0 @@ -import * as path from 'path'; -import { $TSContext, AmplifyCategories } from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; - -export const name = AmplifyCategories.API; - -export const run = async (context: $TSContext) => { - if (/^win/.test(process.platform)) { - try { - const { run } = await import(path.join('.', AmplifyCategories.API, context.parameters.first)); - return run(context); - } catch (e) { - printer.error('Command not found'); - } - } - const header = `amplify ${AmplifyCategories.API} `; - const commands = [ - { - name: 'add', - description: `Takes you through a CLI flow to add a ${AmplifyCategories.API} resource to your local backend`, - }, - { - name: 'push', - description: `Provisions ${AmplifyCategories.API} cloud resources and its dependencies with the latest local developments`, - }, - { - name: 'remove', - description: `Removes ${AmplifyCategories.API} resource from your local backend which would be removed from the cloud on the next push command`, - }, - { - name: 'update', - description: `Takes you through steps in the CLI to update an ${AmplifyCategories.API} resource`, - }, - { - name: 'gql-compile', - description: 'Compiles your GraphQL schema and generates a corresponding cloudformation template', - }, - { - name: 'add-graphql-datasource', - description: 'Provisions the AppSync resources and its dependencies for the provided Aurora Serverless data source', - }, - { - name: 'console', - description: 'Opens the web console for the selected api service', - }, - { - name: 'migrate', - description: 'Migrates GraphQL schemas to the latest GraphQL transformer version', - }, - { - name: 'rebuild', - description: - 'Removes and recreates all DynamoDB tables backing a GraphQL API. Useful for resetting test data during the development phase of an app', - }, - { - name: 'override', - description: 'Generates overrides file to apply custom modifications to CloudFormation', - }, - { - name: 'import', - description: 'Imports existing datasource to GraphQL API', - }, - { - name: 'generate-schema', - description: 'Generates the GraphQL schema from the Data Source', - }, - { - name: 'update-secrets', - description: 'Updates the API plugin related secrets', - }, - ]; - - context.amplify.showHelp(header, commands); - - printer.blankLine(); -}; diff --git a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.ts b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.ts deleted file mode 100644 index 0de060754a..0000000000 --- a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.ts +++ /dev/null @@ -1,254 +0,0 @@ -import * as path from 'path'; -import { mergeTypeDefs } from '@graphql-tools/merge'; -import { - $TSContext, - AmplifyError, - exitOnNextTick, - FeatureFlags, - pathManager, - ResourceDoesNotExistError, - stateManager, -} from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; -import * as fs from 'fs-extra'; -import * as graphql from 'graphql'; -import { - AuroraServerlessMySQLDatabaseReader, - RelationalDBSchemaTransformer, - RelationalDBTemplateGenerator, -} from 'graphql-relational-schema-transformer'; -import inquirer from 'inquirer'; -import _ from 'lodash'; -import { getEnvParamManager } from '@aws-amplify/amplify-environment-parameters'; -import { supportedDataSources } from '../../provider-utils/supported-datasources'; - -const subcommand = 'add-graphql-datasource'; -const category = 'api'; -const providerName = 'awscloudformation'; - -export const name = subcommand; - -/** - * Entry point for adding RDS data source - */ -export const run = async (context: $TSContext): Promise => { - try { - const AWS = await getAwsClient(context, 'list'); - - const result: any = await datasourceSelectionPrompt(context, supportedDataSources); - - const providerController = await import(path.join('..', '..', 'provider-utils', result.providerName, 'index')); - - if (!providerController) { - printer.error('Provider not configured for this category'); - return; - } - - const { datasource } = result; - const answers = await providerController.addDatasource(context, category, datasource); - - const { resourceName, databaseName } = answers; - - /** - * Setting the params using getEnvParamManager.getResourceParamManager.setParams updates - * the team-provider-info file - */ - const currentEnv = context.amplify.getEnvInfo().envName; - - getEnvParamManager(currentEnv).getResourceParamManager(category, resourceName).setParams({ - rdsRegion: answers.region, - rdsClusterIdentifier: answers.dbClusterArn, - rdsSecretStoreArn: answers.secretStoreArn, - rdsDatabaseName: answers.databaseName, - }); - - const backendConfig = stateManager.getBackendConfig(); - - backendConfig[category][resourceName].rdsInit = true; - - stateManager.setBackendConfig(undefined, backendConfig); - - /** - * Load the MySqlRelationalDBReader - */ - const dbReader = new AuroraServerlessMySQLDatabaseReader( - answers.region, - answers.secretStoreArn, - answers.dbClusterArn, - answers.databaseName, - AWS, - ); - - /** - * Instantiate a new Relational Schema Transformer and perform - * the db introspection to get the GraphQL Schema and Template Context - */ - // eslint-disable-next-line spellcheck/spell-checker - const improvePluralizationFlag = FeatureFlags.getBoolean('graphqltransformer.improvePluralization'); - const relationalSchemaTransformer = new RelationalDBSchemaTransformer(dbReader, answers.databaseName, improvePluralizationFlag); - const graphqlSchemaContext = await relationalSchemaTransformer.introspectDatabaseSchema(); - - if (graphqlSchemaContext === null) { - printer.warn('No importable tables were found in the selected Database.'); - printer.blankLine(); - return; - } - - /** - * Merge the GraphQL Schema with the existing schema.graphql in the projects stack - * - */ - const apiDirPath = pathManager.getResourceDirectoryPath(undefined, category, resourceName); - - fs.ensureDirSync(apiDirPath); - - const graphqlSchemaFilePath = path.join(apiDirPath, 'schema.graphql'); - const rdsGraphQLSchemaDoc = graphqlSchemaContext.schemaDoc; - const schemaDirectoryPath = path.join(apiDirPath, 'schema'); - - if (fs.existsSync(graphqlSchemaFilePath)) { - const typesToBeMerged = [rdsGraphQLSchemaDoc]; - const currentGraphQLSchemaDoc = readSchema(graphqlSchemaFilePath); - - if (currentGraphQLSchemaDoc) { - typesToBeMerged.unshift(currentGraphQLSchemaDoc); - } else { - printer.warn(`Graphql Schema file "${graphqlSchemaFilePath}" is empty.`); - printer.blankLine(); - } - - const concatGraphQLSchemaDoc = mergeTypeDefs(typesToBeMerged); - - fs.writeFileSync(graphqlSchemaFilePath, graphql.print(concatGraphQLSchemaDoc), 'utf8'); - } else if (fs.existsSync(schemaDirectoryPath)) { - const rdsSchemaFilePath = path.join(schemaDirectoryPath, 'sql.graphql'); - - fs.writeFileSync(rdsSchemaFilePath, graphql.print(rdsGraphQLSchemaDoc), 'utf8'); - } else { - throw new AmplifyError('ApiCategorySchemaNotFoundError', { - message: 'No schema found', - resolution: `Your SQL schema should be in either ${graphqlSchemaFilePath} or schema directory ${schemaDirectoryPath}`, - }); - } - - const resolversDir = path.join(apiDirPath, 'resolvers'); - - /** - * Instantiate a new Relational Template Generator and create - * the template and relational resolvers - */ - - const templateGenerator = new RelationalDBTemplateGenerator(graphqlSchemaContext); - - let template = templateGenerator.createTemplate(context); - - template = templateGenerator.addRelationalResolvers(template, resolversDir, improvePluralizationFlag); - - const cfn = templateGenerator.printCloudformationTemplate(template); - - /** - * Add the generated the CFN to the appropriate nested stacks directory - */ - - const stacksDir = path.join(apiDirPath, 'stacks'); - const writeToPath = path.join(stacksDir, `${resourceName}-${databaseName}-rds.json`); - - fs.writeFileSync(writeToPath, cfn, 'utf8'); - - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); - - printer.success(`Successfully added the ${datasource} datasource locally`); - printer.blankLine(); - printer.success('Some next steps:'); - printer.info('"amplify push" will build all your local backend resources and provision it in the cloud'); - printer.info( - '"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud', - ); - printer.blankLine(); - } catch (error) { - printer.error('There was an error adding the datasource'); - throw error; - } -}; - -// eslint-disable-next-line @typescript-eslint/no-shadow -const datasourceSelectionPrompt = async (context: $TSContext, supportedDataSources): Promise => { - const options = []; - Object.keys(supportedDataSources).forEach((datasource) => { - const optionName = - supportedDataSources[datasource].alias || - `${supportedDataSources[datasource].providerName}:${supportedDataSources[datasource].service}`; - options.push({ - name: optionName, - value: { - provider: supportedDataSources[datasource].provider, - datasource, - providerName: supportedDataSources[datasource].provider, - }, - }); - }); - - if (options.length === 0) { - const errMessage = `No data sources defined by configured providers for category: ${category}`; - - printer.error(errMessage); - - await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - - exitOnNextTick(1); - } - - if (options.length === 1) { - // No need to ask questions - printer.info(`Using datasource: ${options[0].value.datasource}, provided by: ${options[0].value.providerName}`); - - return new Promise((resolve) => { - resolve(options[0].value); - }); - } - - const question = [ - { - name: 'datasource', - message: 'Please select from one of the below mentioned data sources', - type: 'list', - choices: options, - }, - ]; - - return inquirer.prompt(question).then((answer) => answer.datasource); -}; - -const getAwsClient = async (context: $TSContext, action: string): Promise => { - const providerPlugins = context.amplify.getProviderPlugins(context); - // eslint-disable-next-line - const provider = require(providerPlugins[providerName]); - - return provider.getConfiguredAWSClient(context, 'aurora-serverless', action); -}; - -/** - * Read the GraphQL schema - */ -export const readSchema = (graphqlSchemaFilePath: string): graphql.DocumentNode => { - const graphqlSchemaRaw = fs.readFileSync(graphqlSchemaFilePath).toString(); - - if (graphqlSchemaRaw.trim().length === 0) { - return null; - } - - let currentGraphQLSchemaDoc: graphql.DocumentNode; - - try { - currentGraphQLSchemaDoc = graphql.parse(graphqlSchemaRaw); - } catch (err) { - const relativePathToInput = path.relative(process.cwd(), graphqlSchemaRaw); - throw new AmplifyError('UserInputError', { - message: `Could not parse graphql scehma \n${relativePathToInput}\n`, - details: err.message, - link: 'https://docs.amplify.aws/cli-legacy/graphql-transformer/relational/', - }); - } - - return currentGraphQLSchemaDoc; -}; diff --git a/packages/amplify-category-api/src/commands/api/add.ts b/packages/amplify-category-api/src/commands/api/add.ts deleted file mode 100644 index 7ff8f270e0..0000000000 --- a/packages/amplify-category-api/src/commands/api/add.ts +++ /dev/null @@ -1,62 +0,0 @@ -import * as path from 'path'; -import { $TSContext, AmplifyCategories, AmplifySupportedService } from '@aws-amplify/amplify-cli-core'; -import { printer, prompter } from '@aws-amplify/amplify-prompts'; - -const subcommand = 'add'; -const category = AmplifyCategories.API; - -export const name = subcommand; - -export const run = async (context: $TSContext) => { - const servicesMetadata = (await import(path.join('..', '..', 'provider-utils', 'supported-services'))).supportedServices; - return context.amplify - .serviceSelectionPrompt(context, category, servicesMetadata) - .then(async (result) => { - const options = { - service: result.service, - providerPlugin: result.providerName, - }; - const providerController = await import(path.join('..', '..', 'provider-utils', result.providerName, 'index')); - if (!providerController) { - printer.error('Provider not configured for this category'); - return; - } - - if ((await shouldUpdateExistingRestApi(context, result.service)) === true) { - return providerController.updateResource(context, category, result.service, { allowContainers: false }); - } - - return providerController.addResource(context, result.service, options); - }) - .then((resourceName: string) => { - printer.success(`Successfully added resource ${resourceName} locally`); - printer.blankLine(); - printer.success('Some next steps:'); - printer.info('"amplify push" will build all your local backend resources and provision it in the cloud'); - printer.info( - '"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud', - ); - printer.blankLine(); - }) - .catch(async (err) => { - printer.error('There was an error adding the API resource'); - throw err; - }); -}; - -async function shouldUpdateExistingRestApi(context: $TSContext, selectedService: string): Promise { - if (selectedService !== AmplifySupportedService.APIGW) { - return false; - } - - const { allResources } = await context.amplify.getResourceStatus(); - const hasRestApis = allResources.some( - (resource: Record) => resource.service === AmplifySupportedService.APIGW && resource.mobileHubMigrated !== true, - ); - - if (!hasRestApis) { - return false; - } - - return prompter.confirmContinue('Would you like to add a new path to an existing REST API:'); -} diff --git a/packages/amplify-category-api/src/commands/api/console.ts b/packages/amplify-category-api/src/commands/api/console.ts deleted file mode 100644 index 85a1118e3b..0000000000 --- a/packages/amplify-category-api/src/commands/api/console.ts +++ /dev/null @@ -1,22 +0,0 @@ -import * as path from 'path'; -import { $TSContext, AmplifyCategories } from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; - -const subcommand = 'console'; - -export const name = subcommand; - -export const run = async (context: $TSContext) => { - const servicesMetadata = (await import(path.join('..', '..', 'provider-utils', 'supported-services'))).supportedServices; - const result = await context.amplify.serviceSelectionPrompt(context, AmplifyCategories.API, servicesMetadata); - try { - const providerController = await import(path.join('..', '..', 'provider-utils', result.providerName, 'index')); - if (!providerController) { - throw new Error(`Provider "${result.providerName}" is not configured for this category`); - } - return providerController.console(context, result.service); - } catch (err) { - printer.error('Error opening console.'); - throw err; - } -}; diff --git a/packages/amplify-category-api/src/commands/api/generate-schema.ts b/packages/amplify-category-api/src/commands/api/generate-schema.ts deleted file mode 100644 index 3b0d4c41de..0000000000 --- a/packages/amplify-category-api/src/commands/api/generate-schema.ts +++ /dev/null @@ -1,98 +0,0 @@ -import * as path from 'path'; -import { $TSContext, AmplifyError, ApiCategoryFacade } from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; -import fs from 'fs-extra'; -import _ from 'lodash'; -import { SQL_SCHEMA_FILE_NAME, ImportedDataSourceConfig, ImportedRDSType } from '@aws-amplify/graphql-transformer-core'; -import { graphqlSchemaFromSQLSchema } from '@aws-amplify/graphql-schema-generator'; -import { getAppSyncAPIName, getAPIResourceDir } from '../../provider-utils/awscloudformation/utils/amplify-meta-utils'; -import { - storeConnectionSecrets, - getSecretsKey, - getDatabaseName, - getConnectionSecrets, -} from '../../provider-utils/awscloudformation/utils/rds-resources/database-resources'; -import { writeSchemaFile, generateRDSSchema } from '../../provider-utils/awscloudformation/utils/graphql-schema-utils'; -import { PREVIEW_BANNER } from '../../category-constants'; -import { parse } from 'graphql'; -import { getEngineInput } from '../../provider-utils/awscloudformation/utils/rds-input-utils'; - -const subcommand = 'generate-schema'; - -export const name = subcommand; - -export const run = async (context: $TSContext): Promise => { - const transformerVersion = await ApiCategoryFacade.getTransformerVersion(context); - if (transformerVersion !== 2) { - throw new AmplifyError('InvalidDirectiveError', { - message: 'Imported SQL schema can only generate a GraphQL schema with the version 2 transformer.', - }); - } - const sqlSchema = context.parameters?.options?.['sql-schema']; - const engineType = context.parameters?.options?.['engine-type']; - const out = context.parameters?.options?.out; - // unauthenticated flow - if (sqlSchema || engineType || out) { - if (!(sqlSchema && engineType && out)) { - if (!sqlSchema) { - throw new AmplifyError('UserInputError', { message: 'A SQL schema must be provided with --sql-schema' }); - } - if (!engineType) { - throw new AmplifyError('UserInputError', { message: 'An engine type must be provided with --engine-type' }); - } - if (!out) { - throw new AmplifyError('UserInputError', { message: 'An output path must be provided with --out' }); - } - } - if (!Object.values(ImportedRDSType).includes(engineType)) { - throw new AmplifyError('UserInputError', { message: `${engineType} is not a supported engine type.` }); - } - if (!fs.existsSync(sqlSchema)) { - throw new AmplifyError('UserInputError', { message: `SQL schema file ${sqlSchema} does not exists.` }); - } - const schema = await graphqlSchemaFromSQLSchema(fs.readFileSync(sqlSchema, 'utf8'), engineType); - writeSchemaFile(out, schema); - } else { - printer.warn(PREVIEW_BANNER); - const apiName = getAppSyncAPIName(); - const apiResourceDir = getAPIResourceDir(apiName); - - // proceed if there are any existing imported Relational Data Sources - const pathToSchemaFile = path.join(apiResourceDir, SQL_SCHEMA_FILE_NAME); - - if (!fs.existsSync(pathToSchemaFile)) { - throw new AmplifyError('UserInputError', { message: 'No imported Data Sources to Generate GraphQL Schema.' }); - } - - const importedSchema = parse(fs.readFileSync(pathToSchemaFile, 'utf8')); - const engine = await getEngineInput(importedSchema); - - const secretsKey = getSecretsKey(); - const database = await getDatabaseName(context, apiName, secretsKey); - if (!database) { - throw new AmplifyError('UserInputError', { - message: - 'Cannot fetch the imported database name to generate the schema. Use "amplify api update-secrets" to update the database information.', - }); - } - - // read and validate the RDS connection secrets - const { secrets, storeSecrets } = await getConnectionSecrets(context, secretsKey, engine); - const databaseConfig: ImportedDataSourceConfig = { - ...secrets, - engine, - }; - - const schemaString = await generateRDSSchema(context, databaseConfig, pathToSchemaFile); - // If connection is successful, store the secrets in parameter store - if (storeSecrets) { - await storeConnectionSecrets(context, secrets, apiName, secretsKey); - } - writeSchemaFile(pathToSchemaFile, schemaString); - - if (_.isEmpty(schemaString)) { - printer.warn('If your schema file is empty, it is likely that your database has no tables.'); - } - printer.info(`Successfully imported the schema definition for ${databaseConfig.database} database into ${pathToSchemaFile}`); - } -}; diff --git a/packages/amplify-category-api/src/commands/api/gql-compile.ts b/packages/amplify-category-api/src/commands/api/gql-compile.ts deleted file mode 100644 index fd40d9e541..0000000000 --- a/packages/amplify-category-api/src/commands/api/gql-compile.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { forceRefreshSchema } from '../../force-updates/force-refresh-schema'; - -const subcommand = 'gql-compile'; - -export const name = subcommand; - -export const run = async (context: $TSContext) => { - if (context?.input?.options?.force) { - forceRefreshSchema(); - } - return context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); -}; diff --git a/packages/amplify-category-api/src/commands/api/import.ts b/packages/amplify-category-api/src/commands/api/import.ts deleted file mode 100644 index cb67993e6e..0000000000 --- a/packages/amplify-category-api/src/commands/api/import.ts +++ /dev/null @@ -1,31 +0,0 @@ -import * as path from 'path'; -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; -import fs from 'fs-extra'; -import { SQL_SCHEMA_FILE_NAME } from '@aws-amplify/graphql-transformer-core'; -import { importAppSyncAPIWalkthrough } from '../../provider-utils/awscloudformation/service-walkthroughs/import-appsync-api-walkthrough'; -import { getAPIResourceDir } from '../../provider-utils/awscloudformation/utils/amplify-meta-utils'; -import { writeSchemaFile, generateRDSSchema } from '../../provider-utils/awscloudformation/utils/graphql-schema-utils'; -import { PREVIEW_BANNER } from '../../category-constants'; - -const subcommand = 'import'; - -export const name = subcommand; - -export const run = async (context: $TSContext) => { - printer.warn(PREVIEW_BANNER); - const importAppSyncAPIWalkInputs = await importAppSyncAPIWalkthrough(context); - - if (importAppSyncAPIWalkInputs?.dataSourceConfig) { - // ensure imported API resource artifacts are created - const apiResourceDir = getAPIResourceDir(importAppSyncAPIWalkInputs.apiName); - fs.ensureDirSync(apiResourceDir); - - const pathToSchemaFile = path.join(apiResourceDir, SQL_SCHEMA_FILE_NAME); - const schemaString = await generateRDSSchema(context, importAppSyncAPIWalkInputs.dataSourceConfig, pathToSchemaFile); - writeSchemaFile(pathToSchemaFile, schemaString); - - // print next steps - printer.info(`Successfully imported the database schema into ${pathToSchemaFile}.`); - } -}; diff --git a/packages/amplify-category-api/src/commands/api/migrate.ts b/packages/amplify-category-api/src/commands/api/migrate.ts deleted file mode 100644 index fb231b050b..0000000000 --- a/packages/amplify-category-api/src/commands/api/migrate.ts +++ /dev/null @@ -1,47 +0,0 @@ -import * as path from 'path'; -import { $TSContext, AmplifyCategories, pathManager, stateManager, FeatureFlags } from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; -import { attemptV2TransformerMigration, revertV2Migration } from '@aws-amplify/graphql-transformer-migrator'; -import { checkAppsyncApiResourceMigration } from '../../provider-utils/awscloudformation/utils/check-appsync-api-migration'; - -const subcommand = 'migrate'; - -export const name = subcommand; - -export const run = async (context: $TSContext) => { - const apiNames = Object.entries(stateManager.getMeta()?.api || {}) - .filter(([_, apiResource]) => (apiResource as any).service === 'AppSync') - .map(([name]) => name); - if (apiNames.length === 0) { - printer.info( - 'No GraphQL API configured in the project. Only GraphQL APIs can be migrated. To add a GraphQL API run `amplify add api`.', - ); - return; - } - if (apiNames.length > 1) { - // this condition should never hit as we have upstream defensive logic to prevent multiple GraphQL APIs. But just to cover all the bases - printer.error( - 'You have multiple GraphQL APIs in the project. Only one GraphQL API is allowed per project. Run `amplify remove api` to remove an API.', - ); - return; - } - const apiName = apiNames[0]; - const apiResourceDir = path.join(pathManager.getBackendDirPath(), AmplifyCategories.API, apiName); - - if (await checkAppsyncApiResourceMigration(context, apiName, true)) { - await context.amplify.invokePluginMethod(context, 'awscloudformation', undefined, 'compileSchema', [context, { forceCompile: true }]); - } - - if (context.parameters?.options?.revert) { - await revertV2Migration(apiResourceDir, stateManager.getCurrentEnvName()); - return; - } - const transformerVersion = FeatureFlags.getNumber('graphqltransformer.transformerversion'); - const improvePluralization = FeatureFlags.getBoolean('graphqltransformer.improvepluralization'); - await attemptV2TransformerMigration( - apiResourceDir, - apiName, - { transformerVersion, improvePluralization }, - stateManager.getCurrentEnvName(), - ); -}; diff --git a/packages/amplify-category-api/src/commands/api/override.ts b/packages/amplify-category-api/src/commands/api/override.ts deleted file mode 100644 index 1e018d1324..0000000000 --- a/packages/amplify-category-api/src/commands/api/override.ts +++ /dev/null @@ -1,97 +0,0 @@ -import * as path from 'path'; -import { - $TSContext, - AmplifyCategories, - AmplifySupportedService, - ApiCategoryFacade, - generateOverrideSkeleton, - pathManager, - stateManager, -} from '@aws-amplify/amplify-cli-core'; -import { printer, prompter } from '@aws-amplify/amplify-prompts'; -import { ADMIN_QUERIES_NAME } from '../../category-constants'; -import { AdminQueriesProps, ApigwInputState } from '../../provider-utils/awscloudformation/apigw-input-state'; -import { ApigwStackTransform } from '../../provider-utils/awscloudformation/cdk-stack-builder'; -import { checkAppsyncApiResourceMigration } from '../../provider-utils/awscloudformation/utils/check-appsync-api-migration'; - -export const name = 'override'; - -export const run = async (context: $TSContext) => { - const amplifyMeta = stateManager.getMeta(); - const apiResources: string[] = []; - - if (amplifyMeta[AmplifyCategories.API]) { - Object.keys(amplifyMeta[AmplifyCategories.API]).forEach((resourceName) => { - apiResources.push(resourceName); - }); - } - - if (apiResources.length === 0) { - const errMessage = 'No resources to override. You need to add a resource.'; - printer.error(errMessage); - return; - } - - let selectedResourceName: string = apiResources[0]; - - if (apiResources.length > 1) { - selectedResourceName = await prompter.pick('Which resource would you like to add overrides for?', apiResources); - } - - const { service }: { service: string } = amplifyMeta[AmplifyCategories.API][selectedResourceName]; - const destPath = pathManager.getResourceDirectoryPath(undefined, AmplifyCategories.API, selectedResourceName); - - const srcPath = path.join( - __dirname, - '..', - '..', - '..', - 'resources', - 'awscloudformation', - 'overrides-resource', - service === AmplifySupportedService.APIGW ? 'APIGW' : service, // avoid space in filename - ); - - // Make sure to migrate first - if (service === AmplifySupportedService.APPSYNC) { - /** - * Below steps checks for TransformerV1 app and updates the FF { useexperimentalpipelinedtransformer , transformerversion} - */ - const transformerVersion = await ApiCategoryFacade.getTransformerVersion(context); - if (transformerVersion === 2 && (await checkAppsyncApiResourceMigration(context, selectedResourceName, false))) { - await context.amplify.invokePluginMethod(context, 'awscloudformation', undefined, 'compileSchema', [context, { forceCompile: true }]); - await generateOverrideSkeleton(context, srcPath, destPath); - } else { - printer.warn( - 'The GraphQL API is using transformer version 1. Run `amplify migrate api` to upgrade to transformer version 2 and rerun amplify override api to enable override functionality for API', - ); - } - } else if (service === AmplifySupportedService.APIGW) { - // Migration logic goes in here - const apigwInputState = new ApigwInputState(context, selectedResourceName); - if (!apigwInputState.cliInputsFileExists()) { - if (selectedResourceName === ADMIN_QUERIES_NAME) { - const { dependsOn }: { dependsOn: Record[] } = amplifyMeta[AmplifyCategories.API][selectedResourceName]; - if (!Array.isArray(dependsOn) || dependsOn.length === 0) { - throw new Error(`Invalid dependsOn entry found in amplify-meta.json for "${ADMIN_QUERIES_NAME}"`); - } - - const getResourceNameFromDependsOn = (categoryName: string, dependsOn: Record[]) => - dependsOn.filter((entry) => entry.category === categoryName)[0].resourceName; - - const props: AdminQueriesProps = { - apiName: selectedResourceName, - authResourceName: getResourceNameFromDependsOn(AmplifyCategories.AUTH, dependsOn), - functionName: getResourceNameFromDependsOn(AmplifyCategories.FUNCTION, dependsOn), - dependsOn: dependsOn, - }; - await apigwInputState.migrateAdminQueries(props); - } else { - await apigwInputState.migrateApigwResource(selectedResourceName); - const stackGenerator = new ApigwStackTransform(context, selectedResourceName); - await stackGenerator.transform(); - } - } - await generateOverrideSkeleton(context, srcPath, destPath); - } -}; diff --git a/packages/amplify-category-api/src/commands/api/push.ts b/packages/amplify-category-api/src/commands/api/push.ts deleted file mode 100644 index 88519203b5..0000000000 --- a/packages/amplify-category-api/src/commands/api/push.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { $TSContext, AmplifyCategories } from '@aws-amplify/amplify-cli-core'; - -const subcommand = 'push'; - -export const name = subcommand; - -export const run = async (context: $TSContext) => { - const resourceName = context.parameters.first; - context.amplify.constructExeInfo(context); - return context.amplify.pushResources(context, AmplifyCategories.API, resourceName); -}; diff --git a/packages/amplify-category-api/src/commands/api/rebuild.ts b/packages/amplify-category-api/src/commands/api/rebuild.ts deleted file mode 100644 index a37c6e0a2a..0000000000 --- a/packages/amplify-category-api/src/commands/api/rebuild.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { $TSContext, AmplifyCategories, FeatureFlags, stateManager } from '@aws-amplify/amplify-cli-core'; -import { printer, prompter, exact } from '@aws-amplify/amplify-prompts'; - -const subcommand = 'rebuild'; - -export const name = subcommand; - -const rebuild = true; - -export const run = async (context: $TSContext) => { - if (!FeatureFlags.getBoolean('graphqlTransformer.enableIterativeGSIUpdates')) { - printer.error('Iterative GSI Updates must be enabled to rebuild an API. See https://docs.amplify.aws/cli/reference/feature-flags/'); - return; - } - const apiNames = Object.entries(stateManager.getMeta()?.api || {}) - .filter(([_, apiResource]) => (apiResource as any).service === 'AppSync') - .map(([name]) => name); - if (apiNames.length === 0) { - printer.info('No GraphQL API configured in the project. Only GraphQL APIs can be rebuilt. To add a GraphQL API run `amplify add api`.'); - return; - } - if (apiNames.length > 1) { - // this condition should never hit as we have upstream defensive logic to prevent multiple GraphQL APIs. But just to cover all the bases - printer.error( - 'You have multiple GraphQL APIs in the project. Only one GraphQL API is allowed per project. Run `amplify remove api` to remove an API.', - ); - return; - } - const apiName = apiNames[0]; - printer.warn(`This will recreate all tables backing models in your GraphQL API ${apiName}.`); - printer.warn('ALL EXISTING DATA IN THESE TABLES WILL BE LOST.'); - await prompter.input('Type the name of the API to confirm you want to continue', { - validate: exact(apiName, 'Input does not match the GraphQL API name'), - }); - const { amplify, parameters } = context; - const resourceName = parameters.first; - amplify.constructExeInfo(context); - return amplify.pushResources(context, AmplifyCategories.API, resourceName, undefined, rebuild); -}; diff --git a/packages/amplify-category-api/src/commands/api/remove.ts b/packages/amplify-category-api/src/commands/api/remove.ts deleted file mode 100644 index 389a5409ef..0000000000 --- a/packages/amplify-category-api/src/commands/api/remove.ts +++ /dev/null @@ -1,30 +0,0 @@ -import * as path from 'path'; -import { $TSContext, AmplifyCategories, AmplifySupportedService } from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; - -const subcommand = 'remove'; -const gqlConfigFilename = '.graphqlconfig.yml'; - -export const name = subcommand; - -export const run = async (context: $TSContext) => { - const resourceName = context.parameters.first; - - const resourceValues = await context.amplify.removeResource(context, AmplifyCategories.API, resourceName, { - serviceSuffix: { [AmplifySupportedService.APPSYNC]: '(GraphQL API)', [AmplifySupportedService.APIGW]: '(REST API)' }, - }); - try { - if (!resourceValues) { - return; - } // indicates that the customer selected "no" at the confirmation prompt - if (resourceValues.service === AmplifySupportedService.APPSYNC) { - const { projectPath } = context.amplify.getEnvInfo(); - - const gqlConfigFile = path.normalize(path.join(projectPath, gqlConfigFilename)); - context.filesystem.remove(gqlConfigFile); - } - } catch (err) { - printer.error('There was an error removing the api resource'); - throw err; - } -}; diff --git a/packages/amplify-category-api/src/commands/api/update-secrets.ts b/packages/amplify-category-api/src/commands/api/update-secrets.ts deleted file mode 100644 index b521c082cc..0000000000 --- a/packages/amplify-category-api/src/commands/api/update-secrets.ts +++ /dev/null @@ -1,42 +0,0 @@ -import * as path from 'path'; -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; -import fs from 'fs-extra'; -import _ from 'lodash'; -import { SQL_SCHEMA_FILE_NAME, ImportedDataSourceConfig } from '@aws-amplify/graphql-transformer-core'; -import { databaseConfigurationInputWalkthrough } from '../../provider-utils/awscloudformation/service-walkthroughs/appSync-rds-db-config'; -import { getAppSyncAPIName, getAPIResourceDir } from '../../provider-utils/awscloudformation/utils/amplify-meta-utils'; -import { storeConnectionSecrets, getSecretsKey } from '../../provider-utils/awscloudformation/utils/rds-resources/database-resources'; -import { PREVIEW_BANNER } from '../../category-constants'; -import { parse } from 'graphql'; -import { getEngineInput } from '../../provider-utils/awscloudformation/utils/rds-input-utils'; - -const subcommand = 'update-secrets'; - -export const name = subcommand; - -export const run = async (context: $TSContext) => { - printer.warn(PREVIEW_BANNER); - - const apiName = getAppSyncAPIName(); - const apiResourceDir = getAPIResourceDir(apiName); - - // proceed if there are any existing imported Relational Data Sources - const pathToSchemaFile = path.join(apiResourceDir, SQL_SCHEMA_FILE_NAME); - if (!fs.existsSync(pathToSchemaFile)) { - printer.info('No imported Data Sources to update the secrets.'); - return; - } - - const importedSchema = parse(fs.readFileSync(pathToSchemaFile, 'utf8')); - const engine = await getEngineInput(importedSchema); - - const secretsKey = await getSecretsKey(); - - // read and validate the RDS connection parameters - const databaseConfig: ImportedDataSourceConfig = await databaseConfigurationInputWalkthrough(engine); - - await storeConnectionSecrets(context, databaseConfig, apiName, secretsKey); - - printer.info('Successfully updated the secrets for the database.'); -}; diff --git a/packages/amplify-category-api/src/commands/api/update.ts b/packages/amplify-category-api/src/commands/api/update.ts deleted file mode 100644 index ddeb526539..0000000000 --- a/packages/amplify-category-api/src/commands/api/update.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as path from 'path'; -import { $TSContext, AmplifyCategories } from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; - -const subcommand = 'update'; - -export const name = subcommand; -export const alias = ['configure']; - -export const run = async (context: $TSContext) => { - const servicesMetadata = (await import(path.join('..', '..', 'provider-utils', 'supported-services'))).supportedServices; - - return context.amplify - .serviceSelectionPrompt(context, AmplifyCategories.API, servicesMetadata) - .then(async (result) => { - const providerController = await import(path.join('..', '..', 'provider-utils', result.providerName, 'index')); - if (!providerController) { - printer.error('Provider not configured for this category'); - return; - } - return providerController.updateResource(context, AmplifyCategories.API, result.service); - }) - .then(() => printer.success('Successfully updated resource')); -}; diff --git a/packages/amplify-category-api/src/errors/amplify-error-converter.ts b/packages/amplify-category-api/src/errors/amplify-error-converter.ts deleted file mode 100644 index 7ba62becd2..0000000000 --- a/packages/amplify-category-api/src/errors/amplify-error-converter.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { AmplifyError, AmplifyErrorType } from '@aws-amplify/amplify-cli-core'; - -const amplifyGraphQLErrorCodes = new Set([ - 'InvalidDirectiveError', - 'InvalidTransformerError', - 'SchemaValidationError', - 'TransformerContractError', - 'DestructiveMigrationError', - 'InvalidMigrationError', - 'InvalidGSIMigrationError', - 'UnknownDirectiveError', - 'GraphQLError', - 'ApiCategorySchemaNotFoundError', - 'InvalidOverrideError', -]); - -/** - * error can be an AmplifyException Type or Error type or any type - */ -export abstract class AmplifyGraphQLTransformerErrorConverter { - /** - * create - * @param error : default error to be thrown if not present in list : amplifyErrorList - */ - static convert = (error: any): any => { - if (error instanceof Error && error?.name && amplifyGraphQLErrorCodes.has(error.name)) { - const amplifyErrorType = `${error.name}` as AmplifyErrorType; - return new AmplifyError( - amplifyErrorType, - { - message: error.message, // message is not enumerable - ...error, - }, - error, - ); - } - return error; - }; -} diff --git a/packages/amplify-category-api/src/force-updates/api-resource-paths.ts b/packages/amplify-category-api/src/force-updates/api-resource-paths.ts deleted file mode 100644 index af27af1b55..0000000000 --- a/packages/amplify-category-api/src/force-updates/api-resource-paths.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { pathManager, stateManager } from '@aws-amplify/amplify-cli-core'; -import fs from 'fs-extra'; - -/** - * Checks the project root meta for a resource related to AppSync, and if the expected path exists, returns true, else false. - * @returns a boolean indicating if there is a graphql api on the project. - */ -const containsGraphQLApi = (): boolean => { - const projectPath = pathManager.findProjectRoot() ?? process.cwd(); - const meta = stateManager.getMeta(projectPath); - - const apiNames = Object.entries(meta?.api || {}) - .filter(([_, apiResource]) => (apiResource as any).service === 'AppSync') - .map(([name]) => name); - - const doesNotHaveGqlApi = apiNames.length < 1; - - if (doesNotHaveGqlApi) { - return false; - } - - const apiName = apiNames[0]; - const apiResourceDir = pathManager.getResourceDirectoryPath(projectPath, 'api', apiName); - - if (!fs.existsSync(apiResourceDir)) { - return false; - } - - return true; -}; - -/** - * Search for the single GraphQL Api in the project, and return the path. - * @returns the path to the resource directory for a graphql api, of undefined if not found. - */ -export const getApiResourceDir = (): string | undefined => { - const hasGraphQLApi = containsGraphQLApi(); - if (!hasGraphQLApi) { - return undefined; - } - - const projectPath = pathManager.findProjectRoot() ?? process.cwd(); - const meta = stateManager.getMeta(projectPath); - - const apiNames = Object.entries(meta?.api || {}) - .filter(([_, apiResource]) => (apiResource as any).service === 'AppSync') - .map(([name]) => name); - - const apiName = apiNames[0]; - const apiResourceDir = pathManager.getResourceDirectoryPath(projectPath, 'api', apiName); - - return apiResourceDir; -}; diff --git a/packages/amplify-category-api/src/force-updates/auth-notifications.ts b/packages/amplify-category-api/src/force-updates/auth-notifications.ts deleted file mode 100644 index 70ae74838d..0000000000 --- a/packages/amplify-category-api/src/force-updates/auth-notifications.ts +++ /dev/null @@ -1,244 +0,0 @@ -import path from 'path'; -import { $TSContext, exitOnNextTick, FeatureFlags, pathManager, stateManager } from '@aws-amplify/amplify-cli-core'; -import { printer, prompter } from '@aws-amplify/amplify-prompts'; -import { DirectiveNode, DocumentNode, FieldDefinitionNode, FieldNode, parse } from 'graphql'; -import { collectDirectivesByType, collectDirectivesByTypeNames, readProjectConfiguration } from 'graphql-transformer-core'; -import fs from 'fs-extra'; -import { getApiResourceDir } from './api-resource-paths'; -import { forceRefreshSchema } from './force-refresh-schema'; - -const setNotificationFlag = async (projectPath: string, flagName: string, value: boolean): Promise => { - await FeatureFlags.ensureFeatureFlag('graphqltransformer', flagName); - - const config = stateManager.getCLIJSON(projectPath, undefined, { - throwIfNotExist: false, - preserveComments: true, - }); - - if (config) { - config.features.graphqltransformer[flagName] = value; - stateManager.setCLIJSON(projectPath, config); - await FeatureFlags.reloadValues(); - } -}; - -const loadResolvers = async (apiResourceDirectory: string): Promise> => { - const resolvers = {}; - - const resolverDirectory = path.join(apiResourceDirectory, 'build', 'resolvers'); - const resolverDirExists = fs.existsSync(resolverDirectory); - if (resolverDirExists) { - const resolverFiles = await fs.readdir(resolverDirectory); - for (const resolverFile of resolverFiles) { - if (resolverFile.indexOf('.') === 0) { - // eslint-disable-next-line no-continue - continue; - } - const resolverFilePath = path.join(resolverDirectory, resolverFile); - resolvers[resolverFile] = await fs.readFile(resolverFilePath, 'utf8'); - } - } - - return resolvers; -}; - -/** - * checks if we should display auth notification - */ -export const displayAuthNotification = (directiveMap: any, fieldDirectives: Set): boolean => { - const usesTransformerV2 = FeatureFlags.getNumber('graphqltransformer.transformerVersion') === 2; - const schemaHasValues = Object.keys(directiveMap).some((typeName: string) => { - const typeObj = directiveMap[typeName]; - const modelDirective = typeObj.find((dir: DirectiveNode) => dir.name.value === 'model'); - - const subscriptionOff: boolean = (modelDirective?.arguments || []).some((arg: any) => { - if (arg.name.value === 'subscriptions') { - const subscriptionNull = arg.value.kind === 'NullValue'; - const levelFieldOffOrNull = arg.value?.fields?.some( - ({ name, value }) => name.value === 'level' && (value.value === 'off' || value.kind === 'NullValue'), - ); - - return levelFieldOffOrNull || subscriptionNull; - } - }); - - return subscriptionOff && fieldDirectives.has(typeName); - }); - - return schemaHasValues && usesTransformerV2; -}; - -/** - * checks if the schema has the auth directives - */ -export const hasFieldAuthDirectives = (doc: DocumentNode): Set => { - const haveFieldAuthDir: Set = new Set(); - - doc.definitions?.forEach((def: any) => { - const withAuth: FieldNode[] = (def.fields || []).filter((field: FieldDefinitionNode) => { - const nonNullable = field.type.kind === 'NonNullType'; - const hasAuth = field.directives?.some((dir) => dir.name.value === 'auth'); - return hasAuth && nonNullable; - }); - - if (withAuth.length > 0) { - haveFieldAuthDir.add(def.name.value); - } - }); - - return haveFieldAuthDir; -}; - -/** - * security notification - */ -export const notifyFieldAuthSecurityChange = async (context: $TSContext): Promise => { - const flagName = 'showFieldAuthNotification'; - const dontShowNotification = !FeatureFlags.getBoolean(`graphqltransformer.${flagName}`); - - if (dontShowNotification) return false; - - const projectPath = pathManager.findProjectRoot() ?? process.cwd(); - const apiResourceDir = await getApiResourceDir(); - if (!apiResourceDir) { - await setNotificationFlag(projectPath, flagName, false); - return false; - } - - const project = await readProjectConfiguration(apiResourceDir); - const directiveMap = collectDirectivesByType(project.schema); - const doc: DocumentNode = parse(project.schema); - const fieldDirectives: Set = hasFieldAuthDirectives(doc); - - let schemaModified = false; - if (displayAuthNotification(directiveMap, fieldDirectives)) { - printer.blankLine(); - const continueChange = await prompter.yesOrNo( - 'This version of Amplify CLI introduces additional security enhancements for your GraphQL API. ' + - "The changes are applied automatically with this deployment. This change won't impact your client code. Continue?", - ); - - if (!continueChange) { - await context.usageData.emitSuccess(); - exitOnNextTick(0); - } - forceRefreshSchema(); - schemaModified = true; - } - - await setNotificationFlag(projectPath, flagName, false); - return schemaModified; -}; - -/** - * checks if the schema has the V2 auth directives - */ -const hasV2AuthDirectives = (doc: DocumentNode): boolean => { - let containsAuthDir = false; - const usesTransformerV2 = FeatureFlags.getNumber('graphqltransformer.transformerVersion') === 2; - - doc.definitions?.forEach((def: any) => { - if (def.directives?.some((dir) => dir.name.value === 'auth')) { - containsAuthDir = true; - } - }); - - return containsAuthDir && usesTransformerV2; -}; - -/** - * security notification - */ -export const notifyListQuerySecurityChange = async (context: $TSContext): Promise => { - const apiResourceDir = await getApiResourceDir(); - if (!apiResourceDir) { - return false; - } - - const project = await readProjectConfiguration(apiResourceDir); - const resolvers = await loadResolvers(apiResourceDir); - - const resolversToCheck = Object.entries(resolvers) - .filter(([resolverFileName, _]) => resolverFileName.startsWith('Query.list') && resolverFileName.endsWith('.req.vtl')) - .map(([_, resolverCode]) => resolverCode); - const listQueryPattern = - /#set\( \$filterExpression = \$util\.parseJson\(\$util\.transform\.toDynamoDBFilterExpression\(\$filter\)\) \)\s*(?!\s*#if\( \$util\.isNullOrEmpty\(\$filterExpression\) \))/gm; - const resolversToSecure = resolversToCheck.filter((resolver) => listQueryPattern.test(resolver)); - if (resolversToSecure.length === 0) { - return false; - } - - const doc: DocumentNode = parse(project.schema); - - let schemaModified = false; - if (hasV2AuthDirectives(doc)) { - printer.blankLine(); - const continueChange = await prompter.yesOrNo( - 'This version of Amplify CLI introduces additional security enhancements for your GraphQL API. ' + - "The changes are applied automatically with this deployment. This change won't impact your client code. Continue?", - ); - - if (!continueChange) { - await context.usageData.emitSuccess(); - exitOnNextTick(0); - } - - forceRefreshSchema(); - schemaModified = true; - } - - return schemaModified; -}; - -/** - * Checks for security enhancements in the schema and displays a warning if they are found. - */ -export const notifySecurityEnhancement = async (context: $TSContext): Promise => { - if (FeatureFlags.getBoolean('graphqltransformer.securityEnhancementNotification')) { - const projectPath = pathManager.findProjectRoot() ?? process.cwd(); - const meta = stateManager.getMeta(); - - const apiNames = Object.entries(meta?.api || {}) - .filter(([_, apiResource]) => (apiResource as any).service === 'AppSync') - .map(([name]) => name); - - if (apiNames.length !== 1) { - await setNotificationFlag(projectPath, 'securityEnhancementNotification', false); - return; - } - - const apiName = apiNames[0]; - - const apiResourceDir = pathManager.getResourceDirectoryPath(projectPath, 'api', apiName); - - if (!fs.existsSync(apiResourceDir)) { - await setNotificationFlag(projectPath, 'securityEnhancementNotification', false); - return; - } - - const project = await readProjectConfiguration(apiResourceDir); - - const directiveMap = collectDirectivesByTypeNames(project.schema); - const notifyAuthWithKey = Object.keys(directiveMap.types).some( - (type) => directiveMap.types[type].includes('auth') && directiveMap.types[type].includes('primaryKey'), - ); - - if (meta?.auth && notifyAuthWithKey) { - printer.blankLine(); - const shouldContinue = await prompter.yesOrNo( - "This version of Amplify CLI introduces additional security enhancements for your GraphQL API. @auth authorization rules applied on primary keys and indexes are scoped down further. The changes are applied automatically with this deployment. This change won't impact your client code. Continue", - ); - - if (!shouldContinue) { - await context.usageData.emitSuccess(); - exitOnNextTick(0); - } - - forceRefreshSchema(); - - await setNotificationFlag(projectPath, 'securityEnhancementNotification', false); - } else { - await setNotificationFlag(projectPath, 'securityEnhancementNotification', false); - } - } -}; diff --git a/packages/amplify-category-api/src/force-updates/force-refresh-schema.ts b/packages/amplify-category-api/src/force-updates/force-refresh-schema.ts deleted file mode 100644 index f4a9e70969..0000000000 --- a/packages/amplify-category-api/src/force-updates/force-refresh-schema.ts +++ /dev/null @@ -1,54 +0,0 @@ -import path from 'path'; -import fs from 'fs-extra'; -import { getApiResourceDir } from './api-resource-paths'; - -/** - * Add a whitespace character to the graphql schema, forcing a rebuild of resolver/schema/cfn resources, and a push. - * This is useful if resolver implementations have changed, and the customer does not wish to update their schema, - * or amplify is updating on their behalf under the hood. - */ -export const forceRefreshSchema = (): void => { - const apiResourceDir = getApiResourceDir(); - const schemaFilePath = path.join(apiResourceDir, 'schema.graphql'); - const schemaDirectoryPath = path.join(apiResourceDir, 'schema'); - const schemaFileExists = fs.existsSync(schemaFilePath); - const schemaDirectoryExists = fs.existsSync(schemaDirectoryPath); - - if (schemaFileExists) { - fs.appendFileSync(schemaFilePath, ' '); - } else if (schemaDirectoryExists) { - modifyGraphQLSchemaDirectory(schemaDirectoryPath); - } -}; - -/** - * Given a schema path, attach whitespace to each non-hidden file recursively. - * @param schemaDirectoryPath the path to search - * @returns a false at the top level, when complete. - */ -const modifyGraphQLSchemaDirectory = (schemaDirectoryPath: string): boolean => { - const files = fs.readdirSync(schemaDirectoryPath); - - for (const fileName of files) { - const isHiddenFile = fileName.indexOf('.') === 0; - - if (isHiddenFile) { - // eslint-disable-next-line no-continue - continue; - } - - const fullPath = path.join(schemaDirectoryPath, fileName); - const stats = fs.lstatSync(fullPath); - - if (stats.isDirectory() && modifyGraphQLSchemaDirectory(fullPath)) { - return true; - } - - if (stats.isFile()) { - fs.appendFileSync(fullPath, ' '); - return true; - } - } - - return false; -}; diff --git a/packages/amplify-category-api/src/force-updates/index.ts b/packages/amplify-category-api/src/force-updates/index.ts deleted file mode 100644 index 8f7ca50f1d..0000000000 --- a/packages/amplify-category-api/src/force-updates/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { notifySecurityEnhancement, notifyFieldAuthSecurityChange, notifyListQuerySecurityChange } from './auth-notifications'; - -/** - * Extracted data force update logic from the `push` command in CLI. - * Runs through expected force updates in order. - */ -export const checkForcedUpdates = async (context: $TSContext): Promise => { - await notifySecurityEnhancement(context); - - /** - * The following two checks use similar phrasing for the customer. This isn't ideal moving forward, but - * leaving these two as-is since they were added in CLI version 7.6.19. - */ - let securityChangeNotified = false; - securityChangeNotified = await notifyFieldAuthSecurityChange(context); - - if (!securityChangeNotified) { - securityChangeNotified = await notifyListQuerySecurityChange(context); - } -}; diff --git a/packages/amplify-category-api/src/graphql-transformer/amplify-cli-feature-flag-adapter.ts b/packages/amplify-category-api/src/graphql-transformer/amplify-cli-feature-flag-adapter.ts deleted file mode 100644 index e166509709..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/amplify-cli-feature-flag-adapter.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { FeatureFlags } from '@aws-amplify/amplify-cli-core'; -import { FeatureFlagProvider } from 'graphql-transformer-core'; - -export class AmplifyCLIFeatureFlagAdapterBase implements FeatureFlagProvider { - getBoolean(featureName: string, defaultValue?: boolean): boolean { - return this.getValue(featureName, 'boolean', defaultValue); - } - - getNumber(featureName: string, defaultValue?: number): number { - return this.getValue(featureName, 'number', defaultValue); - } - - getObject(): object { - // Todo: for future extensibility - throw new Error('Not implemented'); - } - - protected getValue(featureName: string, type: 'boolean' | 'number' | 'string', defaultValue: T): T { - const keyName = `graphQLTransformer.${featureName}`; - try { - switch (type) { - case 'boolean': - return FeatureFlags.getBoolean(keyName) as T; - case 'number': - return FeatureFlags.getNumber(keyName) as T; - } - } catch (e) { - if (defaultValue) { - return defaultValue; - } - throw e; - } - } -} - -// Mapping to new type to ensure the provider interface is implemented -export class AmplifyCLIFeatureFlagAdapter extends AmplifyCLIFeatureFlagAdapterBase {} diff --git a/packages/amplify-category-api/src/graphql-transformer/api-key-helpers.ts b/packages/amplify-category-api/src/graphql-transformer/api-key-helpers.ts deleted file mode 100644 index 542980a074..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/api-key-helpers.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { $TSContext, CloudformationProviderFacade } from '@aws-amplify/amplify-cli-core'; - -export async function hasApiKey(context: $TSContext): Promise { - const apiKeyConfig = await CloudformationProviderFacade.getApiKeyConfig(context); - return !!apiKeyConfig && !!apiKeyConfig?.apiKeyExpirationDays; -} diff --git a/packages/amplify-category-api/src/graphql-transformer/api-utils.ts b/packages/amplify-category-api/src/graphql-transformer/api-utils.ts deleted file mode 100644 index a5a2a9c2a0..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/api-utils.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ensureEnvParamManager } from '@aws-amplify/amplify-environment-parameters'; -import { - $TSContext, - AmplifyCategories, - ApiCategoryFacade, - getGraphQLTransformerOpenSearchProductionDocLink, -} from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; -import { ResourceConstants } from 'graphql-transformer-common'; - -export async function searchablePushChecks(context: $TSContext, map: Record, apiName: string): Promise { - const searchableModelTypes = Object.keys(map).filter((type) => map[type].includes('searchable') && map[type].includes('model')); - if (searchableModelTypes.length) { - const apiParameterManager = (await ensureEnvParamManager()).instance.getResourceParamManager(AmplifyCategories.API, apiName); - const getInstanceType = (instanceTypeParam: string) => apiParameterManager.getParam(instanceTypeParam); - const instanceType = - getInstanceType(ResourceConstants.PARAMETERS.OpenSearchInstanceType) ?? - getInstanceType(ResourceConstants.PARAMETERS.ElasticsearchInstanceType) ?? - 't2.small.elasticsearch'; - if (instanceType === 't2.small.elasticsearch' || instanceType === 't3.small.elasticsearch') { - const version = await ApiCategoryFacade.getTransformerVersion(context); - const docLink = getGraphQLTransformerOpenSearchProductionDocLink(version); - printer.warn( - `Your instance type for OpenSearch is ${instanceType}, you may experience performance issues or data loss. Consider reconfiguring with the instructions here ${docLink}`, - ); - } - } -} diff --git a/packages/amplify-category-api/src/graphql-transformer/auth-mode-compare.ts b/packages/amplify-category-api/src/graphql-transformer/auth-mode-compare.ts deleted file mode 100644 index 5e6e517c9d..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/auth-mode-compare.ts +++ /dev/null @@ -1,42 +0,0 @@ -import _ from 'lodash'; - -export function isAuthModeUpdated(options): boolean { - const { authConfig, previousAuthConfig } = getAuthConfigForCompare(options); - return authConfig && previousAuthConfig && !_.isEqual(authConfig, previousAuthConfig); -} - -function getAuthConfigForCompare(options) { - if (!(options.authConfig && options.previousAuthConfig)) { - return {}; - } - - // Deep copy the authConfig for comparison - let authConfig = _.cloneDeep(options.authConfig); - let previousAuthConfig = _.cloneDeep(options.previousAuthConfig); - - // Remove apiKeyExpirationDate key for comparision as this may change even if there are no auth mode changes - if (authConfig) { - authConfig.defaultAuthentication = removeApiKeyExpirationDate(authConfig.defaultAuthentication); - authConfig.additionalAuthenticationProviders = authConfig.additionalAuthenticationProviders?.map((mode) => - removeApiKeyExpirationDate(mode), - ); - } - if (previousAuthConfig) { - previousAuthConfig.defaultAuthentication = removeApiKeyExpirationDate(previousAuthConfig.defaultAuthentication); - previousAuthConfig.additionalAuthenticationProviders = previousAuthConfig.additionalAuthenticationProviders?.map((mode) => - removeApiKeyExpirationDate(mode), - ); - } - - return { - authConfig, - previousAuthConfig, - }; -} - -function removeApiKeyExpirationDate(mode) { - if (mode?.apiKeyConfig) { - delete mode.apiKeyConfig.apiKeyExpirationDate; - } - return mode; -} diff --git a/packages/amplify-category-api/src/graphql-transformer/cdk-compat/amplify-api-resource-stack-types.ts b/packages/amplify-category-api/src/graphql-transformer/cdk-compat/amplify-api-resource-stack-types.ts deleted file mode 100644 index d96c32bfb0..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/cdk-compat/amplify-api-resource-stack-types.ts +++ /dev/null @@ -1,91 +0,0 @@ -// Amplify generated Types for API - override.ts - -import { CfnApiKey, CfnDataSource, CfnFunctionConfiguration, CfnGraphQLApi, CfnGraphQLSchema, CfnResolver } from 'aws-cdk-lib/aws-appsync'; -import { CfnTable } from 'aws-cdk-lib/aws-dynamodb'; -import { CfnPolicy, CfnRole } from 'aws-cdk-lib/aws-iam'; -import { CfnDomain } from 'aws-cdk-lib/aws-elasticsearch'; -import { CfnFunction, CfnEventSourceMapping } from 'aws-cdk-lib/aws-lambda'; -import { CfnStack } from 'aws-cdk-lib'; - -// Base template -// Customer can use these params to mutate the Cloudformation for the resource - -export interface AmplifyApiGraphQlResourceStackTemplate { - // directives stack - api?: Partial; - models?: Partial>; - http?: Partial; - opensearch?: Partial; - function?: Partial; - predictions?: Partial; -} - -export type AppsyncApiStack = { - rootstack: CfnStack; - GraphQLAPI: CfnGraphQLApi; - GraphQLAPIDefaultApiKey?: CfnApiKey; - GraphQLAPITransformerSchema?: CfnGraphQLSchema; - GraphQLAPINONEDS?: CfnDataSource; - AmplifyDataStore?: CfnTable; - AmplifyDataStoreIAMRole?: CfnRole; - DynamoDBAccess?: CfnPolicy; -}; - -export type ModelDirectiveStack = AppsyncStackCommon & DDBModelDirectiveStack; - -export type AppsyncStackCommon = { - resolvers?: Record; - appsyncFunctions?: Record; -}; - -export type DDBModelDirectiveStack = { - modelStack?: CfnStack; - modelDDBTable?: CfnTable; - modelIamRole?: CfnRole; - modelIamRoleDefaultPolicy?: CfnPolicy; - dynamoDBAccess?: CfnPolicy; - modelDatasource?: CfnDataSource; - invokeLambdaFunction?: CfnPolicy; -}; - -export interface HttpsDirectiveStack { - httpsDataSource?: Record; - httpDataSourceServiceRole?: Record; - httpDataSourceServiceRoleDefaultPolicy?: Record; -} - -export interface OpenSearchDirectiveStack { - OpenSearchDataSource?: CfnDataSource; - OpenSearchAccessIAMRole?: CfnRole; - OpenSearchAccessIAMRoleDefaultPolicy?: CfnPolicy; - OpenSearchDomain?: CfnDomain; - OpenSearchStreamingLambdaIAMRole?: CfnRole; - OpenSearchStreamingLambdaIAMRoleDefaultPolicy?: CfnPolicy; - CloudwatchLogsAccess?: CfnPolicy; - OpenSearchStreamingLambdaFunction?: CfnFunction; - OpenSearchModelLambdaMapping?: Record; -} - -export interface FunctionDirectiveStack { - lambdaDataSource: Record; - lambdaDataSourceRole: Record; - lambdaDataSourceServiceRoleDefaultPolicy: Record; -} - -export interface PredictionsDirectiveStack { - RekognitionDataSource: CfnDataSource; - RekognitionDataSourceServiceRole: CfnRole; - TranslateDataSource: CfnDataSource; - translateTextAccess: CfnPolicy; - LambdaDataSource: CfnDataSource; - LambdaDataSourceServiceRole: CfnRole; - LambdaDataSourceServiceRoleDefaultPolicy: CfnPolicy; - TranslateDataSourceServiceRole: CfnRole; - predictionsLambdaIAMRole: CfnRole; - predictionsLambdaFunction: CfnFunction; - PredictionsLambdaAccess: CfnPolicy; - predictionsIAMRole: CfnRole; - PredictionsStorageAccess: CfnPolicy; - identifyTextAccess: CfnPolicy; - identifyLabelsAccess: CfnPolicy; -} diff --git a/packages/amplify-category-api/src/graphql-transformer/cdk-compat/amplify-s3-asset.ts b/packages/amplify-category-api/src/graphql-transformer/cdk-compat/amplify-s3-asset.ts deleted file mode 100644 index d45513f69e..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/cdk-compat/amplify-s3-asset.ts +++ /dev/null @@ -1,62 +0,0 @@ -import * as crypto from 'crypto'; -import * as cdk from 'aws-cdk-lib'; -import { FileAssetPackaging, Stack } from 'aws-cdk-lib'; -import { Construct } from 'constructs'; -import { TransformerStackSythesizer } from './stack-synthesizer'; - -export interface TemplateProps { - readonly fileContent: string; - readonly fileName: string; -} - -export class AmplifyS3Asset extends Construct implements cdk.IAsset { - public readonly assetHash: string; - - public readonly httpUrl: string; - - public readonly s3BucketName: string; - - public readonly s3ObjectKey: string; - - public readonly s3ObjectUrl: string; - - constructor(scope: Construct, id: string, props: TemplateProps) { - super(scope, id); - - const rootStack = findRootStack(scope); - const sythesizer = rootStack.synthesizer; - - // Check the constructor name instead of using 'instanceof' because the latter does not work - // with copies of the class, which happens with custom transformers. - // See: https://github.com/aws-amplify/amplify-cli/issues/9362 - if (sythesizer.constructor.name === TransformerStackSythesizer.name) { - (sythesizer as TransformerStackSythesizer).setMappingTemplates(props.fileName, props.fileContent); - this.assetHash = crypto.createHash('sha256').update(props.fileContent).digest('hex'); - const asset = sythesizer.addFileAsset({ - fileName: props.fileName, - packaging: FileAssetPackaging.FILE, - sourceHash: this.assetHash, - }); - this.httpUrl = asset.httpUrl; - this.s3BucketName = asset.bucketName; - this.s3ObjectKey = asset.objectKey; - this.s3ObjectUrl = asset.s3ObjectUrl; - } else { - // TODO: handle a generic synthesizer by creating a asset in output path - throw new Error('Template asset can be used only with TransformerStackSynthesizer'); - } - } -} - -function findRootStack(scope: Construct): Stack { - if (!scope) { - throw new Error('Nested stacks cannot be defined as a root construct'); - } - - const rootStack = scope.node.scopes.find((p) => Stack.isStack(p)); - if (!rootStack) { - throw new Error('Nested stacks must be defined within scope of another non-nested stack'); - } - - return rootStack as Stack; -} diff --git a/packages/amplify-category-api/src/graphql-transformer/cdk-compat/deployment-resources.ts b/packages/amplify-category-api/src/graphql-transformer/cdk-compat/deployment-resources.ts deleted file mode 100644 index 54e00f9e4f..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/cdk-compat/deployment-resources.ts +++ /dev/null @@ -1,46 +0,0 @@ -export interface Template { - AWSTemplateFormatVersion?: string; - Description?: string; - Metadata?: Record; - Parameters?: Record; - Mappings?: { - [key: string]: { - [key: string]: Record; - }; - }; - Conditions?: Record; - Transform?: any; - Resources?: Record; - Outputs?: Record; -} - -export interface StackMapping { - [resourceId: string]: string; -} - -export interface ResolversFunctionsAndSchema { - // Resolver templates keyed by their filename. - resolvers: Record; - // Contains mapping templates for pipeline functions. - pipelineFunctions: Record; - // Code for any functions that need to be deployed. - functions: Record; - // The full GraphQL schema. - schema: string; - // List of the user overridden slots - userOverriddenSlots: string[]; -} - -export interface NestedStacks { - // The root stack template. - rootStack: Template; - // All the nested stack templates. - stacks: Record; - // The full stack mapping for the deployment. - stackMapping: StackMapping; -} - -/** - * The full set of resources needed for the deployment. - */ -export interface DeploymentResources extends ResolversFunctionsAndSchema, NestedStacks {} diff --git a/packages/amplify-category-api/src/graphql-transformer/cdk-compat/nested-stack.ts b/packages/amplify-category-api/src/graphql-transformer/cdk-compat/nested-stack.ts deleted file mode 100644 index 27d2ef9627..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/cdk-compat/nested-stack.ts +++ /dev/null @@ -1,172 +0,0 @@ -import * as crypto from 'crypto'; -import { - Aws, - CfnResource, - CfnStack, - FileAssetPackaging, - Fn, - IResolveContext, - IStackSynthesizer, - Lazy, - NestedStackProps, - Stack, - Token, -} from 'aws-cdk-lib'; -import { Construct } from 'constructs'; -import { TransformerRootStack } from './root-stack'; -import { TransformerStackSythesizer } from './stack-synthesizer'; - -export type TransformerNestedStackProps = NestedStackProps & { - synthesizer?: IStackSynthesizer; -}; -export class TransformerNestedStack extends TransformerRootStack { - public readonly templateFile: string; - - public readonly nestedStackResource?: CfnResource; - - private readonly parameters: { [name: string]: string }; - - private readonly resource: CfnStack; - - private readonly _contextualStackId: string; - - private readonly _contextualStackName: string; - - private _templateUrl?: string; - - private _rootStack: Stack; - - constructor(scope: Construct, id: string, props: TransformerNestedStackProps = {}) { - const rootStack = findRootStack(scope); - const synthesizer = props.synthesizer || new TransformerStackSythesizer(); - super(scope, id, { - env: { account: rootStack.account, region: rootStack.region }, - ...props, - synthesizer, - }); - - this._rootStack = rootStack; - - const parentScope = new Construct(scope, `${id}.NestedStack`); - // Transformer synthesizes the stack in memory and stack names are going to be unique - this.templateFile = `stacks/${id}.json`; - - this.parameters = props.parameters || {}; - - this.resource = new CfnStack(parentScope, `${id}.NestedStackResource`, { - templateUrl: Lazy.uncachedString({ - produce: () => { - return this._templateUrl || ''; - }, - }), - parameters: Lazy.any({ - produce: () => (Object.keys(this.parameters).length > 0 ? this.parameters : undefined), - }), - notificationArns: props.notificationArns, - timeoutInMinutes: props.timeout ? props.timeout.toMinutes() : undefined, - }); - - this.nestedStackResource = this.resource; - - // context-aware stack name: if resolved from within this stack, return AWS::StackName - // if resolved from the outer stack, use the { Ref } of the AWS::CloudFormation::Stack resource - // which resolves the ARN of the stack. We need to extract the stack name, which is the second - // component after splitting by "/" - this._contextualStackName = this.contextualAttribute(Aws.STACK_NAME, Fn.select(1, Fn.split('/', this.resource.ref))); - this._contextualStackId = this.contextualAttribute(Aws.STACK_ID, this.resource.ref); - } - - /** - * An attribute that represents the name of the nested stack. - * - * This is a context aware attribute: - * - If this is referenced from the parent stack, it will return a token that parses the name from the stack ID. - * - If this is referenced from the context of the nested stack, it will return `{ "Ref": "AWS::StackName" }` - * - * @attribute - * @example mystack-mynestedstack-sggfrhxhum7w - */ - public get stackName() { - return this._contextualStackName; - } - - /** - * An attribute that represents the ID of the stack. - * - * This is a context aware attribute: - * - If this is referenced from the parent stack, it will return `{ "Ref": "LogicalIdOfNestedStackResource" }`. - * - If this is referenced from the context of the nested stack, it will return `{ "Ref": "AWS::StackId" }` - * - * @attribute - * @example "arn:aws:cloudformation:us-east-2:123456789012:stack/mystack-mynestedstack-sggfrhxhum7w/f449b250-b969-11e0-a185-5081d0136786" - */ - public get stackId() { - return this._contextualStackId; - } - - /** - * Assign a value to one of the nested stack parameters. - * @param name The parameter name (ID) - * @param value The value to assign - */ - public setParameter(name: string, value: string) { - this.parameters[name] = value; - } - - /** - * Defines an asset at the parent stack which represents the template of this - * nested stack. - * - * This private API is used by `App.prepare()` within a loop that rectifies - * references every time an asset is added. This is because (at the moment) - * assets are addressed using CloudFormation parameters. - * - * @returns `true` if a new asset was added or `false` if an asset was - * previously added. When this returns `true`, App will do another reference - * rectification cycle. - * - * @internal - */ - public _prepareTemplateAsset() { - if (this._templateUrl) { - return false; - } - - const cfn = JSON.stringify((this as any)._toCloudFormation()); - const templateHash = crypto.createHash('sha256').update(cfn).digest('hex'); - - const templateLocation = this._rootStack.synthesizer.addFileAsset({ - packaging: FileAssetPackaging.FILE, - sourceHash: templateHash, - fileName: this.templateFile, - }); - - this._templateUrl = templateLocation.httpUrl; - - return true; - } - - private contextualAttribute(innerValue: string, outerValue: string) { - return Token.asString({ - resolve: (context: IResolveContext) => { - if (Stack.of(context.scope) === this) { - return innerValue; - } else { - return outerValue; - } - }, - }); - } -} -function findRootStack(scope: Construct): Stack { - if (!scope) { - throw new Error('Nested stacks cannot be defined as a root construct'); - } - - const rootStack = scope.node.scopes.find((p) => Stack.isStack(p)); - if (!rootStack) { - throw new Error('Nested stacks must be defined within scope of another non-nested stack'); - } - - return rootStack as Stack; -} diff --git a/packages/amplify-category-api/src/graphql-transformer/cdk-compat/project-config.ts b/packages/amplify-category-api/src/graphql-transformer/cdk-compat/project-config.ts deleted file mode 100644 index d193eaf6c1..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/cdk-compat/project-config.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { DataSourceStrategiesProvider } from '@aws-amplify/graphql-transformer-interfaces'; -import { TransformConfig } from 'graphql-transformer-core'; - -export type Template = { - Parameters: Record; - Resources: Record; - Outputs: Record; - Conditions: Record; -}; - -export interface TransformerProjectConfig extends DataSourceStrategiesProvider { - schema: string; - functions: Record; - pipelineFunctions: Record; - resolvers: Record; - stacks: Record; - config: TransformConfig; -} diff --git a/packages/amplify-category-api/src/graphql-transformer/cdk-compat/root-stack.ts b/packages/amplify-category-api/src/graphql-transformer/cdk-compat/root-stack.ts deleted file mode 100644 index 97fe11681b..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/cdk-compat/root-stack.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { CfnElement, Stack, CfnResource, ISynthesisSession } from 'aws-cdk-lib'; - -export class TransformerRootStack extends Stack { - private readonly resourceTypeToPreserveLogicalName: string[] = [ - 'AWS::DynamoDB::Table', - 'AWS::Elasticsearch::Domain', - 'AWS::RDS::DBCluster', - 'AWS::CloudFormation::Stack', - 'AWS::AppSync::GraphQLApi', - ]; - - /** - * Allocate a logical id based on the resource presense in the stack mapping. If an resource is already - * created using older version of the transformer, then keep the name the same. Otherwiser use the CDK - * stack naming convention to avoid logical name collision - * @param cfnElement - */ - - protected allocateLogicalId = (cfnElement: CfnElement): string => { - const regExPattern = /[^A-Za-z0-9]/g; - if (cfnElement instanceof CfnResource && this.resourceTypeToPreserveLogicalName.includes(cfnElement.cfnResourceType)) { - // Each L2 Construct creates a lower level CFN socpe with name Resource. We want to get the id of the parent scope - const scope = cfnElement.node.scopes.reverse().find((scope) => scope.node.id !== 'Resource'); - if (scope) { - const logicalId = scope.node.id.replace('.NestedStackResource', ''); - // if the id contains non alphanumeric char, fallback to CDK resource naming - if (!regExPattern.test(logicalId)) return logicalId; - } - } - - return super.allocateLogicalId(cfnElement); - }; - - /** - * GraphQL transformer keeps the generated resources in memory and passes it to Amplify CLI. Updating the logic - * of stack sythesize to support that. - * @param session - */ - // eslint-disable-next-line @typescript-eslint/no-unused-vars - public renderCloudFormationTemplate = (_: ISynthesisSession): string => { - return JSON.stringify((this as any)._toCloudFormation(), undefined, 2); - }; -} diff --git a/packages/amplify-category-api/src/graphql-transformer/cdk-compat/stack-synthesizer.ts b/packages/amplify-category-api/src/graphql-transformer/cdk-compat/stack-synthesizer.ts deleted file mode 100644 index c4a41f693b..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/cdk-compat/stack-synthesizer.ts +++ /dev/null @@ -1,143 +0,0 @@ -import * as crypto from 'crypto'; -import { ISynthesisSession, Stack, LegacyStackSynthesizer, FileAssetSource, FileAssetLocation, CfnParameter } from 'aws-cdk-lib'; -import { Template } from './deployment-resources'; -import { TransformerRootStack } from './root-stack'; - -/** - * TransformerStackSythesizer - */ -export class TransformerStackSythesizer extends LegacyStackSynthesizer { - private readonly stackAssets: Map = new Map(); - - private readonly mapingTemplateAssets: Map = new Map(); - - private _deploymentBucket?: CfnParameter; - - private _deploymentRootKey?: CfnParameter; - - /** - * synthesizeStackTemplate - * - * This method has been deprecated by cdk and is not used in runtime. - * @deprecated Replaced by synthesizeTemplate. - */ - protected synthesizeStackTemplate(stack: Stack, session: ISynthesisSession): void { - if (stack instanceof TransformerRootStack) { - const template = stack.renderCloudFormationTemplate(session) as string; - const templateName = stack.node.id; - this.setStackAsset(templateName, template); - return; - } - throw new Error( - 'Error synthesizing the template. Expected Stack to be either instance of TransformerRootStack or TransformerNestedStack', - ); - } - - protected synthesizeTemplate(session: ISynthesisSession, _?: string): FileAssetSource { - const stack = this.boundStack; - if (stack instanceof TransformerRootStack) { - const template = stack.renderCloudFormationTemplate(session) as string; - const templateName = stack.node.id; - this.setStackAsset(templateName, template); - const contentHash = crypto.createHash('sha256').update(template).digest('hex'); - return { - sourceHash: contentHash, - }; - } - throw new Error( - 'Error synthesizing the template. Expected Stack to be either instance of TransformerRootStack or TransformerNestedStack', - ); - } - - /** - * setStackAsset - */ - setStackAsset(templateName: string, template: string): void { - this.stackAssets.set(templateName, JSON.parse(template)); - } - - /** - * collectStacks - */ - collectStacks(): Map { - return new Map(this.stackAssets.entries()); - } - - /** - * setMappingTemplates - */ - setMappingTemplates(templateName: string, template: string): void { - this.mapingTemplateAssets.set(templateName, template); - } - - /** - * collectMappingTemplates - */ - collectMappingTemplates(): Map { - return new Map(this.mapingTemplateAssets.entries()); - } - - /** - * addFileAsset - */ - public addFileAsset(asset: FileAssetSource): FileAssetLocation { - const bucketName = this.deploymentBucket.valueAsString; - const rootKey = this.deploymentRootKey.valueAsString; - - const objectKey = `${rootKey}/${asset.fileName}`; - const httpUrl = `https://s3.${this.boundStack.region}.${this.boundStack.urlSuffix}/${bucketName}/${rootKey}/${asset.fileName}`; - const s3ObjectUrl = `s3://${bucketName}/${rootKey}/${asset.fileName}`; - - return { - bucketName, - objectKey, - httpUrl, - s3ObjectUrl, - }; - } - - /** - * ensureDeployementParameters - */ - private ensureDeployementParameters() { - if (!this._deploymentBucket) { - this._deploymentBucket = new CfnParameter(this.boundStack, 'S3DeploymentBucket', { - type: 'String', - description: 'An S3 Bucket name where assets are deployed', - }); - } - if (!this._deploymentRootKey) { - this._deploymentRootKey = new CfnParameter(this.boundStack, 'S3DeploymentRootKey', { - type: 'String', - description: 'An S3 key relative to the S3DeploymentBucket that points to the root of the deployment directory.', - }); - } - } - - /** - * deploymentBucket - */ - private get deploymentBucket(): CfnParameter { - this.ensureDeployementParameters(); - assertNotNull(this._deploymentBucket); - return this._deploymentBucket; - } - - /** - * deploymentRootKey - */ - private get deploymentRootKey(): CfnParameter { - this.ensureDeployementParameters(); - assertNotNull(this._deploymentRootKey); - return this._deploymentRootKey; - } -} - -/** - * assertNotNull - */ -export function assertNotNull(x: A | undefined): asserts x is NonNullable { - if (x === null && x === undefined) { - throw new Error('You must call bindStack() first'); - } -} diff --git a/packages/amplify-category-api/src/graphql-transformer/cdk-compat/transform-manager.ts b/packages/amplify-category-api/src/graphql-transformer/cdk-compat/transform-manager.ts deleted file mode 100644 index 273ee15db1..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/cdk-compat/transform-manager.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { App, CfnParameter, Stack } from 'aws-cdk-lib'; -import { Construct } from 'constructs'; -import type { - AssetProvider, - NestedStackProvider, - S3Asset, - AssetProps, - SynthParameters, - TransformParameterProvider, -} from '@aws-amplify/graphql-transformer-interfaces'; -import { DeploymentResources, Template } from './deployment-resources'; -import { TransformerStackSythesizer } from './stack-synthesizer'; -import { TransformerNestedStack } from './nested-stack'; -import { TransformerRootStack } from './root-stack'; -import { AmplifyApiGraphQlResourceStackTemplate } from './amplify-api-resource-stack-types'; -import { AmplifyS3Asset } from './amplify-s3-asset'; - -export type OverrideConfig = { - overrideFlag: boolean; - applyOverride: (scope: Construct) => AmplifyApiGraphQlResourceStackTemplate; -}; - -/** - * Stack Manager plugin which supports the Amplify CLI transformer behavior today. Manages Transformer stacks, nested stacks, - * and synthesizers, then provides mechanisms for synthesis. - */ -export class TransformManager { - private readonly app: App = new App(); - public readonly rootStack: TransformerRootStack; - private readonly stackSynthesizer = new TransformerStackSythesizer(); - private readonly childStackSynthesizers: Map = new Map(); - private synthParameters: SynthParameters; - private paramMap: Map; - - constructor( - private readonly overrideConfig: OverrideConfig | undefined, - hasIamAuth: boolean, - hasUserPoolAuth: boolean, - adminRoles: string[], - identityPoolId: string, - ) { - this.rootStack = new TransformerRootStack(this.app, 'transformer-root-stack', { - synthesizer: this.stackSynthesizer, - }); - - this.generateParameters(hasIamAuth, hasUserPoolAuth, adminRoles, identityPoolId); - } - - getTransformScope(): Construct { - return this.rootStack; - } - - /** - * Retrieve the nestedStackProvider for a Transformer Managed Stack - */ - getNestedStackProvider(): NestedStackProvider { - return { - provide: (scope: Construct, name: string): Stack => { - const synthesizer = new TransformerStackSythesizer(); - const newStack = new TransformerNestedStack(scope, name, { - synthesizer, - }); - this.childStackSynthesizers.set(name, synthesizer); - return newStack; - }, - }; - } - - getAssetProvider(): AssetProvider { - return { - provide: (scope: Construct, id: string, props: AssetProps): S3Asset => new AmplifyS3Asset(scope, id, props), - }; - } - - private generateParameters(hasIamAuth: boolean, hasUserPoolAuth: boolean, adminRoles: string[], identityPoolId: string): void { - this.paramMap = new Map(); - const envParameter = new CfnParameter(this.rootStack, 'env', { - default: 'NONE', - type: 'String', - }); - this.paramMap.set('env', envParameter); - const apiNameParameter = new CfnParameter(this.rootStack, 'AppSyncApiName', { - default: 'AppSyncSimpleTransform', - type: 'String', - }); - this.paramMap.set('AppSyncApiName', apiNameParameter); - this.synthParameters = { - amplifyEnvironmentName: envParameter.valueAsString, - apiName: apiNameParameter.valueAsString, - adminRoles, - identityPoolId, - }; - if (hasIamAuth) { - const authenticatedUserRoleNameParameter = new CfnParameter(this.rootStack, 'authRoleName', { type: 'String' }); - this.synthParameters.authenticatedUserRoleName = authenticatedUserRoleNameParameter.valueAsString; - this.paramMap.set('authRoleName', authenticatedUserRoleNameParameter); - const unauthenticatedUserRoleNameParameter = new CfnParameter(this.rootStack, 'unauthRoleName', { type: 'String' }); - this.synthParameters.unauthenticatedUserRoleName = unauthenticatedUserRoleNameParameter.valueAsString; - this.paramMap.set('unauthRoleName', unauthenticatedUserRoleNameParameter); - } - if (hasUserPoolAuth) { - const userPoolIdParameter = new CfnParameter(this.rootStack, 'AuthCognitoUserPoolId', { type: 'String' }); - this.synthParameters.userPoolId = userPoolIdParameter.valueAsString; - this.paramMap.set('AuthCognitoUserPoolId', userPoolIdParameter); - } - } - - getParameterProvider(): TransformParameterProvider { - return { - provide: (name: string): CfnParameter | void => this.paramMap.get(name), - }; - } - - getSynthParameters(): SynthParameters { - return this.synthParameters; - } - - generateDeploymentResources(): Omit { - if (this.overrideConfig?.overrideFlag) { - this.overrideConfig.applyOverride(this.rootStack); - } - - this.app.synth({ force: true, skipValidation: true }); - - const templates = this.getCloudFormationTemplates(); - const rootStackTemplate = templates.get('transformer-root-stack'); - const childStacks: Record = {}; - for (const [templateName, template] of templates.entries()) { - if (templateName !== 'transformer-root-stack') { - childStacks[templateName] = template; - } - } - - const fileAssets = this.getMappingTemplates(); - const pipelineFunctions: Record = {}; - const resolvers: Record = {}; - const functions: Record = {}; - for (const [templateName, template] of fileAssets) { - if (templateName.startsWith('pipelineFunctions/')) { - pipelineFunctions[templateName.replace('pipelineFunctions/', '')] = template; - } else if (templateName.startsWith('resolvers/')) { - resolvers[templateName.replace('resolvers/', '')] = template; - } else if (templateName.startsWith('functions/')) { - functions[templateName.replace('functions/', '')] = template; - } - } - const schema = fileAssets.get('schema.graphql') || ''; - - return { - functions, - pipelineFunctions, - resolvers, - schema, - stacks: childStacks, - rootStack: rootStackTemplate!, - stackMapping: {}, - }; - } - - private getCloudFormationTemplates = (): Map => { - let stacks = this.stackSynthesizer.collectStacks(); - this.childStackSynthesizers.forEach((synthesizer) => { - stacks = new Map([...stacks.entries(), ...synthesizer.collectStacks()]); - }); - return stacks; - }; - - private getMappingTemplates = (): Map => this.stackSynthesizer.collectMappingTemplates(); -} diff --git a/packages/amplify-category-api/src/graphql-transformer/constants.ts b/packages/amplify-category-api/src/graphql-transformer/constants.ts deleted file mode 100644 index 00e0894b57..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/constants.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const DESTRUCTIVE_UPDATES_FLAG = 'allow-destructive-graphql-schema-updates'; -export const PROVIDER_NAME = 'awscloudformation'; -export const PARAMETERS_FILENAME = 'parameters.json'; -export const ROOT_APPSYNC_S3_KEY = 'amplify-appsync-files'; -export const SCHEMA_FILENAME = 'schema.graphql'; -export const SCHEMA_DIR_NAME = 'schema'; diff --git a/packages/amplify-category-api/src/graphql-transformer/directive-definitions.ts b/packages/amplify-category-api/src/graphql-transformer/directive-definitions.ts deleted file mode 100644 index 38e9246d0b..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/directive-definitions.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { getAppSyncServiceExtraDirectives } from '@aws-amplify/graphql-transformer-core'; -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { print } from 'graphql'; -import { TransformerPluginProvider } from '@aws-amplify/graphql-transformer-interfaces'; -import { constructTransformerChain } from '@aws-amplify/graphql-transformer'; -import { getTransformerFactoryV1 } from './transformer-factory'; -import { getTransformerVersion } from './transformer-version'; -import { loadCustomTransformersV2 } from './transformer-options-v2'; - -/** - * Return the set of directive definitions for the project, includes both appsync and amplify supported directives. - * This will return the relevant set determined by whether or not the customer is using GQL transformer v1 or 2 in their project. - */ -export const getDirectiveDefinitions = async (context: $TSContext, resourceDir: string): Promise => { - const transformerVersion = await getTransformerVersion(context); - const transformList = - transformerVersion === 2 ? await getTransformListV2(resourceDir) : await getTransformerFactoryV1(context, resourceDir)(true); - - const transformDirectives = transformList - .map((transform) => [transform.directive, ...transform.typeDefinitions].map((node) => print(node)).join('\n')) - .join('\n'); - - return [getAppSyncServiceExtraDirectives(), transformDirectives].join('\n'); -}; - -/** - * Get the list of v2 transformers, including custom transformers. - * @param resourceDir directory to search for custom transformer config in. - * @returns the list of transformers, including any defined custom transformers. - */ -const getTransformListV2 = async (resourceDir: string): Promise => - constructTransformerChain({ - customTransformers: await loadCustomTransformersV2(resourceDir), - }); diff --git a/packages/amplify-category-api/src/graphql-transformer/index.ts b/packages/amplify-category-api/src/graphql-transformer/index.ts deleted file mode 100644 index f5f9376517..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { getDirectiveDefinitions } from './directive-definitions'; -export { getTransformerVersion } from './transformer-version'; -export { transformGraphQLSchema } from './transform-graphql-schema'; diff --git a/packages/amplify-category-api/src/graphql-transformer/override.ts b/packages/amplify-category-api/src/graphql-transformer/override.ts deleted file mode 100644 index 5c94b93566..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/override.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { CfnResource } from 'aws-cdk-lib'; -import * as fs from 'fs-extra'; -import * as path from 'path'; -import _ from 'lodash'; -import { pathManager, stateManager } from '@aws-amplify/amplify-cli-core'; -import { Construct } from 'constructs'; -import { getAppSyncAPIName } from '../provider-utils/awscloudformation/utils/amplify-meta-utils'; -import { ConstructResourceMeta } from './types/types'; -import { convertToAppsyncResourceObj, getStackMeta } from './types/utils'; -import { AmplifyApiGraphQlResourceStackTemplate } from './cdk-compat/amplify-api-resource-stack-types'; - -/** - * - * @param scope - * @param overrideDir - */ -export function applyFileBasedOverride(scope: Construct, overrideDirPath?: string): AmplifyApiGraphQlResourceStackTemplate { - const overrideDir = overrideDirPath ?? path.join(pathManager.getBackendDirPath(), 'api', getAppSyncAPIName()); - const overrideFilePath = path.join(overrideDir, 'build', 'override.js'); - if (!fs.existsSync(overrideFilePath)) { - return {}; - } - - const stacks: string[] = []; - const amplifyApiObj: any = {}; - scope.node.findAll().forEach((node) => { - const resource = node as CfnResource; - if (resource.cfnResourceType === 'AWS::CloudFormation::Stack') { - stacks.push(node.node.id.split('.')[0]); - } - }); - - scope.node.findAll().forEach((node) => { - const resource = node as CfnResource; - let pathArr; - if (node.node.id === 'Resource') { - pathArr = node.node.path.split('/').filter((key) => key !== node.node.id); - } else { - pathArr = node.node.path.split('/'); - } - let constructPathObj: ConstructResourceMeta; - if (resource.cfnResourceType) { - constructPathObj = getStackMeta(pathArr, node.node.id, stacks, resource); - if (!_.isEmpty(constructPathObj.rootStack)) { - // api scope - const field = constructPathObj.rootStack!.stackType; - const { resourceName } = constructPathObj; - _.set(amplifyApiObj, [field, resourceName], resource); - } else if (!_.isEmpty(constructPathObj.nestedStack)) { - const fieldType = constructPathObj.nestedStack!.stackType; - const fieldName = constructPathObj.nestedStack!.stackName; - const { resourceName } = constructPathObj; - if (constructPathObj.resourceType.includes('Resolver')) { - _.set(amplifyApiObj, [fieldType, fieldName, 'resolvers', resourceName], resource); - } else if (constructPathObj.resourceType.includes('FunctionConfiguration')) { - _.set(amplifyApiObj, [fieldType, fieldName, 'appsyncFunctions', resourceName], resource); - } else { - _.set(amplifyApiObj, [fieldType, fieldName, resourceName], resource); - } - } - } - }); - - const appsyncResourceObj = convertToAppsyncResourceObj(amplifyApiObj); - const { envName } = stateManager.getLocalEnvInfo(); - const { projectName } = stateManager.getProjectConfig(); - const projectInfo = { - envName, - projectName, - }; - try { - // TODO: Invoke `runOverride` from CLI core once core refactor is done, and - // this function can become async https://github.com/aws-amplify/amplify-cli/blob/7bc0b5654a585104a537c1a3f9615bd672435b58/packages/amplify-cli-core/src/overrides-manager/override-runner.ts#L4 - // before importing the override file, we should clear the require cache to avoid - // importing an outdated version of the override file - // see: https://github.com/nodejs/modules/issues/307 - // and https://stackoverflow.com/questions/9210542/node-js-require-cache-possible-to-invalidate - delete require.cache[require.resolve(overrideFilePath)]; - const overrideImport = require(overrideFilePath); - if (overrideImport && overrideImport?.override && typeof overrideImport?.override === 'function') { - overrideImport.override(appsyncResourceObj, projectInfo); - } - } catch (err) { - throw new InvalidOverrideError(err); - } - return appsyncResourceObj; -} - -/** - * - */ -export class InvalidOverrideError extends Error { - details: string; - - resolution: string; - - constructor(error: Error) { - super('Executing overrides failed.'); - this.name = 'InvalidOverrideError'; - this.details = error.message; - this.resolution = 'There may be runtime errors in your overrides file. If so, fix the errors and try again.'; - if ((Error as any).captureStackTrace) { - (Error as any).captureStackTrace(this, InvalidOverrideError); - } - } -} diff --git a/packages/amplify-category-api/src/graphql-transformer/sandbox-mode-helpers.ts b/packages/amplify-category-api/src/graphql-transformer/sandbox-mode-helpers.ts deleted file mode 100644 index 818663b918..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/sandbox-mode-helpers.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* eslint-disable prefer-arrow/prefer-arrow-functions */ -/* eslint-disable func-style */ -import chalk from 'chalk'; -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; -import { parse } from 'graphql'; -import { hasApiKey } from './api-key-helpers'; - -const AMPLIFY = 'AMPLIFY'; -const AUTHORIZATION_RULE = 'AuthRule'; -const ALLOW = 'allow'; -const PUBLIC = 'public'; - -// eslint-disable-next-line consistent-return -export async function showSandboxModePrompts(context: $TSContext): Promise { - if (!(await hasApiKey(context))) { - printer.info( - ` -⚠️ WARNING: Global Sandbox Mode has been enabled, which requires a valid API key. If -you'd like to disable, remove ${chalk.green('"input AMPLIFY { globalAuthRule: AuthRule = { allow: public } }"')} -from your GraphQL schema and run 'amplify push' again. If you'd like to proceed with -sandbox mode disabled, do not create an API Key. -`, - 'yellow', - ); - // eslint-disable-next-line no-return-await - return await context.amplify.invokePluginMethod(context, 'api', undefined, 'promptToAddApiKey', [context]); - } -} - -export function showGlobalSandboxModeWarning(doclink: string): void { - printer.info( - ` -⚠️ WARNING: your GraphQL API currently allows public create, read, update, and delete access to all models via an API Key. To configure PRODUCTION-READY authorization rules, review: ${doclink} -`, - 'yellow', - ); -} - -function matchesGlobalAuth(field: any): boolean { - return ['global_auth_rule', 'globalAuthRule'].includes(field.name.value); -} - -export function schemaHasSandboxModeEnabled(schema: string, docLink: string): boolean { - const { definitions } = parse(schema); - const amplifyInputType: any = definitions.find((d: any) => d.kind === 'InputObjectTypeDefinition' && d.name.value === AMPLIFY); - if (!amplifyInputType) { - return false; - } - - const authRuleField = amplifyInputType.fields.find(matchesGlobalAuth); - - if (!authRuleField) { - return false; - } - - const typeName = authRuleField.type.name.value; - const defaultValueField = authRuleField.defaultValue.fields[0]; - const defaultValueName = defaultValueField.name.value; - const defaultValueValue = defaultValueField.value.value; - const authScalarMatch = typeName === AUTHORIZATION_RULE; - const defaultValueNameMatch = defaultValueName === ALLOW; - const defaultValueValueMatch = defaultValueValue === PUBLIC; - - if (authScalarMatch && defaultValueNameMatch && defaultValueValueMatch) { - return true; - } - throw Error(`There was a problem with your auth configuration. Learn more about auth here: ${docLink}`); -} diff --git a/packages/amplify-category-api/src/graphql-transformer/transform-config.ts b/packages/amplify-category-api/src/graphql-transformer/transform-config.ts deleted file mode 100644 index fdb5318cc8..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/transform-config.ts +++ /dev/null @@ -1,107 +0,0 @@ -import * as path from 'path'; -import { TransformConfig } from '@aws-amplify/graphql-transformer-core'; -import { AmplifyError } from '@aws-amplify/amplify-cli-core'; -import fs from 'fs-extra'; -import { TRANSFORM_CONFIG_FILE_NAME } from 'graphql-transformer-core'; - -export interface ProjectOptions { - projectDirectory?: string; - transformersFactory: Function; - transformersFactoryArgs: object[]; - currentCloudBackendDirectory: string; - rootStackFileName?: string; - dryRun?: boolean; - disableFunctionOverrides?: boolean; - disablePipelineFunctionOverrides?: boolean; - disableResolverOverrides?: boolean; - buildParameters?: Object; -} - -/** - * try to load transformer config from specified projectDir - * if it does not exist then we return a blank object - * */ - -export async function loadConfig(projectDir: string): Promise { - // Initialize the config always with the latest version, other members are optional for now. - let config: TransformConfig = {}; - try { - const configPath = path.join(projectDir, TRANSFORM_CONFIG_FILE_NAME); - const configExists = fs.existsSync(configPath); - if (configExists) { - const configStr = await fs.readFile(configPath, 'utf-8'); - config = JSON.parse(configStr); - } - return config as TransformConfig; - } catch (err) { - return config; - } -} - -export async function writeConfig(projectDir: string, config: TransformConfig): Promise { - const configFilePath = path.join(projectDir, TRANSFORM_CONFIG_FILE_NAME); - await fs.writeFile(configFilePath, JSON.stringify(config, null, 4)); - return config; -} - -export function throwIfNotJSONExt(stackFile: string): void { - const extension = path.extname(stackFile); - if (extension === '.yaml' || extension === '.yml') { - throw new AmplifyError('CloudFormationTemplateError', { - message: 'Yaml is not yet supported', - resolution: `Please convert the CloudFormation stack ${stackFile} to json.`, - }); - } - if (extension !== '.json') { - throw new AmplifyError('CloudFormationTemplateError', { - message: `Invalid extension ${extension} for stack ${stackFile}`, - resolution: `Convert the CloudFormation stack ${stackFile} to json.`, - }); - } -} - -/** - * Given a project directory read the schema from disk. The schema may be a - * single schema.graphql or a set of .graphql files in a directory named `schema`. - * Preference is given to the `schema.graphql` if provided. - * @param projectDirectory The project directory. - */ -export async function readSchema(projectDirectory: string): Promise { - const schemaFilePath = path.join(projectDirectory, 'schema.graphql'); - const schemaDirectoryPath = path.join(projectDirectory, 'schema'); - const schemaFileExists = fs.existsSync(schemaFilePath); - const schemaDirectoryExists = fs.existsSync(schemaDirectoryPath); - let schema; - if (schemaFileExists) { - schema = (await fs.readFile(schemaFilePath)).toString(); - } else if (schemaDirectoryExists) { - schema = (await readSchemaDocuments(schemaDirectoryPath)).join('\n'); - } else { - throw new AmplifyError('ApiCategorySchemaNotFoundError', { - message: 'No schema found', - resolution: `GraphQL schema should be either in ${schemaFilePath} or at schema directory ${schemaDirectoryPath}`, - }); - } - return schema; -} - -async function readSchemaDocuments(schemaDirectoryPath: string): Promise { - const files = await fs.readdir(schemaDirectoryPath); - let schemaDocuments = []; - for (const fileName of files) { - if (fileName.indexOf('.') === 0) { - continue; - } - - const fullPath = `${schemaDirectoryPath}/${fileName}`; - const stats = await fs.lstat(fullPath); - if (stats.isDirectory()) { - const childDocs = await readSchemaDocuments(fullPath); - schemaDocuments = schemaDocuments.concat(childDocs); - } else if (stats.isFile()) { - const schemaDoc = await fs.readFile(fullPath); - schemaDocuments.push(schemaDoc); - } - } - return schemaDocuments; -} diff --git a/packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema-v1.ts b/packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema-v1.ts deleted file mode 100644 index 9c073446e0..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema-v1.ts +++ /dev/null @@ -1,466 +0,0 @@ -import path from 'path'; -import fs from 'fs-extra'; -import chalk from 'chalk'; -import inquirer from 'inquirer'; -import { - $TSContext, - AmplifyCategories, - ApiCategoryFacade, - CloudformationProviderFacade, - getGraphQLTransformerAuthDocLink, - getGraphQLTransformerAuthSubscriptionsDocLink, - getGraphQLTransformerOpenSearchProductionDocLink, - JSONUtilities, - pathManager, - stateManager, - exitOnNextTick, -} from '@aws-amplify/amplify-cli-core'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { - collectDirectivesByTypeNames, - readTransformerConfiguration, - writeTransformerConfiguration, - TRANSFORM_CONFIG_FILE_NAME, - TRANSFORM_BASE_VERSION, - CLOUDFORMATION_FILE_NAME, - revertAPIMigration, - migrateAPIProject, - readProjectConfiguration, - buildAPIProject, - getSanityCheckRules, -} from 'graphql-transformer-core'; -import { isAuthModeUpdated } from './auth-mode-compare'; -import { AmplifyCLIFeatureFlagAdapter } from './amplify-cli-feature-flag-adapter'; -import { searchablePushChecks } from './api-utils'; -import { getTransformerFactoryV1 } from './transformer-factory'; - -const apiCategory = 'api'; -const parametersFileName = 'parameters.json'; -const schemaFileName = 'schema.graphql'; -const schemaDirName = 'schema'; -const ROOT_APPSYNC_S3_KEY = 'amplify-appsync-files'; -const DESTRUCTIVE_UPDATES_FLAG = 'allow-destructive-graphql-schema-updates'; -const PROVIDER_NAME = 'awscloudformation'; - -async function warnOnAuth(context, map) { - const unAuthModelTypes = Object.keys(map).filter((type) => !map[type].includes('auth') && map[type].includes('model')); - if (unAuthModelTypes.length) { - const transformerVersion = await ApiCategoryFacade.getTransformerVersion(context); - const docLink = getGraphQLTransformerAuthDocLink(transformerVersion); - context.print.warning("\nThe following types do not have '@auth' enabled. Consider using @auth with @model"); - context.print.warning(unAuthModelTypes.map((type) => `\t - ${type}`).join('\n')); - context.print.info(`Learn more about @auth here: ${docLink}\n`); - } -} - -/** - * @TODO Include a map of versions to keep track - */ -async function transformerVersionCheck(context, resourceDir, cloudBackendDirectory, updatedResources, usedDirectives) { - const transformerVersion = await ApiCategoryFacade.getTransformerVersion(context); - const authDocLink = getGraphQLTransformerAuthSubscriptionsDocLink(transformerVersion); - const searchable = getGraphQLTransformerOpenSearchProductionDocLink(transformerVersion); - const versionChangeMessage = `The default behavior for @auth has changed in the latest version of Amplify\nRead here for details: ${authDocLink}`; - const warningESMessage = `The behavior for @searchable has changed after version 4.14.1.\nRead here for details: ${searchable}`; - const checkVersionExist = (config) => config && config.Version; - const checkESWarningExists = (config) => config && config.ElasticsearchWarning; - let writeToConfig = false; - - // this is where we check if there is a prev version of the transformer being used - // by using the transformer.conf.json file - const cloudTransformerConfig = await readTransformerConfiguration(cloudBackendDirectory); - const cloudVersionExist = checkVersionExist(cloudTransformerConfig); - const cloudWarningExist = checkESWarningExists(cloudTransformerConfig); - - // check local resource if the question has been answered before - const localTransformerConfig = await readTransformerConfiguration(resourceDir); - const localVersionExist = checkVersionExist(localTransformerConfig); - const localWarningExist = checkESWarningExists(localTransformerConfig); - - // if we already asked the confirmation question before at a previous push - // or during current operations we should not ask again. - const showPrompt = !(cloudVersionExist || localVersionExist); - const showWarning = !(cloudWarningExist || localWarningExist); - - const resources = updatedResources.filter((resource) => resource.service === 'AppSync'); - if (resources.length > 0) { - if (showPrompt && usedDirectives.includes('auth')) { - await warningMessage(context, versionChangeMessage); - } - if (showWarning && usedDirectives.includes('searchable')) { - await warningMessage(context, warningESMessage); - } - } - - // searchable warning flag - - // Only touch the file if it misses the Version property - // Always set to the base version, to not to break existing projects when coming - // from an older version of the CLI. - if (!localTransformerConfig.Version) { - localTransformerConfig.Version = TRANSFORM_BASE_VERSION; - writeToConfig = true; - } - // Add the warning as noted in the elasticsearch - if (!localTransformerConfig.warningESMessage) { - localTransformerConfig.ElasticsearchWarning = true; - writeToConfig = true; - } - if (writeToConfig) { - await writeTransformerConfiguration(resourceDir, localTransformerConfig); - } -} - -async function warningMessage(context, warningMessage) { - if (context.exeInfo && context.exeInfo.inputParams && context.exeInfo.inputParams.yes) { - context.print.warning(`\n${warningMessage}\n`); - } else { - context.print.warning(`\n${warningMessage}\n`); - const response = await inquirer.prompt({ - name: 'transformerConfig', - type: 'confirm', - message: `Do you wish to continue?`, - default: false, - }); - if (!response.transformerConfig) { - await context.usageData.emitSuccess(); - exitOnNextTick(0); - } - } -} - -function apiProjectIsFromOldVersion(pathToProject, resourcesToBeCreated) { - const resources = resourcesToBeCreated.filter((resource) => resource.service === 'AppSync'); - if (!pathToProject || resources.length > 0) { - return false; - } - return fs.existsSync(`${pathToProject}/${CLOUDFORMATION_FILE_NAME}`) && !fs.existsSync(`${pathToProject}/${TRANSFORM_CONFIG_FILE_NAME}`); -} - -/** - * API migration happens in a few steps. First we calculate which resources need - * to remain in the root stack (DDB tables, ES Domains, etc) and write them to - * transform.conf.json. We then call CF's update stack on the root stack such - * that only the resources that need to be in the root stack remain there - * (this deletes resolvers from the schema). We then compile the project with - * the new implementation and call update stack again. - * @param {*} context - * @param {*} resourceDir - */ -async function migrateProject(context, options) { - const { resourceDir, isCLIMigration, cloudBackendDirectory } = options; - const updateAndWaitForStack = options.handleMigration || (() => Promise.resolve('Skipping update')); - let oldProjectConfig; - let oldCloudBackend; - try { - context.print.info('\nMigrating your API. This may take a few minutes.'); - const { project, cloudBackend } = await migrateAPIProject({ - projectDirectory: resourceDir, - cloudBackendDirectory, - }); - oldProjectConfig = project; - oldCloudBackend = cloudBackend; - await updateAndWaitForStack({ isCLIMigration }); - } catch (e) { - await revertAPIMigration(resourceDir, oldProjectConfig); - throw e; - } - try { - // After the intermediate update, we need the transform function - // to look at this directory since we did not overwrite the currentCloudBackend with the build - options.cloudBackendDirectory = resourceDir; - await transformGraphQLSchemaV1(context, options); - const result = await updateAndWaitForStack({ isCLIMigration }); - context.print.info('\nFinished migrating API.'); - return result; - } catch (e) { - context.print.error('Reverting API migration.'); - await revertAPIMigration(resourceDir, oldCloudBackend); - try { - await updateAndWaitForStack({ isReverting: true, isCLIMigration }); - } catch (e) { - context.print.error('Error reverting intermediate migration stack.'); - } - await revertAPIMigration(resourceDir, oldProjectConfig); - context.print.error('API successfully reverted.'); - throw e; - } -} - -export async function transformGraphQLSchemaV1(context, options) { - const backEndDir = context.amplify.pathManager.getBackendDirPath(); - const flags = context.parameters.options; - if (flags['no-gql-override']) { - return; - } - - let { resourceDir, parameters } = options; - const { forceCompile } = options; - - // Compilation during the push step - const { resourcesToBeCreated, resourcesToBeUpdated, allResources } = await context.amplify.getResourceStatus(apiCategory); - let resources = resourcesToBeCreated.concat(resourcesToBeUpdated); - - // When build folder is missing include the API - // to be compiled without the backend/api//build - // cloud formation push will fail even if there is no changes in the GraphQL API - // https://github.com/aws-amplify/amplify-console/issues/10 - const resourceNeedCompile = allResources - .filter((r) => !resources.includes(r)) - .filter((r) => { - const buildDir = path.normalize(path.join(backEndDir, apiCategory, r.resourceName, 'build')); - return !fs.existsSync(buildDir); - }); - resources = resources.concat(resourceNeedCompile); - - if (forceCompile) { - resources = resources.concat(allResources); - } - resources = resources.filter((resource) => resource.service === 'AppSync'); - // check if api is in update status or create status - const isNewAppSyncAPI: boolean = resourcesToBeCreated.filter((resource) => resource.service === 'AppSync').length !== 0; - - if (!resourceDir) { - // There can only be one appsync resource - if (resources.length > 0) { - const resource = resources[0]; - if (resource.providerPlugin !== PROVIDER_NAME) { - return; - } - const { category, resourceName } = resource; - resourceDir = path.normalize(path.join(backEndDir, category, resourceName)); - } else { - // No appsync resource to update/add - return; - } - } - - let previouslyDeployedBackendDir = options.cloudBackendDirectory; - if (!previouslyDeployedBackendDir) { - if (resources.length > 0) { - const resource = resources[0]; - if (resource.providerPlugin !== PROVIDER_NAME) { - return; - } - const { category, resourceName } = resource; - const cloudBackendRootDir = context.amplify.pathManager.getCurrentCloudBackendDirPath(); - /* eslint-disable */ - previouslyDeployedBackendDir = path.normalize(path.join(cloudBackendRootDir, category, resourceName)); - /* eslint-enable */ - } - } - - const parametersFilePath = path.join(resourceDir, parametersFileName); - - if (!parameters && fs.existsSync(parametersFilePath)) { - try { - parameters = JSONUtilities.readJson(parametersFilePath); - } catch (e) { - parameters = {}; - } - } - - const isCLIMigration = options.migrate; - const isOldApiVersion = apiProjectIsFromOldVersion(previouslyDeployedBackendDir, resourcesToBeCreated); - const migrateOptions = { - ...options, - resourceDir, - migrate: false, - isCLIMigration, - cloudBackendDirectory: previouslyDeployedBackendDir, - }; - if (isCLIMigration && isOldApiVersion) { - return await migrateProject(context, migrateOptions); - } else if (isOldApiVersion) { - let IsOldApiProject; - - if (context.exeInfo && context.exeInfo.inputParams && context.exeInfo.inputParams.yes) { - IsOldApiProject = context.exeInfo.inputParams.yes; - } else { - const migrateMessage = - `${chalk.bold('The CLI is going to take the following actions during the migration step:')}\n` + - '\n1. If you have a GraphQL API, we will update the corresponding Cloudformation stack to support larger annotated schemas and custom resolvers.\n' + - 'In this process, we will be making Cloudformation API calls to update your GraphQL API Cloudformation stack. This operation will result in deletion of your AppSync resolvers and then the creation of new ones and for a brief while your AppSync API will be unavailable until the migration finishes\n' + - '\n2. We will be updating your local Cloudformation files present inside the ‘amplify/‘ directory of your app project, for the GraphQL API service\n' + - '\n3. If for any reason the migration fails, the CLI will rollback your cloud and local changes and you can take a look at https://aws-amplify.github.io/docs/cli/migrate?sdk=js for manually migrating your project so that it’s compatible with the latest version of the CLI\n' + - '\n4. ALL THE ABOVE MENTIONED OPERATIONS WILL NOT DELETE ANY DATA FROM ANY OF YOUR DATA STORES\n' + - `\n${chalk.bold('Before the migration, please be aware of the following things:')}\n` + - '\n1. Make sure to have an internet connection through the migration process\n' + - '\n2. Make sure to not exit/terminate the migration process (by interrupting it explicitly in the middle of migration), as this will lead to inconsistency within your project\n' + - '\n3. Make sure to take a backup of your entire project (including the amplify related config files)\n' + - '\nDo you want to continue?\n'; - ({ IsOldApiProject } = await inquirer.prompt({ - name: 'IsOldApiProject', - type: 'confirm', - message: migrateMessage, - default: true, - })); - } - if (!IsOldApiProject) { - throw new Error('Migration cancelled. Please downgrade to a older version of the Amplify CLI or migrate your API project.'); - } - return await migrateProject(context, migrateOptions); - } - - let { authConfig } = options; - - // - // If we don't have an authConfig from the caller, use it from the - // already read resources[0], which is an AppSync API. - // - - if (!authConfig) { - if (resources[0].output.securityType) { - // Convert to multi-auth format if needed. - authConfig = { - defaultAuthentication: { - authenticationType: resources[0].output.securityType, - }, - additionalAuthenticationProviders: [], - }; - } else { - ({ authConfig } = resources[0].output); - } - } - - // for the predictions directive get storage config - const s3ResourceName = await invokeS3GetResourceName(context); - const storageConfig = { - bucketName: s3ResourceName ? await getBucketName(context, s3ResourceName) : undefined, - }; - - const buildDir = path.normalize(path.join(resourceDir, 'build')); - const schemaFilePath = path.normalize(path.join(resourceDir, schemaFileName)); - const schemaDirPath = path.normalize(path.join(resourceDir, schemaDirName)); - let deploymentRootKey = await getPreviousDeploymentRootKey(previouslyDeployedBackendDir); - if (!deploymentRootKey) { - const deploymentSubKey = await CloudformationProviderFacade.hashDirectory(context, resourceDir); - deploymentRootKey = `${ROOT_APPSYNC_S3_KEY}/${deploymentSubKey}`; - } - const projectBucket = options.dryRun ? 'fake-bucket' : getProjectBucket(context); - const buildParameters = { - ...parameters, - S3DeploymentBucket: projectBucket, - S3DeploymentRootKey: deploymentRootKey, - }; - - // If it is a dry run, don't create the build folder as it could make a follow-up command - // to not to trigger a build, hence a corrupt deployment. - if (!options.dryRun) { - fs.ensureDirSync(buildDir); - } - - // Transformer compiler code - // const schemaText = await readProjectSchema(resourceDir); - const project = await readProjectConfiguration(resourceDir); - - // Check for common errors - const directiveMap = collectDirectivesByTypeNames(project.schema); - await warnOnAuth(context, directiveMap.types); - await searchablePushChecks(context, directiveMap.types, parameters[ResourceConstants.PARAMETERS.AppSyncApiName]); - - await transformerVersionCheck(context, resourceDir, previouslyDeployedBackendDir, resourcesToBeUpdated, directiveMap.directives); - - const transformerListFactory = await getTransformerFactoryV1(context, resourceDir, authConfig); - - let searchableTransformerFlag = false; - - if (directiveMap.directives.includes('searchable')) { - searchableTransformerFlag = true; - } - - const ff = new AmplifyCLIFeatureFlagAdapter(); - const allowDestructiveUpdates = context?.input?.options?.[DESTRUCTIVE_UPDATES_FLAG] || context?.input?.options?.force; - const sanityCheckRulesList = getSanityCheckRules(isNewAppSyncAPI, ff, allowDestructiveUpdates); - - const buildConfig = { - ...options, - buildParameters, - projectDirectory: resourceDir, - transformersFactory: transformerListFactory, - transformersFactoryArgs: [searchableTransformerFlag, storageConfig], - rootStackFileName: 'cloudformation-template.json', - currentCloudBackendDirectory: previouslyDeployedBackendDir, - featureFlags: ff, - sanityCheckRules: sanityCheckRulesList, - }; - const transformerOutput = await buildAPIProject(buildConfig); - - context.print.success(`GraphQL schema compiled successfully.\n\nEdit your schema at ${schemaFilePath} or \ -place .graphql files in a directory at ${schemaDirPath}`); - - if (isAuthModeUpdated(options)) { - parameters.AuthModeLastUpdated = new Date(); - } - if (!options.dryRun) { - JSONUtilities.writeJson(parametersFilePath, parameters); - } - - return transformerOutput; -} - -function getProjectBucket(context) { - const projectDetails = context.amplify.getProjectDetails(); - const projectBucket = projectDetails.amplifyMeta.providers - ? projectDetails.amplifyMeta.providers[PROVIDER_NAME].DeploymentBucketName - : ''; - return projectBucket; -} - -async function getPreviousDeploymentRootKey(previouslyDeployedBackendDir) { - // this is the function - let parameters; - try { - const parametersPath = path.join(previouslyDeployedBackendDir, 'build', parametersFileName); - const parametersExists = fs.existsSync(parametersPath); - if (parametersExists) { - const parametersString = await fs.readFile(parametersPath); - parameters = JSON.parse(parametersString.toString()); - } - return parameters.S3DeploymentRootKey; - } catch (err) { - return undefined; - } -} - -// TODO: Remove until further discussion -// function getTransformerOptions(project, transformerName) { -// if ( -// project && -// project.config && -// project.config.TransformerOptions && -// project.config.TransformerOptions[transformerName] -// ) { -// return project.config.TransformerOptions[transformerName]; -// } -// return undefined; -// } - -/** - * S3API - * TBD: Remove this once all invoke functions are moved to a library shared across amplify - * */ -async function invokeS3GetResourceName(context) { - const s3ResourceName = await context.amplify.invokePluginMethod(context, 'storage', undefined, 's3GetResourceName', [context]); - return s3ResourceName; -} - -async function getBucketName(context: $TSContext, s3ResourceName: string) { - const { amplify } = context; - const { amplifyMeta } = amplify.getProjectDetails(); - const stackName = amplifyMeta.providers.awscloudformation.StackName; - const s3ResourcePath = pathManager.getResourceDirectoryPath(undefined, AmplifyCategories.STORAGE, s3ResourceName); - const cliInputsPath = path.join(s3ResourcePath, 'cli-inputs.json'); - let bucketParameters; - // get bucketParameters 1st from cli-inputs , if not present, then parameters.json - if (fs.existsSync(cliInputsPath)) { - bucketParameters = JSONUtilities.readJson(cliInputsPath); - } else { - bucketParameters = stateManager.getResourceParametersJson(undefined, AmplifyCategories.STORAGE, s3ResourceName); - } - - const bucketName = stackName.startsWith('amplify-') - ? `${bucketParameters.bucketName}\${hash}-\${env}` - : `${bucketParameters.bucketName}${s3ResourceName}-\${env}`; - return bucketName; -} diff --git a/packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema-v2.ts b/packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema-v2.ts deleted file mode 100644 index daa6496094..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema-v2.ts +++ /dev/null @@ -1,484 +0,0 @@ -import path from 'path'; -import { - constructSqlDirectiveDataSourceStrategies, - DDB_AMPLIFY_MANAGED_DATASOURCE_STRATEGY, - DDB_DEFAULT_DATASOURCE_STRATEGY, - getDefaultStrategyNameForDbType, - getImportedRDSTypeFromStrategyDbType, - isDynamoDbType, - isSqlDbType, - UserDefinedSlot, -} from '@aws-amplify/graphql-transformer-core'; -import { - AppSyncAuthConfiguration, - DataSourceStrategiesProvider, - ModelDataSourceStrategy, - ModelDataSourceStrategyDbType, - ModelDataSourceStrategySqlDbType, - RDSLayerMapping, - RDSSNSTopicMapping, - SQLLambdaModelDataSourceStrategy, - SqlDirectiveDataSourceStrategy, - SqlModelDataSourceDbConnectionConfig, - TransformerLog, - TransformerLogLevel, - VpcConfig, -} from '@aws-amplify/graphql-transformer-interfaces'; -import * as fs from 'fs-extra'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { sanityCheckProject } from 'graphql-transformer-core'; -import _ from 'lodash'; -import { executeTransform } from '@aws-amplify/graphql-transformer'; -import { $TSContext, AmplifyCategories, AmplifySupportedService, JSONUtilities, pathManager } from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; -import { getHostVpc } from '@aws-amplify/graphql-schema-generator'; -import fetch from 'node-fetch'; -import { - getConnectionSecrets, - getExistingConnectionDbConnectionConfig, - getSecretsKey, -} from '../provider-utils/awscloudformation/utils/rds-resources/database-resources'; -import { getAppSyncAPIName } from '../provider-utils/awscloudformation/utils/amplify-meta-utils'; -import { checkForUnsupportedDirectives, containsSqlModelOrDirective } from '../provider-utils/awscloudformation/utils/rds-resources/utils'; -import { isAuthModeUpdated } from './auth-mode-compare'; -import { getAdminRoles, getIdentityPoolId, mergeUserConfigWithTransformOutput, writeDeploymentToDisk } from './utils'; -import { generateTransformerOptions } from './transformer-options-v2'; -import { TransformerProjectOptions } from './transformer-options-types'; -import { DeploymentResources } from './cdk-compat/deployment-resources'; -import { TransformManager } from './cdk-compat/transform-manager'; - -const PARAMETERS_FILENAME = 'parameters.json'; -const SCHEMA_FILENAME = 'schema.graphql'; -const SCHEMA_DIR_NAME = 'schema'; -const PROVIDER_NAME = 'awscloudformation'; -const USE_BETA_SQL_LAYER = 'use-beta-sql-layer'; - -/** - * Transform GraphQL Schema - */ -export const transformGraphQLSchemaV2 = async (context: $TSContext, options): Promise => { - let resourceName: string; - const backEndDir = pathManager.getBackendDirPath(); - const flags = context.parameters.options; - if (flags['no-gql-override']) { - return undefined; - } - - let { resourceDir, parameters } = options; - const { forceCompile } = options; - - // Compilation during the push step - const { resourcesToBeCreated, resourcesToBeUpdated, allResources } = await context.amplify.getResourceStatus(AmplifyCategories.API); - let resources = resourcesToBeCreated.concat(resourcesToBeUpdated); - - // When build folder is missing include the API - // to be compiled without the backend/api//build - // cloud formation push will fail even if there is no changes in the GraphQL API - // https://github.com/aws-amplify/amplify-console/issues/10 - const resourceNeedCompile = allResources - .filter((r) => !resources.includes(r)) - .filter((r) => { - const buildDir = path.normalize(path.join(backEndDir, AmplifyCategories.API, r.resourceName, 'build')); - return !fs.pathExistsSync(buildDir); - }); - resources = resources.concat(resourceNeedCompile); - - if (forceCompile) { - resources = resources.concat(allResources); - } - resources = resources.filter((resource) => resource.service === 'AppSync'); - - if (!resourceDir) { - // There can only be one appsync resource - if (resources.length > 0) { - const resource = resources[0]; - if (resource.providerPlugin !== PROVIDER_NAME) { - return undefined; - } - const { category } = resource; - ({ resourceName } = resource); - resourceDir = path.normalize(path.join(backEndDir, category, resourceName)); - } else { - // No appsync resource to update/add - return undefined; - } - } - - const previouslyDeployedBackendDir = options.cloudBackendDirectory; - if (!previouslyDeployedBackendDir) { - if (resources.length > 0) { - const resource = resources[0]; - if (resource.providerPlugin !== PROVIDER_NAME) { - return undefined; - } - } - } - - const parametersFilePath = path.join(resourceDir, PARAMETERS_FILENAME); - - if (!parameters && fs.pathExistsSync(parametersFilePath)) { - try { - parameters = JSONUtilities.readJson(parametersFilePath); - - // OpenSearch Instance type support for x.y.search types - if (parameters[ResourceConstants.PARAMETERS.OpenSearchInstanceType]) { - parameters[ResourceConstants.PARAMETERS.OpenSearchInstanceType] = parameters[ - ResourceConstants.PARAMETERS.OpenSearchInstanceType - ].replace('.search', '.elasticsearch'); - } - } catch (e) { - parameters = {}; - } - } - - let { authConfig }: { authConfig: AppSyncAuthConfiguration } = options; - - if (_.isEmpty(authConfig) && !_.isEmpty(resources)) { - authConfig = await context.amplify.invokePluginMethod( - context, - AmplifyCategories.API, - AmplifySupportedService.APPSYNC, - 'getAuthConfig', - [context, resources[0].resourceName], - ); - // handle case where auth project is not migrated , if Auth not migrated above function will return empty Object - if (_.isEmpty(authConfig)) { - // - // If we don't have an authConfig from the caller, use it from the - // already read resources[0], which is an AppSync API. - // - if (resources[0].output.securityType) { - // Convert to multi-auth format if needed. - authConfig = { - defaultAuthentication: { - authenticationType: resources[0].output.securityType, - }, - additionalAuthenticationProviders: [], - }; - } else { - ({ authConfig } = resources[0].output); - } - } - } - - const buildDir = path.normalize(path.join(resourceDir, 'build')); - const schemaFilePath = path.normalize(path.join(resourceDir, SCHEMA_FILENAME)); - const schemaDirPath = path.normalize(path.join(resourceDir, SCHEMA_DIR_NAME)); - - // If it is a dry run, don't create the build folder as it could make a follow-up command - // to not to trigger a build, hence a corrupt deployment. - if (!options.dryRun) { - fs.ensureDirSync(buildDir); - } - - // The buildConfig.projectConfig returned by `generateTransformerOptions` is not actually compatible with DataSourceStrategiesProvider. We - // will correct that in buildAPIProject. - const buildConfig: TransformerProjectOptions = await generateTransformerOptions(context, options); - if (!buildConfig) { - return undefined; - } - - const transformerOutput = await buildAPIProject(context, buildConfig); - - printer.success(`GraphQL schema compiled successfully.\n\nEdit your schema at ${schemaFilePath} or \ -place .graphql files in a directory at ${schemaDirPath}`); - - if (isAuthModeUpdated(options)) { - parameters.AuthModeLastUpdated = new Date(); - } - if (!options.dryRun) { - JSONUtilities.writeJson(parametersFilePath, parameters); - } - - return transformerOutput; -}; - -const getAuthenticationTypesForAuthConfig = (authConfig?: AppSyncAuthConfiguration): (string | undefined)[] => - [authConfig?.defaultAuthentication, ...(authConfig?.additionalAuthenticationProviders ?? [])].map( - (authConfigEntry) => authConfigEntry?.authenticationType, - ); - -const hasIamAuth = (authConfig?: AppSyncAuthConfiguration): boolean => - getAuthenticationTypesForAuthConfig(authConfig).some((authType) => authType === 'AWS_IAM'); - -const hasUserPoolAuth = (authConfig?: AppSyncAuthConfiguration): boolean => - getAuthenticationTypesForAuthConfig(authConfig).some((authType) => authType === 'AMAZON_COGNITO_USER_POOLS'); - -/** - * Given an array of DataSourceType shapes from the Gen1 CLI import flow, finds the single SQL database type. Throws an error if more than - * one SQL database type is detected. - */ -const getSqlDbTypeFromDataSourceTypes = ( - dataSourceTypes: Array<{ - dbType: ModelDataSourceStrategyDbType; - provisionDB: boolean; - provisionStrategy: 'DEFAULT' | 'AMPLIFY_TABLE'; - }>, -): ModelDataSourceStrategySqlDbType | undefined => { - const dbTypes = Object.values(dataSourceTypes) - .map((dsType) => dsType.dbType) - .filter(isSqlDbType); - if (dbTypes.length === 0) { - return undefined; - } - if (new Set(dbTypes).size > 1) { - throw new Error(`Multiple imported SQL datasource types ${Array.from(dbTypes)} are detected. Only one type is supported.`); - } - return dbTypes[0]; -}; - -/** - * The `projectConfig` argument to `fixUpDataSourceStrategiesProvider` is a `ProjectConfiguration` from the Gen1 CLI import flow. That type - * is not exported, and don't want to pollute the Gen2 / CDK compat interfaces with those legacy attributes, so instead we'll strongly type - * the fields we're interested in operating on. - */ -interface Gen1ProjectConfiguration { - schema: string; - modelToDatasourceMap: Map< - string, - { - dbType: ModelDataSourceStrategyDbType; - provisionDB: boolean; - provisionStrategy: 'DEFAULT' | 'AMPLIFY_TABLE'; - } - >; - customQueries: Map; -} - -/** - * Utility to fix up the project config generated by the Gen1 CLI flow into the ModelDataSourceStrategy types expected by the transformer - * internals. Internally, this function makes network calls to retrieve the database connection parameter info from SSM, and uses those - * values to discover VPC configurations for the database. - */ -const fixUpDataSourceStrategiesProvider = async ( - context: $TSContext, - projectConfig: Gen1ProjectConfiguration, -): Promise => { - const modelToDatasourceMap = projectConfig.modelToDatasourceMap ?? new Map(); - const datasourceMapValues: Array<{ - dbType: ModelDataSourceStrategyDbType; - provisionDB: boolean; - provisionStrategy: 'DEFAULT' | 'AMPLIFY_TABLE'; - }> = modelToDatasourceMap ? Array.from(modelToDatasourceMap.values()) : []; - - // We allow a DynamoDB and SQL data source to live alongside each other, although we don't (yet) support relationships between them. We'll - // process the dbTypes separately so we can validate that there is only one SQL source. - const dataSourceStrategies: Record = {}; - modelToDatasourceMap.forEach((value, key) => { - if (!isDynamoDbType(value.dbType)) { - return; - } - switch (value.provisionStrategy) { - case 'DEFAULT': - dataSourceStrategies[key] = DDB_DEFAULT_DATASOURCE_STRATEGY; - break; - case 'AMPLIFY_TABLE': - dataSourceStrategies[key] = DDB_AMPLIFY_MANAGED_DATASOURCE_STRATEGY; - break; - default: - throw new Error(`Unsupported provisionStrategy ${value.provisionStrategy}`); - } - }); - - const sqlDbType = getSqlDbTypeFromDataSourceTypes(datasourceMapValues); - let sqlDirectiveDataSourceStrategies: SqlDirectiveDataSourceStrategy[] | undefined; - if (sqlDbType) { - const dbConnectionConfig = getDbConnectionConfig(); - const vpcConfiguration = await isSqlLambdaVpcConfigRequired(context, sqlDbType); - const strategy: SQLLambdaModelDataSourceStrategy = { - name: getDefaultStrategyNameForDbType(sqlDbType), - dbType: sqlDbType, - dbConnectionConfig, - vpcConfiguration, - }; - modelToDatasourceMap.forEach((value, key) => { - if (!isSqlDbType(value.dbType)) { - return; - } - dataSourceStrategies[key] = strategy; - }); - - let customSqlStatements: Record | undefined; - if (typeof projectConfig.customQueries === 'object') { - customSqlStatements = {}; - (projectConfig.customQueries as Map).forEach((value, key) => { - customSqlStatements[key] = value; - }); - } - - sqlDirectiveDataSourceStrategies = constructSqlDirectiveDataSourceStrategies(projectConfig.schema, strategy, customSqlStatements); - } - - return { - dataSourceStrategies, - sqlDirectiveDataSourceStrategies, - }; -}; - -/** - * buildAPIProject - * - * Note that SQL-backed API support is quite limited in this function. Notably: - * - It requires there is only one SQL data source in the API - * - It does not support declaring a SQL schema without a `@model` tied to a SQL data source - * - * TODO: Remove SQL handling from Gen1 CLI. - */ -const buildAPIProject = async (context: $TSContext, opts: TransformerProjectOptions): Promise => { - // The incoming opts.projectConfig is not actually compatible with DataSourceStrategiesProvider. We will correct that in this function. - - const schema = opts.projectConfig.schema.toString(); - // Skip building the project if the schema is blank - if (!schema) { - return undefined; - } - - const { dataSourceStrategies, sqlDirectiveDataSourceStrategies } = await fixUpDataSourceStrategiesProvider( - context, - opts.projectConfig as unknown as Gen1ProjectConfiguration, - ); - - checkForUnsupportedDirectives(schema, { dataSourceStrategies }); - - const useBetaSqlLayer = context?.input?.options?.[USE_BETA_SQL_LAYER] ?? false; - - // Read the RDS Mapping S3 Manifest only if the schema contains SQL models or @sql directives. - let rdsLayerMapping: RDSLayerMapping | undefined = undefined; - let rdsSnsTopicMapping: RDSSNSTopicMapping | undefined = undefined; - if (containsSqlModelOrDirective(dataSourceStrategies, sqlDirectiveDataSourceStrategies)) { - rdsLayerMapping = await getRDSLayerMapping(context, useBetaSqlLayer); - rdsSnsTopicMapping = await getRDSSNSTopicMapping(context, useBetaSqlLayer); - } - - const transformManager = new TransformManager( - opts.overrideConfig, - hasIamAuth(opts.authConfig), - hasUserPoolAuth(opts.authConfig), - await getAdminRoles(context, opts.resourceName), - await getIdentityPoolId(context), - ); - - executeTransform({ - ...opts, - scope: transformManager.rootStack, - nestedStackProvider: transformManager.getNestedStackProvider(), - assetProvider: transformManager.getAssetProvider(), - parameterProvider: transformManager.getParameterProvider(), - synthParameters: transformManager.getSynthParameters(), - schema, - dataSourceStrategies, - sqlDirectiveDataSourceStrategies, - printTransformerLog, - rdsLayerMapping, - rdsSnsTopicMapping, - }); - - const transformOutput: DeploymentResources = { - ...transformManager.generateDeploymentResources(), - userOverriddenSlots: opts.userDefinedSlots ? getUserOverridenSlots(opts.userDefinedSlots) : [], - }; - - const builtProject = mergeUserConfigWithTransformOutput(opts.projectConfig, transformOutput, opts); - - const buildLocation = path.join(opts.projectDirectory, 'build'); - const currentCloudLocation = opts.currentCloudBackendDirectory ? path.join(opts.currentCloudBackendDirectory, 'build') : undefined; - - if (opts.projectDirectory && !opts.dryRun) { - await writeDeploymentToDisk(context, builtProject, buildLocation, opts.rootStackFileName, opts.buildParameters); - await sanityCheckProject( - currentCloudLocation, - buildLocation, - opts.rootStackFileName, - opts.sanityCheckRules.diffRules, - opts.sanityCheckRules.projectRules, - ); - } - - return builtProject; -}; - -export const getUserOverridenSlots = (userDefinedSlots: Record): string[] => - Object.values(userDefinedSlots) - .flat() - .flatMap((slot) => [slot.requestResolver?.fileName, slot.responseResolver?.fileName]) - .flat() - .filter((slotName) => slotName !== undefined); - -const getRDSLayerMapping = async (context: $TSContext, useBetaSqlLayer = false): Promise => { - const bucket = `${ResourceConstants.RESOURCES.SQLLayerManifestBucket}${useBetaSqlLayer ? '-beta' : ''}`; - const region = context.amplify.getProjectMeta().providers.awscloudformation.Region; - const url = `https://${bucket}.s3.amazonaws.com/${ResourceConstants.RESOURCES.SQLLayerVersionManifestKeyPrefix}${region}`; - const response = await fetch(url); - if (response.status === 200) { - const result = await response.text(); - const mapping = { - [region]: { - layerRegion: result, - }, - }; - return mapping as RDSLayerMapping; - } else { - throw new Error(`Unable to retrieve layer mapping from ${url} with status code ${response.status}.`); - } -}; - -const getRDSSNSTopicMapping = async (context: $TSContext, useBetaSqlLayer = false): Promise => { - const bucket = `${ResourceConstants.RESOURCES.SQLLayerManifestBucket}${useBetaSqlLayer ? '-beta' : ''}`; - const region = context.amplify.getProjectMeta().providers.awscloudformation.Region; - const url = `https://${bucket}.s3.amazonaws.com/${ResourceConstants.RESOURCES.SQLSNSTopicARNManifestKeyPrefix}${region}`; - const response = await fetch(url); - if (response.status === 200) { - const result = await response.text(); - const mapping = { - [region]: { - topicArn: result, - }, - }; - return mapping as RDSSNSTopicMapping; - } else { - throw new Error(`Unable to retrieve sns topic ARN mapping from ${url} with status code ${response.status}.`); - } -}; - -const isSqlLambdaVpcConfigRequired = async (context: $TSContext, dbType: ModelDataSourceStrategyDbType): Promise => { - // If the database is in VPC, we will use the same VPC configuration for the SQL lambda. - // Customers are required to add inbound rule for port 443 from the private subnet in the Security Group. - // https://docs.aws.amazon.com/systems-manager/latest/userguide/setup-create-vpc.html#vpc-requirements-and-limitations - const vpcSubnetConfig = await getSQLLambdaVpcConfig(context, dbType); - - return vpcSubnetConfig; -}; - -const getDbConnectionConfig = (): SqlModelDataSourceDbConnectionConfig => { - const apiName = getAppSyncAPIName(); - const secretsKey = getSecretsKey(); - const paths = getExistingConnectionDbConnectionConfig(apiName, secretsKey); - return paths; -}; - -const getSQLLambdaVpcConfig = async (context: $TSContext, dbType: ModelDataSourceStrategyDbType): Promise => { - const [secretsKey, engine] = [getSecretsKey(), getImportedRDSTypeFromStrategyDbType(dbType)]; - const { secrets } = await getConnectionSecrets(context, secretsKey, engine); - const region = context.amplify.getProjectMeta().providers.awscloudformation.Region; - const vpcConfig = await getHostVpc(secrets.host, region); - return vpcConfig; -}; - -const printTransformerLog = (log: TransformerLog): void => { - switch (log.level) { - case TransformerLogLevel.ERROR: - printer.error(log.message); - break; - case TransformerLogLevel.WARN: - printer.warn(log.message); - break; - case TransformerLogLevel.INFO: - printer.info(log.message); - break; - case TransformerLogLevel.DEBUG: - printer.debug(log.message); - break; - default: - printer.error(log.message); - } -}; diff --git a/packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema.ts b/packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema.ts deleted file mode 100644 index 6e192ef93a..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { DeploymentResources as DeploymentResourcesV1 } from 'graphql-transformer-core'; -import { $TSContext, ApiCategoryFacade } from '@aws-amplify/amplify-cli-core'; -import { AmplifyGraphQLTransformerErrorConverter } from '../errors/amplify-error-converter'; -import { DeploymentResources as DeploymentResourcesV2 } from './cdk-compat/deployment-resources'; -import { transformGraphQLSchemaV1 } from './transform-graphql-schema-v1'; -import { transformGraphQLSchemaV2 } from './transform-graphql-schema-v2'; - -/** - * Determine which transformer version is in effect, and execute the appropriate transformation. - */ -export const transformGraphQLSchema = async ( - context: $TSContext, - options: any, -): Promise => { - try { - const transformerVersion = await ApiCategoryFacade.getTransformerVersion(context); - return transformerVersion === 2 ? await transformGraphQLSchemaV2(context, options) : await transformGraphQLSchemaV1(context, options); - } catch (error) { - throw AmplifyGraphQLTransformerErrorConverter.convert(error); - } -}; diff --git a/packages/amplify-category-api/src/graphql-transformer/transformer-factory.ts b/packages/amplify-category-api/src/graphql-transformer/transformer-factory.ts deleted file mode 100644 index e4283bb514..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/transformer-factory.ts +++ /dev/null @@ -1,115 +0,0 @@ -import path from 'path'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { SearchableModelTransformer } from 'graphql-elasticsearch-transformer'; -import { VersionedModelTransformer } from 'graphql-versioned-transformer'; -import { FunctionTransformer } from 'graphql-function-transformer'; -import { HttpTransformer } from 'graphql-http-transformer'; -import { PredictionsTransformer } from 'graphql-predictions-transformer'; -import { KeyTransformer } from 'graphql-key-transformer'; -import { $TSContext, pathManager, stateManager, CloudformationProviderFacade } from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; -import { readTransformerConfiguration, TRANSFORM_CONFIG_FILE_NAME, ITransformer, TransformConfig } from 'graphql-transformer-core'; -import importFrom from 'import-from'; -import importGlobal from 'import-global'; - -const PROVIDER_NAME = 'awscloudformation'; - -export const getTransformerFactoryV1 = - (context: $TSContext, resourceDir: string, authConfig?: any) => async (addSearchableTransformer: boolean, storageConfig?: any) => { - const transformerList: ITransformer[] = [ - new DynamoDBModelTransformer(), - new VersionedModelTransformer(), - new FunctionTransformer(), - new HttpTransformer(), - new KeyTransformer(), - new ModelConnectionTransformer(), - new PredictionsTransformer(storageConfig), - ]; - - if (addSearchableTransformer) { - transformerList.push(new SearchableModelTransformer()); - } - - const customTransformersConfig: TransformConfig = await readTransformerConfiguration(resourceDir); - const customTransformers = ( - customTransformersConfig && customTransformersConfig.transformers ? customTransformersConfig.transformers : [] - ) - .map(importTransformerModule) - .map((imported) => { - const CustomTransformer = imported.default; - if (typeof CustomTransformer === 'function') return new CustomTransformer(); - if (typeof CustomTransformer === 'object') return CustomTransformer; - throw new Error("Custom Transformers' default export must be a function or an object"); - }) - .filter((customTransformer) => customTransformer); - - if (customTransformers.length > 0) { - transformerList.push(...customTransformers); - } - - // TODO: Build dependency mechanism into transformers. Auth runs last - // so any resolvers that need to be protected will already be created. - - let amplifyAdminEnabled = false; - - try { - const amplifyMeta = stateManager.getMeta(); - const appId = amplifyMeta?.providers?.[PROVIDER_NAME]?.AmplifyAppId; - const res = await CloudformationProviderFacade.isAmplifyAdminApp(context, appId); - amplifyAdminEnabled = res.isAdminApp; - } catch (err) { - // if it is not an AmplifyAdmin app, do nothing - } - - transformerList.push(new ModelAuthTransformer({ authConfig, addAwsIamAuthInOutputSchema: amplifyAdminEnabled })); - return transformerList; - }; - -/** - * Attempt to load the module from a transformer name using the following priority order - * - modulePath is an absolute path to an NPM package - * - modulePath is a package name, then it will be loaded from the project's root's node_modules with createRequireFromPath. - * - modulePath is a name of a globally installed package - */ -export const importTransformerModule = (transformerName: string): any => { - const fileUrlMatch = /^file:\/\/(.*)\s*$/m.exec(transformerName); - const modulePath = fileUrlMatch ? fileUrlMatch[1] : transformerName; - - if (!modulePath) { - throw new Error(`Invalid value specified for transformer: '${transformerName}'`); - } - - let importedModule; - const tempModulePath = modulePath.toString(); - - try { - if (path.isAbsolute(tempModulePath)) { - // Load it by absolute path - /* eslint-disable-next-line global-require, import/no-dynamic-require */ - importedModule = require(modulePath); - } else { - const projectRootPath = pathManager.findProjectRoot(); - const projectNodeModules = path.join(projectRootPath, 'node_modules'); - - try { - importedModule = importFrom(projectNodeModules, modulePath); - } catch { - // Intentionally left blank to try global - } - - // Try global package install - if (!importedModule) { - importedModule = importGlobal(modulePath); - } - } - - // At this point we've to have an imported module, otherwise module loader, threw an error. - return importedModule; - } catch (error) { - printer.error(`Unable to import custom transformer module(${modulePath}).`); - printer.error(`You may fix this error by editing transformers at ${path.join(transformerName, TRANSFORM_CONFIG_FILE_NAME)}`); - throw error; - } -}; diff --git a/packages/amplify-category-api/src/graphql-transformer/transformer-options-types.ts b/packages/amplify-category-api/src/graphql-transformer/transformer-options-types.ts deleted file mode 100644 index 9dffd06691..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/transformer-options-types.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * ProjectOptions Type Definition - */ -import { AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; -import type { TransformParameters } from '@aws-amplify/graphql-transformer-interfaces'; -import { ResolverConfig, UserDefinedSlot } from '@aws-amplify/graphql-transformer-core'; -import { DiffRule, ProjectRule } from 'graphql-transformer-core'; -import { TransformerFactoryArgs } from '@aws-amplify/graphql-transformer'; -import { Template } from './cdk-compat/deployment-resources'; -import { TransformerProjectConfig } from './cdk-compat/project-config'; -import { OverrideConfig } from './cdk-compat/transform-manager'; - -/** - * Transformer Options used to create a GraphQL Transform and compile a GQL API - */ -export type TransformerProjectOptions = { - resourceName: string; - buildParameters: { - S3DeploymentBucket: string; - S3DeploymentRootKey: string; - }; - projectDirectory: string; - transformersFactoryArgs: TransformerFactoryArgs; - rootStackFileName: 'cloudformation-template.json'; - currentCloudBackendDirectory?: string; - lastDeployedProjectConfig?: TransformerProjectConfig; - projectConfig: TransformerProjectConfig; - resolverConfig?: ResolverConfig; - dryRun?: boolean; - authConfig?: AppSyncAuthConfiguration; - stacks: Record; - sanityCheckRules: SanityCheckRules; - overrideConfig: OverrideConfig; - userDefinedSlots: Record; - stackMapping: Record; - transformParameters: TransformParameters; -}; - -type SanityCheckRules = { - diffRules: DiffRule[]; - projectRules: ProjectRule[]; -}; diff --git a/packages/amplify-category-api/src/graphql-transformer/transformer-options-v2.ts b/packages/amplify-category-api/src/graphql-transformer/transformer-options-v2.ts deleted file mode 100644 index bd4cc5ca77..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/transformer-options-v2.ts +++ /dev/null @@ -1,393 +0,0 @@ -import path from 'path'; -import { - $TSContext, - $TSMeta, - AmplifyCategories, - AmplifySupportedService, - CloudformationProviderFacade, - getGraphQLTransformerAuthDocLink, - JSONUtilities, - pathManager, - stateManager, -} from '@aws-amplify/amplify-cli-core'; -import { AppSyncAuthConfiguration, TransformerPluginProvider } from '@aws-amplify/graphql-transformer-interfaces'; -import { collectDirectivesByTypeNames } from '@aws-amplify/graphql-transformer-core'; -import { getSanityCheckRules, loadProject } from 'graphql-transformer-core'; -import fs from 'fs-extra'; -import { ResourceConstants } from 'graphql-transformer-common'; -import _ from 'lodash'; -import { printer } from '@aws-amplify/amplify-prompts'; -import type { TransformParameters } from '@aws-amplify/graphql-transformer-interfaces'; -import { Construct } from 'constructs'; -import { contextUtil } from '../category-utils/context-util'; -import { shouldEnableNodeToNodeEncryption } from '../provider-utils/awscloudformation/current-backend-state/searchable-node-to-node-encryption'; -import { schemaHasSandboxModeEnabled, showGlobalSandboxModeWarning, showSandboxModePrompts } from './sandbox-mode-helpers'; -import { importTransformerModule } from './transformer-factory'; -import { AmplifyCLIFeatureFlagAdapter } from './amplify-cli-feature-flag-adapter'; -import { DESTRUCTIVE_UPDATES_FLAG, PARAMETERS_FILENAME, PROVIDER_NAME, ROOT_APPSYNC_S3_KEY } from './constants'; -import { TransformerProjectOptions } from './transformer-options-types'; -import { searchablePushChecks } from './api-utils'; -import { parseUserDefinedSlots } from './user-defined-slots'; -import { applyFileBasedOverride } from './override'; -import { OverrideConfig } from './cdk-compat/transform-manager'; - -export const APPSYNC_RESOURCE_SERVICE = 'AppSync'; - -const warnOnAuth = (map: Record, docLink: string): void => { - const unAuthModelTypes = Object.keys(map).filter((type) => !map[type].includes('auth') && map[type].includes('model')); - if (unAuthModelTypes.length) { - printer.info( - ` -⚠️ WARNING: Some types do not have authorization rules configured. That means all create, read, update, and delete operations are denied on these types:`, - 'yellow', - ); - printer.info(unAuthModelTypes.map((type) => `\t - ${type}`).join('\n'), 'yellow'); - printer.info(`Learn more about "@auth" authorization rules here: ${docLink}`, 'yellow'); - } -}; - -/** - * Use current context to generate the Transformer options for generating - * a GraphQL Transformer V2 object - * @param context The $TSContext from the Amplify CLI - * @param options The any options config coming from the Amplify CLI - */ -export const generateTransformerOptions = async (context: $TSContext, options: any): Promise => { - let resourceName: string; - const backEndDir = pathManager.getBackendDirPath(); - const flags = context.parameters.options; - if (flags['no-gql-override']) { - return undefined; - } - - let { parameters } = options; - const { forceCompile } = options; - - // Compilation during the push step - const { resourcesToBeCreated, resourcesToBeUpdated, allResources } = await context.amplify.getResourceStatus(AmplifyCategories.API); - let resources = resourcesToBeCreated.concat(resourcesToBeUpdated); - - // When build folder is missing include the API - // to be compiled without the backend/api//build - // cloud formation push will fail even if there is no changes in the GraphQL API - // https://github.com/aws-amplify/amplify-console/issues/10 - const resourceNeedCompile = allResources - .filter((r) => !resources.includes(r)) - .filter((r) => { - const buildDir = path.normalize(path.join(backEndDir, AmplifyCategories.API, r.resourceName, 'build')); - return !fs.existsSync(buildDir); - }); - resources = resources.concat(resourceNeedCompile); - - if (forceCompile) { - resources = resources.concat(allResources); - } - resources = resources.filter((resource) => resource.service === APPSYNC_RESOURCE_SERVICE); - - const resourceDir = await contextUtil.getResourceDir(context, options); - - let previouslyDeployedBackendDir = options.cloudBackendDirectory; - if (!previouslyDeployedBackendDir) { - if (resources.length > 0) { - const resource = resources[0]; - if (resource.providerPlugin !== PROVIDER_NAME) { - return undefined; - } - const { category } = resource; - resourceName = resource.resourceName; - const cloudBackendRootDir = pathManager.getCurrentCloudBackendDirPath(); - /* eslint-disable */ - previouslyDeployedBackendDir = path.normalize(path.join(cloudBackendRootDir, category, resourceName)); - /* eslint-enable */ - } - } - - const parametersFilePath = path.join(resourceDir, PARAMETERS_FILENAME); - - if (!parameters && fs.existsSync(parametersFilePath)) { - try { - parameters = JSONUtilities.readJson(parametersFilePath); - - // OpenSearch Instance type support for x.y.search types - if (parameters[ResourceConstants.PARAMETERS.OpenSearchInstanceType]) { - parameters[ResourceConstants.PARAMETERS.OpenSearchInstanceType] = parameters[ - ResourceConstants.PARAMETERS.OpenSearchInstanceType - ].replace('.search', '.elasticsearch'); - } - } catch (e) { - parameters = {}; - } - } - - let { authConfig }: { authConfig: AppSyncAuthConfiguration } = options; - - if (_.isEmpty(authConfig) && !_.isEmpty(resources)) { - authConfig = await context.amplify.invokePluginMethod( - context, - AmplifyCategories.API, - AmplifySupportedService.APPSYNC, - 'getAuthConfig', - [context, resources[0].resourceName], - ); - // handle case where auth project is not migrated , if Auth not migrated above function will return empty Object - if (_.isEmpty(authConfig)) { - // - // If we don't have an authConfig from the caller, use it from the - // already read resources[0], which is an AppSync API. - // - if (resources[0].output.securityType) { - // Convert to multi-auth format if needed. - authConfig = { - defaultAuthentication: { - authenticationType: resources[0].output.securityType, - }, - additionalAuthenticationProviders: [], - }; - } else { - ({ authConfig } = resources[0].output); - } - } - } - - // for the predictions directive get storage config - const s3Resource = s3ResourceAlreadyExists(); - const storageConfig = s3Resource ? getBucketName(s3Resource) : undefined; - - let deploymentRootKey = await getPreviousDeploymentRootKey(previouslyDeployedBackendDir); - if (!deploymentRootKey) { - const deploymentSubKey = await CloudformationProviderFacade.hashDirectory(context, resourceDir); - deploymentRootKey = `${ROOT_APPSYNC_S3_KEY}/${deploymentSubKey}`; - } - const projectBucket = options.dryRun ? 'fake-bucket' : getProjectBucket(); - const buildParameters = { - ...parameters, - S3DeploymentBucket: projectBucket, - S3DeploymentRootKey: deploymentRootKey, - }; - - // The project configuration loaded here uses the Gen1 CLI DataSourceTypes and modelToDatasourceMap to hold model information. We'll - // convert it to the supported ModelDataSourceStrategy types later. - const project = await loadProject(resourceDir); - - const lastDeployedProjectConfig = fs.existsSync(previouslyDeployedBackendDir) - ? await loadProject(previouslyDeployedBackendDir) - : undefined; - const docLink = getGraphQLTransformerAuthDocLink(2); - const sandboxModeEnabled = schemaHasSandboxModeEnabled(project.schema, docLink); - const directiveMap = collectDirectivesByTypeNames(project.schema); - const hasApiKey = - authConfig.defaultAuthentication.authenticationType === 'API_KEY' || - authConfig.additionalAuthenticationProviders.some((authProvider) => authProvider.authenticationType === 'API_KEY'); - const showSandboxModeMessage = sandboxModeEnabled && hasApiKey; - - await searchablePushChecks(context, directiveMap.types, parameters[ResourceConstants.PARAMETERS.AppSyncApiName]); - - if (sandboxModeEnabled && options.promptApiKeyCreation) { - const apiKeyConfig = await showSandboxModePrompts(context); - if (apiKeyConfig) authConfig.additionalAuthenticationProviders.push(apiKeyConfig); - } - - if (showSandboxModeMessage) { - showGlobalSandboxModeWarning(docLink); - } else { - warnOnAuth(directiveMap.types, docLink); - } - - // construct sanityCheckRules - const ff = new AmplifyCLIFeatureFlagAdapter(); - const isNewAppSyncAPI: boolean = resourcesToBeCreated.some((resource) => resource.service === 'AppSync'); - const allowDestructiveUpdates = context?.input?.options?.[DESTRUCTIVE_UPDATES_FLAG] || context?.input?.options?.force; - const sanityCheckRules = getSanityCheckRules(isNewAppSyncAPI, ff, allowDestructiveUpdates); - let resolverConfig = {}; - if (!_.isEmpty(resources)) { - resolverConfig = await context.amplify.invokePluginMethod( - context, - AmplifyCategories.API, - AmplifySupportedService.APPSYNC, - 'getResolverConfig', - [context, resources[0].resourceName], - ); - } - - /** - * if Auth is not migrated , we need to fetch resolver Config from transformer.conf.json - * since above function will return empty object - */ - if (_.isEmpty(resolverConfig)) { - resolverConfig = project.config.ResolverConfig; - } - - const resourceDirParts = resourceDir.split(path.sep); - const apiName = resourceDirParts[resourceDirParts.length - 1]; - - const userDefinedSlots = { - ...parseUserDefinedSlots(project.pipelineFunctions), - ...parseUserDefinedSlots(project.resolvers), - }; - - const overrideConfig: OverrideConfig = { - applyOverride: (scope: Construct) => applyFileBasedOverride(scope), - ...options.overrideConfig, - }; - - return { - ...options, - resourceName, - buildParameters, - projectDirectory: resourceDir, - transformersFactoryArgs: { - storageConfig, - customTransformers: await loadCustomTransformersV2(resourceDir), - }, - rootStackFileName: 'cloudformation-template.json', - currentCloudBackendDirectory: previouslyDeployedBackendDir, - // Reminder that `project` has type `any`, and is not actually compatible with DataSourceStrategiesProvider. We will correct that later. - projectConfig: project, - lastDeployedProjectConfig, - authConfig, - sandboxModeEnabled, - sanityCheckRules, - resolverConfig, - userDefinedSlots, - overrideConfig, - stacks: project.stacks, - stackMapping: project.config.StackMapping, - transformParameters: generateTransformParameters(apiName, parameters, project.config, sandboxModeEnabled), - }; -}; - -/** - * Generate transform parameters from feature flags and other config sources. - * @param apiName the api name (used for determining current nodeToNodeEncryption value) - * @param parameters invocation params, bag of bits, used for determining suppressApiKeyGeneration state - * @param projectConfig hydrated project config object, with additional metadata, bag of bits, determines if resolver deduping is disabled - * @param sandboxModeEnabled whether or not to enable sandbox mode on the transformed project - * @returns a single set of params to configure the transform behavior. - */ -const generateTransformParameters = ( - apiName: string, - parameters: any, - projectConfig: any, - sandboxModeEnabled: boolean, -): TransformParameters => { - const featureFlagProvider = new AmplifyCLIFeatureFlagAdapter(); - return { - shouldDeepMergeDirectiveConfigDefaults: featureFlagProvider.getBoolean('shouldDeepMergeDirectiveConfigDefaults'), - useSubUsernameForDefaultIdentityClaim: featureFlagProvider.getBoolean('useSubUsernameForDefaultIdentityClaim'), - populateOwnerFieldForStaticGroupAuth: featureFlagProvider.getBoolean('populateOwnerFieldForStaticGroupAuth'), - secondaryKeyAsGSI: featureFlagProvider.getBoolean('secondaryKeyAsGSI'), - enableAutoIndexQueryNames: featureFlagProvider.getBoolean('enableAutoIndexQueryNames'), - respectPrimaryKeyAttributesOnConnectionField: featureFlagProvider.getBoolean('respectPrimaryKeyAttributesOnConnectionField'), - subscriptionsInheritPrimaryAuth: featureFlagProvider.getBoolean('subscriptionsInheritPrimaryAuth'), - suppressApiKeyGeneration: suppressApiKeyGeneration(parameters), - disableResolverDeduping: projectConfig.DisableResolverDeduping ?? false, - enableSearchNodeToNodeEncryption: shouldEnableNodeToNodeEncryption( - apiName, - pathManager.findProjectRoot(), - pathManager.getCurrentCloudBackendDirPath(), - ), - sandboxModeEnabled, - enableTransformerCfnOutputs: true, - allowDestructiveGraphqlSchemaUpdates: false, - replaceTableUponGsiUpdate: false, - allowGen1Patterns: true, - }; -}; - -export const suppressApiKeyGeneration = (parameters: any): boolean => { - if (!('CreateAPIKey' in parameters)) { - return false; - } - return parameters.CreateAPIKey !== 1 && parameters.CreateAPIKey !== '1'; -}; - -/** - * Scan the project config for custom transformers, then attempt to load them from the various node paths which Amplify supports. - * @param resourceDir the directory to search for transformer configuration. - * @returns a list of custom plugins. - */ -export const loadCustomTransformersV2 = async (resourceDir: string): Promise => { - const customTransformersConfig = await loadProject(resourceDir); - const customTransformerList = customTransformersConfig?.config?.transformers; - return (Array.isArray(customTransformerList) ? customTransformerList : []) - .map(importTransformerModule) - .map((imported) => { - const CustomTransformer = imported.default; - - if (typeof CustomTransformer === 'function') { - return new CustomTransformer(); - } - if (typeof CustomTransformer === 'object') { - // Todo: Use a shim to ensure that it adheres to TransformerProvider interface. For now throw error - // return CustomTransformer; - throw new Error("Custom Transformers' should implement TransformerProvider interface"); - } - - throw new Error("Custom Transformers' default export must be a function or an object"); - }) - .filter((customTransformer) => customTransformer); -}; - -const getBucketName = (s3ResourceName: string): { bucketName: string } => { - const amplifyMeta = stateManager.getMeta(); - const stackName = amplifyMeta.providers.awscloudformation.StackName; - const s3ResourcePath = pathManager.getResourceDirectoryPath(undefined, AmplifyCategories.STORAGE, s3ResourceName); - const cliInputsPath = path.join(s3ResourcePath, 'cli-inputs.json'); - let bucketParameters: Record; - // get bucketParameters 1st from cli-inputs , if not present, then parameters.json - if (fs.existsSync(cliInputsPath)) { - bucketParameters = JSONUtilities.readJson(cliInputsPath); - } else { - bucketParameters = stateManager.getResourceParametersJson(undefined, AmplifyCategories.STORAGE, s3ResourceName); - } - const bucketName = stackName.startsWith('amplify-') - ? `${bucketParameters.bucketName}\${hash}-\${env}` - : `${bucketParameters.bucketName}${s3ResourceName}-\${env}`; - return { bucketName }; -}; - -const getPreviousDeploymentRootKey = async (previouslyDeployedBackendDir: string): Promise => { - // this is the function - let parameters; - try { - const parametersPath = path.join(previouslyDeployedBackendDir, `build/${PARAMETERS_FILENAME}`); - const parametersExists = fs.existsSync(parametersPath); - if (parametersExists) { - const parametersString = await fs.readFile(parametersPath); - parameters = JSON.parse(parametersString.toString()); - } - return parameters.S3DeploymentRootKey; - } catch (err) { - return undefined; - } -}; - -const getProjectBucket = (): string => { - const meta: $TSMeta = stateManager.getMeta(undefined, { throwIfNotExist: false }); - const projectBucket = meta?.providers ? meta.providers[PROVIDER_NAME].DeploymentBucketName : ''; - return projectBucket; -}; - -/** - * Check if storage exists in the project if not return undefined - */ -const s3ResourceAlreadyExists = (): string | undefined => { - try { - let resourceName: string; - const amplifyMeta: $TSMeta = stateManager.getMeta(undefined, { throwIfNotExist: false }); - if (amplifyMeta?.[AmplifyCategories.STORAGE]) { - const categoryResources = amplifyMeta[AmplifyCategories.STORAGE]; - Object.keys(categoryResources).forEach((resource) => { - if (categoryResources[resource].service === AmplifySupportedService.S3) { - resourceName = resource; - } - }); - } - return resourceName; - } catch (error) { - if (error.name === 'UndeterminedEnvironmentError') { - return undefined; - } - throw error; - } -}; diff --git a/packages/amplify-category-api/src/graphql-transformer/transformer-version.ts b/packages/amplify-category-api/src/graphql-transformer/transformer-version.ts deleted file mode 100644 index 905b983530..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/transformer-version.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { $TSContext, pathManager, stateManager, FeatureFlags, AmplifyError } from '@aws-amplify/amplify-cli-core'; - -/** - * Shorthand for Feature flag retrieval. - */ -const useExperimentalPipelinedTransformerFF = (): boolean => - FeatureFlags.getBoolean('graphQLTransformer.useExperimentalPipelinedTransformer'); -const transformerVersionFF = (): number => FeatureFlags.getNumber('graphQLTransformer.transformerVersion'); - -/** - * Inspect feature flags for the project and determine if this particular project should be using graphql v2 or v1. - * Coerces feature flags into a sane state if they are out of, and throws error on invalid configuration. - */ -export const getTransformerVersion = async (context): Promise => { - if (useExperimentalPipelinedTransformerFF() === false) { - return 1; - } - - if (isLegacyFeatureFlagConfiguration()) { - await migrateToTransformerVersionFeatureFlag(context); - } - - const transformerVersion = transformerVersionFF(); - if (transformerVersion !== 1 && transformerVersion !== 2) { - throw new AmplifyError('UserInputError', { - message: `Invalid value specified for transformerVersion: '${transformerVersion}'`, - link: 'https://docs.amplify.aws/cli/reference/feature-flags/#transformerVersion', - }); - } - - return transformerVersion; -}; - -/** - * Return whether or not the project is configured with legacy pipelined transformer feature flags, and may need to be updated. - */ -const isLegacyFeatureFlagConfiguration = (): boolean => useExperimentalPipelinedTransformerFF() && transformerVersionFF() === 1; - -/** - * Update project feature flags and alert the user if they have a deprecated set of feature flags. - */ -const migrateToTransformerVersionFeatureFlag = async (context: $TSContext): Promise => { - const projectPath = pathManager.findProjectRoot() ?? process.cwd(); - - const config = stateManager.getCLIJSON(projectPath, undefined, { - throwIfNotExist: false, - preserveComments: true, - }); - - // eslint-disable-next-line spellcheck/spell-checker - config.features.graphqltransformer.transformerversion = 2; - stateManager.setCLIJSON(projectPath, config); - await FeatureFlags.reloadValues(); - // eslint-disable-next-line spellcheck/spell-checker - context.print.warning( - `\nThe project is configured with 'transformerVersion': ${transformerVersionFF()}, but 'useExperimentalPipelinedTransformer': ${useExperimentalPipelinedTransformerFF()}. Setting the 'transformerVersion': ${ - config.features.graphqltransformer.transformerversion - }. 'useExperimentalPipelinedTransformer' is deprecated.`, - ); -}; diff --git a/packages/amplify-category-api/src/graphql-transformer/types/index.ts b/packages/amplify-category-api/src/graphql-transformer/types/index.ts deleted file mode 100644 index 286d3b124e..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/types/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { ConstructResourceMeta, StackMeta } from './types'; -export { stacksTypes, getStackMeta, convertToAppsyncResourceObj } from './utils'; diff --git a/packages/amplify-category-api/src/graphql-transformer/types/types.ts b/packages/amplify-category-api/src/graphql-transformer/types/types.ts deleted file mode 100644 index 6feb531404..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/types/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -export type ConstructResourceMeta = { - rootStack?: StackMeta; - nestedStack?: StackMeta; - resourceName: string; - resourceType: string; -}; - -export type StackMeta = { - stackName: string; - stackType: string; -}; diff --git a/packages/amplify-category-api/src/graphql-transformer/types/utils.ts b/packages/amplify-category-api/src/graphql-transformer/types/utils.ts deleted file mode 100644 index 480ed10729..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/types/utils.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { CfnResource } from 'aws-cdk-lib'; -import { Construct } from 'constructs'; -import _ from 'lodash'; -import { - AmplifyApiGraphQlResourceStackTemplate, - FunctionDirectiveStack, - AppsyncStackCommon, - HttpsDirectiveStack, - OpenSearchDirectiveStack, - ModelDirectiveStack, -} from '../cdk-compat/amplify-api-resource-stack-types'; -import { ConstructResourceMeta } from './types'; - -export const stacksTypes: Record = { - API: 'api', - MODELS: 'models', - HttpStack: 'http', - FunctionDirectiveStack: 'function', - PredictionsDirectiveStack: 'predictions', - SearchableStack: 'openSearch', -}; - -const rootStackNameInConstruct = 'transformer-root-stack'; - -export const getStackMeta = (constructPathArr: string[], id: string, nestedStackArr: string[], node: Construct): ConstructResourceMeta => { - const resource = node as CfnResource; - if (nestedStackArr.find((val) => val === constructPathArr[1])) { - const nestedStackName = nestedStackArr.find((val) => val === constructPathArr[1]); - const resourceName = constructPathArr.filter((path) => path !== nestedStackName && path !== rootStackNameInConstruct).join(''); - return { - resourceName, - resourceType: resource.cfnResourceType, - nestedStack: { - stackName: nestedStackName!, - stackType: stacksTypes[nestedStackName!] ?? stacksTypes['MODELS'], - }, - }; - } else { - // root stack - const resourceName = constructPathArr.filter((path) => path !== rootStackNameInConstruct).join(''); - return { - resourceName: id === 'Resource' ? resourceName : `${resourceName}${id}`, - resourceType: resource.cfnResourceType, - rootStack: { - stackName: constructPathArr[0], - stackType: stacksTypes.API, - }, - }; - } -}; - -export const convertToAppsyncResourceObj = (amplifyObj: any) => { - let appsyncResourceObject: AmplifyApiGraphQlResourceStackTemplate = {}; - Object.keys(amplifyObj).forEach((keys) => { - if (keys === 'api') { - appsyncResourceObject.api = amplifyObj.api; - } else if (keys === 'models' && !_.isEmpty(amplifyObj[keys])) { - // require filter using keyName - appsyncResourceObject.models = {}; - Object.keys(amplifyObj.models).forEach((key) => { - appsyncResourceObject.models![key] = generateModelDirectiveObject(amplifyObj.models[key]); - }); - } else if (keys === 'function' && !_.isEmpty(amplifyObj[keys])) { - const functionStackObj = amplifyObj.function.FunctionDirectiveStack; - appsyncResourceObject.function = generateFunctionDirectiveObject(functionStackObj); - } else if (keys === 'http' && !_.isEmpty(amplifyObj[keys])) { - const httpStackObj = amplifyObj.http.HttpStack; - appsyncResourceObject.http = generateHttpDirectiveObject(httpStackObj); - } else if (keys === 'openSearch' && !_.isEmpty(amplifyObj[keys])) { - const openSearchStackObj = amplifyObj.openSearch.SearchableStack; - appsyncResourceObject.opensearch = generateOpenSearchDirectiveObject(openSearchStackObj); - } else if (keys === 'predictions' && !_.isEmpty(amplifyObj[keys])) { - appsyncResourceObject.predictions = amplifyObj.predictions.PredictionsDirectiveStack; - if (!_.isEmpty(amplifyObj.predictions.PredictionsDirectiveStack['predictionsLambda.handler'])) { - appsyncResourceObject.predictions!.predictionsLambdaFunction = - amplifyObj.predictions.PredictionsDirectiveStack['predictionsLambda.handler']; - } - } - }); - return appsyncResourceObject; -}; - -const generateFunctionDirectiveObject = (functionStackObj: any) => { - let functionObj: Partial = {}; - Object.keys(functionStackObj).forEach((key) => { - if (key.endsWith('resolvers')) { - functionObj.resolvers = functionStackObj.resolvers; - } else if (key.endsWith('appsyncFunctions')) { - functionObj.appsyncFunctions = functionStackObj.appsyncFunctions; - } else if (functionStackObj[key].cfnResourceType.includes('DataSource')) { - if (!functionObj.lambdaDataSource) { - functionObj.lambdaDataSource = {}; - } - const name = key.substring(0, key.indexOf('LambdaDataSource')); - functionObj.lambdaDataSource[name] = functionStackObj[key]; - } else if (functionStackObj[key].cfnResourceType.includes('Role')) { - if (!functionObj.lambdaDataSourceRole) { - functionObj.lambdaDataSourceRole = {}; - } - const name = key.substring(0, key.indexOf('LambdaDataSourceServiceRole')); - functionObj.lambdaDataSourceRole[name] = functionStackObj[key]; - } else if (functionStackObj[key].cfnResourceType.includes('Policy')) { - if (!functionObj.lambdaDataSourceServiceRoleDefaultPolicy) { - functionObj.lambdaDataSourceServiceRoleDefaultPolicy = {}; - } - const name = key.substring(0, key.indexOf('LambdaDataSourceServiceRoleDefaultPolicy')); - functionObj.lambdaDataSourceServiceRoleDefaultPolicy[name] = functionStackObj[key]; - } - }); - return functionObj; -}; - -const generateHttpDirectiveObject = (httpStackObj: any) => { - let httpObj: Partial = {}; - Object.keys(httpStackObj).forEach((key) => { - if (key.endsWith('resolvers')) { - httpObj.resolvers = httpStackObj.resolvers; - } else if (key.endsWith('appsyncFunctions')) { - httpObj.appsyncFunctions = httpStackObj.appsyncFunctions; - } else if (httpStackObj[key].cfnResourceType.includes('DataSource')) { - if (!httpObj.httpsDataSource) { - httpObj.httpsDataSource = {}; - } - const name = key.substring(0, key.indexOf('DataSource')); - httpObj.httpsDataSource[name] = httpStackObj[key]; - } else if (httpStackObj[key].cfnResourceType.includes('Role')) { - if (!httpObj.httpDataSourceServiceRole) { - httpObj.httpDataSourceServiceRole = {}; - } - const name = key.substring(0, key.indexOf('DataSourceServiceRole')); - httpObj.httpDataSourceServiceRole[name] = httpStackObj[key]; - } - }); - return httpObj; -}; - -const generateOpenSearchDirectiveObject = (opensearchStackObj: any) => { - let opensearchObj: OpenSearchDirectiveStack & AppsyncStackCommon = _.pick( - opensearchStackObj, - 'OpenSearchDataSource', - 'OpenSearchAccessIAMRole', - 'OpenSearchAccessIAMRoleDefaultPolicy', - 'OpenSearchDomain', - 'OpenSearchStreamingLambdaIAMRole', - 'OpenSearchStreamingLambdaIAMRoleDefaultPolicy', - 'CloudwatchLogsAccess', - 'OpenSearchStreamingLambdaFunction', - 'resolvers', - 'appsyncFunctions', - ); - - Object.keys(opensearchStackObj).forEach((key) => { - if (key !== 'resolvers' && key !== 'appsyncFunctions' && opensearchStackObj[key].cfnResourceType.includes('EventSourceMapping')) { - if (!opensearchObj.OpenSearchModelLambdaMapping) { - opensearchObj.OpenSearchModelLambdaMapping = {}; - } - // filter ModelName fromm logicalID - const name = key.substring(0, key.indexOf('LambdaMapping')); - const modeName = key.substring('Searchable'.length, name.length); - opensearchObj.OpenSearchModelLambdaMapping[modeName] = opensearchStackObj[key]; - } - }); - return opensearchObj; -}; - -const generateModelDirectiveObject = (modelStackObj: any) => { - let modelObj: ModelDirectiveStack = _.pick(modelStackObj, 'appsyncFunctions', 'DynamoDBAccess', 'InvokdeLambdaFunction', 'resolvers'); - let strippedModelObj = _.omit(modelStackObj, 'appsyncFunctions', 'DynamoDBAccess', 'InvokdeLambdaFunction', 'resolvers'); - Object.keys(strippedModelObj).forEach((key) => { - if (strippedModelObj[key].cfnResourceType.includes('DataSource')) { - modelObj.modelDatasource = modelStackObj[key]; - } - if (strippedModelObj[key].cfnResourceType.includes('Role')) { - modelObj.modelIamRole = modelStackObj[key]; - } - if (strippedModelObj[key].cfnResourceType.includes('Policy')) { - modelObj.modelIamRoleDefaultPolicy = modelStackObj[key]; - } - if (strippedModelObj[key].cfnResourceType.includes('Table')) { - modelObj.modelDDBTable = modelStackObj[key]; - } - }); - return modelObj; -}; diff --git a/packages/amplify-category-api/src/graphql-transformer/user-defined-slots.ts b/packages/amplify-category-api/src/graphql-transformer/user-defined-slots.ts deleted file mode 100644 index 4d55860888..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/user-defined-slots.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { UserDefinedSlot, UserDefinedResolver } from '@aws-amplify/graphql-transformer-core'; -import _ from 'lodash'; - -export const SLOT_NAMES = new Set([ - 'init', - 'preAuth', - 'auth', - 'postAuth', - 'preDataLoad', - 'preUpdate', - 'preSubscribe', - 'postDataLoad', - 'postUpdate', - 'finish', -]); - -const EXCLUDE_FILES = new Set(['README.md']); - -export function parseUserDefinedSlots(userDefinedTemplates: Record): Record { - type ResolverKey = string; - type ResolverOrder = number; - const groupedResolversMap: Record> = {}; - - Object.entries(userDefinedTemplates) - // filter out non-resolver files - .filter(([fileName]) => !EXCLUDE_FILES.has(fileName)) - .forEach(([fileName, template]) => { - const slicedSlotName = fileName.split('.'); - const isSlot = SLOT_NAMES.has(slicedSlotName[2]); - - if (!isSlot) { - return; - } - const resolverType = slicedSlotName[slicedSlotName.length - 2] === 'res' ? 'responseResolver' : 'requestResolver'; - const resolverName = [slicedSlotName[0], slicedSlotName[1]].join('.'); - const slotName = slicedSlotName[2]; - const resolverOrder = `order${Number(slicedSlotName[3]) || 0}`; - const resolver: UserDefinedResolver = { - fileName, - template, - }; - // because a slot can have a request and response resolver, we need to group corresponding request and response resolvers - if (_.has(groupedResolversMap, [`${resolverName}#${slotName}`, resolverOrder])) { - _.set(groupedResolversMap, [`${resolverName}#${slotName}`, resolverOrder, resolverType], resolver); - } else { - const slot = { - resolverTypeName: slicedSlotName[0], - resolverFieldName: slicedSlotName[1], - slotName, - [resolverType]: resolver, - }; - _.set(groupedResolversMap, [`${resolverName}#${slotName}`, resolverOrder], slot); - } - }); - - return Object.entries(groupedResolversMap) - .map(([resolverNameKey, numberedSlots]) => ({ - orderedSlots: Object.entries(numberedSlots) - .sort(([i], [j]) => i.localeCompare(j)) - .map(([_, slot]) => slot), - resolverName: resolverNameKey.split('#')[0], - })) - .reduce((acc, { orderedSlots, resolverName }) => { - if (acc[resolverName]) { - acc[resolverName].push(...orderedSlots); - } else { - acc[resolverName] = orderedSlots; - } - return acc; - }, {} as Record); -} diff --git a/packages/amplify-category-api/src/graphql-transformer/utils.ts b/packages/amplify-category-api/src/graphql-transformer/utils.ts deleted file mode 100644 index 55cd9aada6..0000000000 --- a/packages/amplify-category-api/src/graphql-transformer/utils.ts +++ /dev/null @@ -1,334 +0,0 @@ -import * as path from 'path'; -import fs from 'fs-extra'; -import rimraf from 'rimraf'; -import { - $TSContext, - AmplifyCategories, - CloudformationProviderFacade, - JSONUtilities, - pathManager, - stateManager, -} from '@aws-amplify/amplify-cli-core'; -import { CloudFormation, Fn } from 'cloudform-types'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { pullAllBy, find } from 'lodash'; -import { printer } from '@aws-amplify/amplify-prompts'; -import { DeploymentResources } from './cdk-compat/deployment-resources'; -import { TransformerProjectConfig } from './cdk-compat/project-config'; - -const PARAMETERS_FILE_NAME = 'parameters.json'; -const CUSTOM_ROLES_FILE_NAME = 'custom-roles.json'; -const AMPLIFY_ADMIN_ROLE = '_Full-access/CognitoIdentityCredentials'; -const AMPLIFY_MANAGE_ROLE = '_Manage-only/CognitoIdentityCredentials'; -const PROVIDER_NAME = 'awscloudformation'; - -interface CustomRolesConfig { - adminRoleNames?: Array | string; -} - -export const getIdentityPoolId = async (ctx: $TSContext): Promise => { - const { allResources, resourcesToBeDeleted } = await ctx.amplify.getResourceStatus('auth'); - const authResources = pullAllBy(allResources, resourcesToBeDeleted, 'resourceName'); - const authResource = find(authResources, { service: 'Cognito', providerPlugin: PROVIDER_NAME }) as any; - return authResource?.output?.IdentityPoolId; -}; - -export const getAdminRoles = async (ctx: $TSContext, apiResourceName: string | undefined): Promise> => { - let currentEnv; - const adminRoles = new Array(); - - try { - currentEnv = ctx.amplify.getEnvInfo().envName; - } catch (err) { - // When there is no environment info, return [] - This is required for sandbox pull - return []; - } - - // admin ui roles - try { - const amplifyMeta = stateManager.getMeta(); - const appId = amplifyMeta?.providers?.[PROVIDER_NAME]?.AmplifyAppId; - const res = await CloudformationProviderFacade.isAmplifyAdminApp(ctx, appId); - if (res.userPoolID) { - adminRoles.push(`${res.userPoolID}${AMPLIFY_ADMIN_ROLE}`, `${res.userPoolID}${AMPLIFY_MANAGE_ROLE}`); - } - } catch (err) { - // no need to error if not admin ui app - } - - // additonal admin role checks - if (apiResourceName) { - // lambda functions which have access to the api - const { allResources, resourcesToBeDeleted } = await ctx.amplify.getResourceStatus('function'); - const resources = pullAllBy(allResources, resourcesToBeDeleted, 'resourceName') - .filter((r: any) => r.dependsOn?.some((d: any) => d?.resourceName === apiResourceName)) - .map((r: any) => `${r.resourceName}-${currentEnv}`); - adminRoles.push(...resources); - - // check for custom iam admin roles - const customRoleFile = path.join( - pathManager.getResourceDirectoryPath(undefined, AmplifyCategories.API, apiResourceName), - CUSTOM_ROLES_FILE_NAME, - ); - if (fs.existsSync(customRoleFile)) { - const customRoleConfig = JSONUtilities.readJson(customRoleFile); - if (customRoleConfig && customRoleConfig.adminRoleNames) { - const customAdminRoles = Array.isArray(customRoleConfig.adminRoleNames) - ? customRoleConfig.adminRoleNames - : [customRoleConfig.adminRoleNames]; - const adminRoleNames = customAdminRoles - // eslint-disable-next-line no-template-curly-in-string - .map((r) => (r.includes('${env}') ? r.replace('${env}', currentEnv) : r)); - adminRoles.push(...adminRoleNames); - } - } - } - return adminRoles; -}; - -export function mergeUserConfigWithTransformOutput( - userConfig: TransformerProjectConfig, - transformOutput: DeploymentResources, - opts?: any, -): DeploymentResources { - const userFunctions = userConfig.functions || {}; - const userResolvers = userConfig.resolvers || {}; - const userPipelineFunctions = userConfig.pipelineFunctions || {}; - const { functions } = transformOutput; - const { resolvers } = transformOutput; - const { pipelineFunctions } = transformOutput; - - if (!opts?.disableFunctionOverrides) { - for (const userFunction of Object.keys(userFunctions)) { - functions[userFunction] = userFunctions[userFunction]; - } - } - - if (!opts?.disablePipelineFunctionOverrides) { - const pipelineFunctionKeys = Object.keys(userPipelineFunctions); - - if (pipelineFunctionKeys.length > 0) { - printer.warn( - ' You are using the "pipelineFunctions" directory for overridden and custom resolvers. ' + - 'Please use the "resolvers" directory as "pipelineFunctions" will be deprecated.\n', - ); - } - - for (const userPipelineFunction of pipelineFunctionKeys) resolvers[userPipelineFunction] = userPipelineFunctions[userPipelineFunction]; - } - - if (!opts?.disableResolverOverrides) { - for (const userResolver of Object.keys(userResolvers)) { - if (userResolver !== 'README.md') { - resolvers[userResolver] = userResolvers[userResolver].toString(); - } - } - } - - const stacks = overrideUserDefinedStacks(userConfig, transformOutput); - - return { - ...transformOutput, - functions, - resolvers, - pipelineFunctions, - stacks, - }; -} - -function overrideUserDefinedStacks(userConfig: TransformerProjectConfig, transformOutput: DeploymentResources) { - const userStacks = userConfig.stacks || {}; - const { stacks, rootStack } = transformOutput; - - const resourceTypesToDependOn = { - 'AWS::CloudFormation::Stack': true, - 'AWS::AppSync::GraphQLApi': true, - 'AWS::AppSync::GraphQLSchema': true, - }; - - const allResourceIds = Object.keys(rootStack.Resources).filter((k: string) => { - const resource = rootStack.Resources[k]; - return resourceTypesToDependOn[resource.Type]; - }); - - const parametersKeys = Object.keys(rootStack.Parameters); - const customStackParams = parametersKeys.reduce( - (acc: any, k: string) => ({ - ...acc, - [k]: Fn.Ref(k), - }), - {}, - ); - - customStackParams[ResourceConstants.PARAMETERS.AppSyncApiId] = Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'); - - const updatedParameters = rootStack.Parameters; - - for (const userStack of Object.keys(userStacks)) { - if (stacks[userStack]) { - throw new Error(`You cannot provide a stack named ${userStack} as it \ - will be overwritten by a stack generated by the GraphQL Transform.`); - } - const userDefinedStack = userStacks[userStack]; - - for (const key of Object.keys(userDefinedStack.Parameters)) { - if (customStackParams[key] == null) { - customStackParams[key] = Fn.Ref(key); - - if (updatedParameters[key]) throw new Error(`Cannot redefine CloudFormation parameter ${key} in stack ${userStack}.`); - else updatedParameters[key] = userDefinedStack.Parameters[key]; - } - } - - const parametersForStack = Object.keys(userDefinedStack.Parameters).reduce( - (acc, k) => ({ - ...acc, - [k]: customStackParams[k], - }), - {}, - ); - - stacks[userStack] = userDefinedStack; - - const stackResourceId = userStack.split(/[^A-Za-z]/).join(''); - const customNestedStack = new CloudFormation.Stack({ - Parameters: parametersForStack, - TemplateURL: Fn.Join('/', [ - 'https://s3.amazonaws.com', - Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentBucket), - Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentRootKey), - 'stacks', - userStack, - ]), - }).dependsOn(allResourceIds); - rootStack.Resources[stackResourceId] = customNestedStack; - } - - rootStack.Parameters = updatedParameters; - - return stacks; -} - -/** - * Writes a deployment to disk at a path. - */ -export async function writeDeploymentToDisk( - context: $TSContext, - deployment: DeploymentResources, - directory: string, - rootStackFileName = 'rootStack.json', - buildParameters: Object, -) { - fs.ensureDirSync(directory); - // Delete the last deployments resources except for tsconfig if present - emptyBuildDirPreserveTsconfig(directory); - - // Write the schema to disk - const { schema } = deployment; - const fullSchemaPath = path.normalize(`${directory}/schema.graphql`); - fs.writeFileSync(fullSchemaPath, schema); - - // Setup the directories if they do not exist. - initStacksAndResolversDirectories(directory); - - // Write resolvers to disk - const resolverFileNames = Object.keys(deployment.resolvers); - const resolverRootPath = resolverDirectoryPath(directory); - for (const resolverFileName of resolverFileNames) { - const fullResolverPath = path.normalize(`${resolverRootPath}/${resolverFileName}`); - fs.writeFileSync(fullResolverPath, deployment.resolvers[resolverFileName]); - } - - // Write pipeline resolvers to disk - const pipelineFunctions = Object.keys(deployment.pipelineFunctions); - const pipelineFunctionRootPath = pipelineFunctionDirectoryPath(directory); - for (const functionFileName of pipelineFunctions) { - const fullTemplatePath = path.normalize(`${pipelineFunctionRootPath}/${functionFileName}`); - fs.writeFileSync(fullTemplatePath, deployment.pipelineFunctions[functionFileName]); - } - - // Write the stacks to disk - const stackNames = Object.keys(deployment.stacks); - const stackRootPath = stacksDirectoryPath(directory); - for (const stackFileName of stackNames) { - const fileNameParts = stackFileName.split('.'); - if (fileNameParts.length === 1) { - fileNameParts.push('json'); - } - const fullFileName = fileNameParts.join('.'); - throwIfNotJSONExt(fullFileName); - const fullStackPath = path.normalize(`${stackRootPath}/${fullFileName}`); - let stackContent = deployment.stacks[stackFileName]; - if (typeof stackContent === 'string') { - stackContent = JSON.parse(stackContent); - } - await CloudformationProviderFacade.prePushCfnTemplateModifier(context, stackContent); - fs.writeFileSync(fullStackPath, JSONUtilities.stringify(stackContent)); - } - - // Write any functions to disk - const functionNames = Object.keys(deployment.functions); - const functionRootPath = path.normalize(`${directory}/functions`); - if (!fs.existsSync(functionRootPath)) { - fs.mkdirSync(functionRootPath); - } - for (const functionName of functionNames) { - const fullFunctionPath = path.normalize(`${functionRootPath}/${functionName}`); - const zipContents = fs.readFileSync(deployment.functions[functionName]); - fs.writeFileSync(fullFunctionPath, zipContents); - } - const { rootStack } = deployment; - const rootStackPath = path.normalize(`${directory}/${rootStackFileName}`); - const rootStackString = JSON.stringify(rootStack, null, 4); - fs.writeFileSync(rootStackPath, rootStackString); - - // Write params to disk - const jsonString = JSON.stringify(buildParameters, null, 4); - const parametersOutputFilePath = path.join(directory, PARAMETERS_FILE_NAME); - fs.writeFileSync(parametersOutputFilePath, jsonString); -} - -function initStacksAndResolversDirectories(directory: string) { - const resolverRootPath = resolverDirectoryPath(directory); - if (!fs.existsSync(resolverRootPath)) { - fs.mkdirSync(resolverRootPath); - } - const stackRootPath = stacksDirectoryPath(directory); - if (!fs.existsSync(stackRootPath)) { - fs.mkdirSync(stackRootPath); - } -} - -function pipelineFunctionDirectoryPath(rootPath: string) { - return path.normalize(path.join(rootPath, 'pipelineFunctions')); -} - -function resolverDirectoryPath(rootPath: string) { - return path.normalize(`${rootPath}/resolvers`); -} - -function stacksDirectoryPath(rootPath: string) { - return path.normalize(`${rootPath}/stacks`); -} - -function throwIfNotJSONExt(stackFile: string) { - const extension = path.extname(stackFile); - if (extension === '.yaml' || extension === '.yml') { - throw new Error(`Yaml is not yet supported. Please convert the CloudFormation stack ${stackFile} to json.`); - } - if (extension !== '.json') { - throw new Error(`Invalid extension ${extension} for stack ${stackFile}`); - } -} - -const emptyBuildDirPreserveTsconfig = (directory: string) => { - const files = fs.readdirSync(directory); - files.forEach((file) => { - const fileDir = path.join(directory, file); - if (fs.lstatSync(fileDir).isDirectory()) { - rimraf.sync(fileDir); - } else if (!file.endsWith('tsconfig.resource.json')) { - fs.unlinkSync(fileDir); - } - }); -}; diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts deleted file mode 100644 index c019e972a8..0000000000 --- a/packages/amplify-category-api/src/index.ts +++ /dev/null @@ -1,406 +0,0 @@ -import * as path from 'path'; -import { - $TSContext, - AmplifyCategories, - AmplifyError, - AmplifySupportedService, - buildOverrideDir, - pathManager, - stateManager, -} from '@aws-amplify/amplify-cli-core'; -import { ensureEnvParamManager } from '@aws-amplify/amplify-environment-parameters'; -import { printer } from '@aws-amplify/amplify-prompts'; -import { validateAddApiRequest, validateUpdateApiRequest } from 'amplify-util-headless-input'; -import * as fs from 'fs-extra'; -import { SQL_SCHEMA_FILE_NAME, ImportedRDSType } from '@aws-amplify/graphql-transformer-core'; -import _ from 'lodash'; -import { run } from './commands/api/console'; -import { - getAppSyncAuthConfig, - getAppSyncResourceName, - getAPIResourceDir, -} from './provider-utils/awscloudformation/utils/amplify-meta-utils'; -import { provider } from './provider-utils/awscloudformation/aws-constants'; -import { ApigwStackTransform } from './provider-utils/awscloudformation/cdk-stack-builder'; -import { getCfnApiArtifactHandler } from './provider-utils/awscloudformation/cfn-api-artifact-handler'; -import { askAuthQuestions } from './provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough'; -import { authConfigToAppSyncAuthType } from './provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; -import { checkAppsyncApiResourceMigration } from './provider-utils/awscloudformation/utils/check-appsync-api-migration'; -import { getAppSyncApiResourceName } from './provider-utils/awscloudformation/utils/getAppSyncApiName'; -import { configureMultiEnvDBSecrets } from './provider-utils/awscloudformation/utils/rds-resources/multi-env-database-secrets'; -import { - deleteConnectionSecrets, - getSecretsKey, - getDatabaseName, - removeVpcSchemaInspectorLambda, -} from './provider-utils/awscloudformation/utils/rds-resources/database-resources'; -import { AmplifyGraphQLTransformerErrorConverter } from './errors/amplify-error-converter'; - -export { NETWORK_STACK_LOGICAL_ID } from './category-constants'; -export { addAdminQueriesApi, updateAdminQueriesApi } from './provider-utils/awscloudformation'; -export { DEPLOYMENT_MECHANISM } from './provider-utils/awscloudformation/base-api-stack'; -// eslint-disable-next-line spellcheck/spell-checker -export { convertDeperecatedRestApiPaths } from './provider-utils/awscloudformation/convert-deprecated-apigw-paths'; -export { getContainers } from './provider-utils/awscloudformation/docker-compose'; -export { EcsAlbStack } from './provider-utils/awscloudformation/ecs-alb-stack'; -export { EcsStack } from './provider-utils/awscloudformation/ecs-apigw-stack'; -export { promptToAddApiKey } from './provider-utils/awscloudformation/prompt-to-add-api-key'; -export { - ApiResource, - generateContainersArtifacts, - processDockerConfig, -} from './provider-utils/awscloudformation/utils/containers-artifacts'; -export { getAuthConfig } from './provider-utils/awscloudformation/utils/get-appsync-auth-config'; -export { getResolverConfig } from './provider-utils/awscloudformation/utils/get-appsync-resolver-config'; -export { getGitHubOwnerRepoFromPath } from './provider-utils/awscloudformation/utils/github'; -export * from './graphql-transformer'; -export * from './force-updates'; -export { showApiAuthAcm } from './category-utils/show-auth-acm'; -export { isDataStoreEnabled } from './category-utils/is-datastore-enabled'; - -const category = AmplifyCategories.API; - -/** - * Open the AppSync/API Gateway AWS console - */ -export const console = async (context: $TSContext): Promise => { - await run(context); -}; - -/** - * Migrate from original API config - */ -export const migrate = async (context: $TSContext, serviceName?: string): Promise => { - const { projectPath } = context?.migrationInfo ?? { projectPath: pathManager.findProjectRoot() }; - const amplifyMeta = stateManager.getMeta(projectPath); - const migrateResourcePromises = []; - for (const categoryName of Object.keys(amplifyMeta)) { - if (categoryName !== category) { - // eslint-disable-next-line no-continue - continue; - } - for (const resourceName of Object.keys(amplifyMeta[category])) { - try { - if (amplifyMeta[category][resourceName].providerPlugin) { - const providerController = await import( - path.join(__dirname, 'provider-utils', amplifyMeta[category][resourceName].providerPlugin, 'index') - ); - // eslint-disable-next-line max-depth - if (!providerController) { - // eslint-disable-next-line no-continue - continue; - } - // eslint-disable-next-line max-depth - if (!serviceName || serviceName === amplifyMeta[category][resourceName].service) { - migrateResourcePromises.push( - providerController.migrateResource(context, projectPath, amplifyMeta[category][resourceName].service, resourceName), - ); - } - } else { - printer.error(`Provider not configured for ${category}: ${resourceName}`); - } - } catch (e) { - printer.warn(`Could not run migration for ${category}: ${resourceName}`); - throw e; - } - } - } - for (const migrateResourcePromise of migrateResourcePromises) { - await migrateResourcePromise; - } -}; - -/** - * Setup new environment with rds datasource - */ -export const initEnv = async (context: $TSContext): Promise => { - const datasource = 'Aurora Serverless'; - const service = 'service'; - const rdsInit = 'rdsInit'; - - const { amplify } = context; - const { envName } = amplify.getEnvInfo(); - - /** - * Check if we need to do the walkthrough, by looking to see if previous environments have - * configured an RDS datasource - */ - const backendConfigFilePath = pathManager.getBackendConfigFilePath(); - - // If this is a mobile hub migrated project without locally added resources then there is no - // backend config exists yet. - if (!fs.existsSync(backendConfigFilePath)) { - return; - } - - const backendConfig = stateManager.getBackendConfig(); - - if (!backendConfig[category]) { - return; - } - - let resourceName; - const apis = Object.keys(backendConfig[category]); - for (const api of apis) { - if (backendConfig[category][api][service] === AmplifySupportedService.APPSYNC) { - resourceName = api; - break; - } - } - - // If an AppSync API does not exist, no need to prompt for rds datasource - if (!resourceName) { - return; - } - - // proceed if there are any existing imported Relational Data Sources - const apiResourceDir = getAPIResourceDir(resourceName); - const pathToSchemaFile = path.join(apiResourceDir, SQL_SCHEMA_FILE_NAME); - if (fs.existsSync(pathToSchemaFile)) { - // read and validate the RDS connection parameters - const secretsKey = await getSecretsKey(); - - const envInfo = { - isNewEnv: context.exeInfo?.isNewEnv, - sourceEnv: context.exeInfo?.sourceEnvName, - yesFlagSet: _.get(context, ['parameters', 'options', 'yes'], false), - envName: envName, - }; - await configureMultiEnvDBSecrets(context, secretsKey, resourceName, envInfo); - } - - // If an AppSync API has not been initialized with RDS, no need to prompt - if (!backendConfig[category][resourceName][rdsInit]) { - return; - } - - const providerController = await import(path.join(__dirname, 'provider-utils', provider, 'index')); - - if (!providerController) { - printer.error('Provider not configured for this category'); - return; - } - - /** - * Check environment parameter manager to ensure it hasn't already been created for current env - */ - const envParamManager = (await ensureEnvParamManager()).instance; - if ( - envParamManager.hasResourceParamManager(category, resourceName) && - envParamManager.getResourceParamManager(category, resourceName).getParam('rdsRegion') - ) { - return; - } - // execute the walkthrough - await providerController - .addDatasource(context, category, datasource) - .then((answers) => { - /** - * Update environment parameter manager with answers - */ - envParamManager.getResourceParamManager(category, resourceName).setParams({ - rdsRegion: answers.region, - rdsClusterIdentifier: answers.dbClusterArn, - rdsSecretStoreArn: answers.secretStoreArn, - rdsDatabaseName: answers.databaseName, - }); - }) - .then(async () => { - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); - }); -}; - -/** - * Get permissions for depending on this resource - */ -export const getPermissionPolicies = async ( - context: $TSContext, - resourceOpsMapping: Record, -): Promise<{ permissionPolicies: any[]; resourceAttributes: any[] }> => { - const amplifyMeta = stateManager.getMeta(); - const permissionPolicies = []; - const resourceAttributes = []; - - await Promise.all( - Object.keys(resourceOpsMapping).map(async (resourceName) => { - try { - const providerName = amplifyMeta[category][resourceName].providerPlugin; - if (providerName) { - const providerController = await import(path.join(__dirname, 'provider-utils', providerName, 'index')); - const { policy, attributes } = await providerController.getPermissionPolicies( - context, - amplifyMeta[category][resourceName].service, - resourceName, - resourceOpsMapping[resourceName], - ); - permissionPolicies.push(policy); - resourceAttributes.push({ resourceName, attributes, category }); - } else { - printer.error(`Provider not configured for ${category}: ${resourceName}`); - } - } catch (e) { - printer.warn(`Could not get policies for ${category}: ${resourceName}`); - throw e; - } - }), - ); - return { permissionPolicies, resourceAttributes }; -}; - -/** - * Main entry point for executing an api subcommand - */ -export const executeAmplifyCommand = async (context: $TSContext): Promise => { - let commandPath = path.normalize(path.join(__dirname, 'commands')); - if (context.input.command === 'help') { - commandPath = path.join(commandPath, category); - } else { - commandPath = path.join(commandPath, category, context.input.command); - } - - // TODO: This is a temporary suppression for CDK deprecation warnings, which should be removed after the migration is complete - // Most of these warning messages are targetting searchable directive, which needs to migrate from elastic search to open search - // This is not diabled in debug mode - disableCDKDeprecationWarning(); - - const commandModule = await import(commandPath); - try { - await commandModule.run(context); - } catch (error) { - if (error) { - printer.error(error.message || error); - if (error.stack) { - printer.debug(error.stack); - } - await context.usageData.emitError(error); - } - process.exitCode = 1; - } -}; - -/** - * Main entry point for executing a headless api command - */ -export const executeAmplifyHeadlessCommand = async (context: $TSContext, headlessPayload: string): Promise => { - context.usageData.pushHeadlessFlow(headlessPayload, context.input); - switch (context.input.command) { - case 'add': - await getCfnApiArtifactHandler(context).createArtifacts(await validateAddApiRequest(headlessPayload)); - break; - case 'update': { - const resourceName = await getAppSyncApiResourceName(context); - await checkAppsyncApiResourceMigration(context, resourceName, true); - await getCfnApiArtifactHandler(context).updateArtifacts(await validateUpdateApiRequest(headlessPayload)); - break; - } - default: - printer.error(`Headless mode for ${context.input.command} api is not implemented yet`); - } -}; - -/** - * Handle state changes in Amplify app. - */ -export const handleAmplifyEvent = async (context: $TSContext, args: any): Promise => { - switch (args.event) { - case 'InternalOnlyPostEnvRemove': { - const meta = stateManager.getMeta(); - const apiName = getAppSyncResourceName(meta); - if (!apiName) { - return; - } - await deleteConnectionSecrets(context, apiName, args?.data?.envName); - await removeVpcSchemaInspectorLambda(context); - break; - } - default: - // other event handlers not implemented - } -}; - -/** - * Add a new auth mode to the API - */ -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -export const addGraphQLAuthorizationMode = async (context: $TSContext, args: Record) => { - const { authType, printLeadText, authSettings } = args; - const meta = stateManager.getMeta(); - const apiName = getAppSyncResourceName(meta); - if (!apiName) { - return undefined; - } - - const authConfig = getAppSyncAuthConfig(meta); - const addAuthConfig = await askAuthQuestions(authType, context, printLeadText, authSettings); - authConfig.additionalAuthenticationProviders.push(addAuthConfig); - await context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'output', { authConfig }); - await context.amplify.updateBackendConfigAfterResourceUpdate(category, apiName, 'output', { authConfig }); - - await getCfnApiArtifactHandler(context).updateArtifacts( - { - version: 1, - serviceModification: { - serviceName: 'AppSync', - additionalAuthTypes: authConfig.additionalAuthenticationProviders.map(authConfigToAppSyncAuthType), - }, - }, - { - skipCompile: false, - }, - ); - - return addAuthConfig; -}; - -/** - * Synthesize the CFN template for the API - */ -export const transformCategoryStack = async (context: $TSContext, resource: Record): Promise => { - if (resource.service === AmplifySupportedService.APPSYNC) { - if (canResourceBeTransformed(resource.resourceName)) { - const backendDir = pathManager.getBackendDirPath(); - const overrideDir = path.join(backendDir, resource.category, resource.resourceName); - const isBuild = await buildOverrideDir(backendDir, overrideDir).catch((error) => { - throw new AmplifyError('InvalidOverrideError', { - message: error.message, - link: 'https://docs.amplify.aws/cli/graphql/override/', - }); - }); - try { - await context.amplify.invokePluginMethod(context, 'awscloudformation', undefined, 'compileSchema', [ - context, - { - forceCompile: true, - overrideConfig: { - overrideFlag: isBuild, - overrideDir, - resourceName: resource.resourceName, - }, - }, - ]); - } catch (error) { - throw AmplifyGraphQLTransformerErrorConverter.convert(error); - } - } - } else if (resource.service === AmplifySupportedService.APIGW) { - if (canResourceBeTransformed(resource.resourceName)) { - // Rebuild CFN - const apigwStack = new ApigwStackTransform(context, resource.resourceName); - await apigwStack.transform(); - } - } -}; - -const canResourceBeTransformed = (resourceName: string): boolean => - stateManager.resourceInputsJsonExists(undefined, AmplifyCategories.API, resourceName); - -/** - * Disable the CDK deprecation warning in production but not in CI/debug mode - */ -const disableCDKDeprecationWarning = () => { - const isDebug = process.argv.includes('--debug') || process.env.AMPLIFY_ENABLE_DEBUG_OUTPUT === 'true'; - if (!isDebug) { - process.env.JSII_DEPRECATED = 'quiet'; - } -}; -// No-op change to trigger publish diff --git a/packages/amplify-category-api/src/provider-utils/api-artifact-handler.ts b/packages/amplify-category-api/src/provider-utils/api-artifact-handler.ts deleted file mode 100644 index 7dbab41d77..0000000000 --- a/packages/amplify-category-api/src/provider-utils/api-artifact-handler.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { AddApiRequest, UpdateApiRequest } from 'amplify-headless-interface'; - -export interface ApiArtifactHandlerOptions { - skipCompile?: boolean; -} - -export interface ApiArtifactHandler { - createArtifacts(request: AddApiRequest): Promise; - updateArtifacts(request: UpdateApiRequest, opts?: ApiArtifactHandlerOptions): Promise; -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/api-input-manager/appsync-api-input-state.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/api-input-manager/appsync-api-input-state.ts deleted file mode 100644 index 7dae196ae2..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/api-input-manager/appsync-api-input-state.ts +++ /dev/null @@ -1,53 +0,0 @@ -import * as path from 'path'; -import { - $TSContext, - AmplifyCategories, - AmplifySupportedService, - CLIInputSchemaValidator, - JSONUtilities, - pathManager, -} from '@aws-amplify/amplify-cli-core'; -import * as fs from 'fs-extra'; -import { AppSyncCLIInputs } from '../service-walkthrough-types/appsync-user-input-types'; - -export class AppsyncApiInputState { - #cliInputsFilePath: string; //cli-inputs.json (output) filepath - - #resourceName: string; //user friendly name provided by user - - #category: string; //category of the resource - - #service: string; //AWS service for the resource - - #buildFilePath: string; - - constructor(private readonly context: $TSContext, resourceName: string) { - this.#category = AmplifyCategories.API; - this.#service = AmplifySupportedService.APPSYNC; - this.#resourceName = resourceName; - - const projectBackendDirPath = pathManager.getBackendDirPath(); - this.#cliInputsFilePath = path.resolve(path.join(projectBackendDirPath, this.#category, this.#resourceName, 'cli-inputs.json')); - this.#buildFilePath = path.resolve(path.join(projectBackendDirPath, this.#category, this.#resourceName, 'build')); - } - - public async isCLIInputsValid(cliInputs: AppSyncCLIInputs = this.getCLIInputPayload()): Promise { - const schemaValidator = new CLIInputSchemaValidator(this.context, 'appsync', this.#category, 'AppSyncCLIInputs'); - return schemaValidator.validateInput(JSON.stringify(cliInputs)); - } - - public getCLIInputPayload(): AppSyncCLIInputs { - return JSONUtilities.readJson(this.#cliInputsFilePath, { throwIfNotExist: true })!; - } - - public cliInputFileExists(): boolean { - return fs.existsSync(this.#cliInputsFilePath); - } - - public async saveCLIInputPayload(cliInputs: AppSyncCLIInputs): Promise { - if (await this.isCLIInputsValid(cliInputs)) { - fs.ensureDirSync(path.join(pathManager.getBackendDirPath(), this.#category, this.#resourceName)); - JSONUtilities.writeJson(this.#cliInputsFilePath, cliInputs); - } - } -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/apigw-input-state.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/apigw-input-state.ts deleted file mode 100644 index 4ad6d22fd5..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/apigw-input-state.ts +++ /dev/null @@ -1,179 +0,0 @@ -import { join } from 'path'; -import { - $TSContext, - AmplifyCategories, - AmplifySupportedService, - CLIInputSchemaValidator, - getMigrateResourceMessageForOverride, - isResourceNameUnique, - JSONUtilities, - PathConstants, - pathManager, - stateManager, -} from '@aws-amplify/amplify-cli-core'; -import { prompter } from '@aws-amplify/amplify-prompts'; -import * as fs from 'fs-extra'; -import { ApigwInputs, ApigwStackTransform, CrudOperation, Path, PermissionSetting } from './cdk-stack-builder'; -import { convertDeperecatedRestApiPaths } from './convert-deprecated-apigw-paths'; -import { ApigwWalkthroughReturnPromise } from './service-walkthrough-types/apigw-types'; - -export class ApigwInputState { - projectRootPath: string; - - resourceName: string; - - paths: { [pathName: string]: Path }; - - constructor(private readonly context: $TSContext, resourceName?: string) { - this.projectRootPath = pathManager.findProjectRoot(); - this.resourceName = resourceName; - } - - public addAdminQueriesResource = async (adminQueriesProps: AdminQueriesProps) => { - this.resourceName = adminQueriesProps.apiName; - this.paths = { - '/{proxy+}': { - lambdaFunction: adminQueriesProps.functionName, - permissions: { - setting: PermissionSetting.PRIVATE, - auth: [CrudOperation.CREATE, CrudOperation.READ, CrudOperation.UPDATE, CrudOperation.DELETE], - }, - }, - }; - - await this.createApigwArtifacts(); - - // Update amplify-meta and backend-config - const backendConfigs = { - service: AmplifySupportedService.APIGW, - providerPlugin: 'awscloudformation', - authorizationType: 'AMAZON_COGNITO_USER_POOLS', - dependsOn: adminQueriesProps.dependsOn, - }; - - this.context.amplify.updateamplifyMetaAfterResourceAdd(AmplifyCategories.API, adminQueriesProps.apiName, backendConfigs); - }; - - public updateAdminQueriesResource = async (adminQueriesProps: AdminQueriesProps) => { - this.resourceName = adminQueriesProps.apiName; - this.paths = { - '/{proxy+}': { - lambdaFunction: adminQueriesProps.functionName, - permissions: { - setting: PermissionSetting.PRIVATE, - auth: [CrudOperation.CREATE, CrudOperation.READ, CrudOperation.UPDATE, CrudOperation.DELETE], - }, - }, - }; - - await this.createApigwArtifacts(); - - this.context.amplify.updateamplifyMetaAfterResourceUpdate( - AmplifyCategories.API, - adminQueriesProps.apiName, - 'dependsOn', - adminQueriesProps.dependsOn, - ); - }; - - public addApigwResource = async (serviceWalkthroughPromise: ApigwWalkthroughReturnPromise, options: Record) => { - const { answers } = await serviceWalkthroughPromise; - - this.resourceName = answers.resourceName; - this.paths = answers.paths; - options.dependsOn = answers.dependsOn; - - isResourceNameUnique(AmplifyCategories.API, this.resourceName); - - await this.createApigwArtifacts(); - - this.context.amplify.updateamplifyMetaAfterResourceAdd(AmplifyCategories.API, this.resourceName, options); - return this.resourceName; - }; - - public updateApigwResource = async (updateWalkthroughPromise: Promise>) => { - const { answers } = await updateWalkthroughPromise; - - this.resourceName = answers.resourceName; - this.paths = answers.paths; - - await this.createApigwArtifacts(); - - this.context.amplify.updateamplifyMetaAfterResourceUpdate(AmplifyCategories.API, this.resourceName, 'dependsOn', answers.dependsOn); - return this.resourceName; - }; - - public migrateAdminQueries = async (adminQueriesProps: AdminQueriesProps) => { - this.resourceName = this.resourceName ?? adminQueriesProps.apiName; - if (!(await prompter.yesOrNo(getMigrateResourceMessageForOverride(AmplifyCategories.API, this.resourceName, true), true))) { - return; - } - const resourceDirPath = pathManager.getResourceDirectoryPath(this.projectRootPath, AmplifyCategories.API, this.resourceName); - - fs.removeSync(join(resourceDirPath, PathConstants.ParametersJsonFileName)); - fs.removeSync(join(resourceDirPath, 'admin-queries-cloudformation-template.json')); - - return this.updateAdminQueriesResource(adminQueriesProps); - }; - - public migrateApigwResource = async (resourceName: string) => { - this.resourceName = this.resourceName ?? resourceName; - if (!(await prompter.yesOrNo(getMigrateResourceMessageForOverride(AmplifyCategories.API, this.resourceName, true), true))) { - return; - } - const deprecatedParametersFileName = 'api-params.json'; - const resourceDirPath = pathManager.getResourceDirectoryPath(this.projectRootPath, AmplifyCategories.API, this.resourceName); - const deprecatedParametersFilePath = join(resourceDirPath, deprecatedParametersFileName); - this.paths = convertDeperecatedRestApiPaths(deprecatedParametersFileName, deprecatedParametersFilePath, this.resourceName); - - fs.removeSync(deprecatedParametersFilePath); - fs.removeSync(join(resourceDirPath, PathConstants.ParametersJsonFileName)); - fs.removeSync(join(resourceDirPath, `${this.resourceName}-cloudformation-template.json`)); - - await this.createApigwArtifacts(); - }; - - public cliInputsFileExists() { - return stateManager.resourceInputsJsonExists(this.projectRootPath, AmplifyCategories.API, this.resourceName); - } - - public getCliInputPayload() { - return stateManager.getResourceInputsJson(this.projectRootPath, AmplifyCategories.API, this.resourceName); - } - - public async isCLIInputsValid(cliInputs?: ApigwInputs) { - if (!cliInputs) { - cliInputs = this.getCliInputPayload(); - } - - const schemaValidator = new CLIInputSchemaValidator( - this.context, - AmplifySupportedService.APIGW, - AmplifyCategories.API, - 'APIGatewayCLIInputs', - ); - await schemaValidator.validateInput(JSONUtilities.stringify(cliInputs)); - } - - private async createApigwArtifacts() { - const resourceDirPath = pathManager.getResourceDirectoryPath(this.projectRootPath, AmplifyCategories.API, this.resourceName); - fs.ensureDirSync(resourceDirPath); - - const buildDirPath = join(resourceDirPath, PathConstants.BuildDirName); - fs.ensureDirSync(buildDirPath); - - stateManager.setResourceInputsJson(this.projectRootPath, AmplifyCategories.API, this.resourceName, { version: 1, paths: this.paths }); - - stateManager.setResourceParametersJson(this.projectRootPath, AmplifyCategories.API, this.resourceName, {}); - - const stack = new ApigwStackTransform(this.context, this.resourceName, this); - await stack.transform(); - } -} - -export type AdminQueriesProps = { - apiName: string; - functionName: string; - authResourceName: string; - dependsOn: Record[]; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/aws-constants.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/aws-constants.ts deleted file mode 100644 index 418b53b47f..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/aws-constants.ts +++ /dev/null @@ -1,8 +0,0 @@ -import * as path from 'path'; - -export const provider = 'awscloudformation'; -export const parametersFileName = 'api-params.json'; -export const cfnParametersFilename = 'parameters.json'; -export const gqlSchemaFilename = 'schema.graphql'; - -export const rootAssetDir = path.resolve(path.join(__dirname, '..', '..', '..', 'resources', 'awscloudformation')); diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/base-api-stack.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/base-api-stack.ts deleted file mode 100644 index 6adeed99f7..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/base-api-stack.ts +++ /dev/null @@ -1,582 +0,0 @@ -import * as path from 'path'; -import * as fs from 'fs-extra'; -import * as ec2 from 'aws-cdk-lib/aws-ec2'; -import * as ecr from 'aws-cdk-lib/aws-ecr'; -import * as ecs from 'aws-cdk-lib/aws-ecs'; -import * as iam from 'aws-cdk-lib/aws-iam'; -import { CfnFunction } from 'aws-cdk-lib/aws-lambda'; -import * as logs from 'aws-cdk-lib/aws-logs'; -import * as s3 from 'aws-cdk-lib/aws-s3'; -import * as ssm from 'aws-cdk-lib/aws-secretsmanager'; -import * as cloudmap from 'aws-cdk-lib/aws-servicediscovery'; -import * as cdk from 'aws-cdk-lib'; -import { Construct } from 'constructs'; -import { NETWORK_STACK_LOGICAL_ID } from '../../category-constants'; -import Container from './docker-compose/ecs-objects/container'; -import { GitHubSourceActionInfo, PipelineWithAwaiter } from './pipeline-with-awaiter'; - -const PIPELINE_AWAITER_ZIP = 'custom-resource-pipeline-awaiter-18.zip'; - -export enum DEPLOYMENT_MECHANISM { - /** - * on every amplify push. - */ - FULLY_MANAGED = 'FULLY_MANAGED', - /** - * on every github push - */ - INDENPENDENTLY_MANAGED = 'INDENPENDENTLY_MANAGED', - /** - * manually push by the customer to ECR - */ - SELF_MANAGED = 'SELF_MANAGED', -} - -export type ContainersStackProps = Readonly<{ - skipWait?: boolean; - categoryName: string; - apiName: string; - dependsOn: ReadonlyArray<{ - category: string; - resourceName: string; - attributes: string[]; - }>; - taskEnvironmentVariables?: Record; - deploymentMechanism: DEPLOYMENT_MECHANISM; - restrictAccess: boolean; - policies?: ReadonlyArray>; - containers: ReadonlyArray; - secretsArns?: ReadonlyMap; - exposedContainer: { name: string; port: number }; - taskPorts: number[]; - isInitialDeploy: boolean; - desiredCount: number; - createCloudMapService?: boolean; - gitHubSourceActionInfo?: GitHubSourceActionInfo; - existingEcrRepositories: Set; - currentStackName: string; -}>; -export abstract class ContainersStack extends cdk.Stack { - protected readonly vpcId: string; - - private readonly vpcCidrBlock: string; - - protected readonly subnets: ReadonlyArray; - - private readonly clusterName: string; - - private readonly zipPath: string; - - private readonly cloudMapNamespaceId: string; - - protected readonly vpcLinkId: string; - - private readonly pipelineWithAwaiter: PipelineWithAwaiter; - - protected readonly cloudMapService: cloudmap.CfnService | undefined; - - protected readonly ecsService: ecs.CfnService; - - protected readonly isAuthCondition: cdk.CfnCondition; - - protected readonly appClientId: string | undefined; - - protected readonly userPoolId: string | undefined; - - protected readonly ecsServiceSecurityGroup: ec2.CfnSecurityGroup; - - protected readonly parameters: ReadonlyMap; - - protected readonly envName: string; - - protected readonly deploymentBucketName: string; - - protected readonly awaiterS3Key: string; - - constructor(scope: Construct, id: string, private readonly props: ContainersStackProps) { - super(scope, id, { synthesizer: new cdk.LegacyStackSynthesizer() }); - - const { - parameters, - vpcId, - vpcCidrBlock, - subnets, - clusterName, - zipPath, - cloudMapNamespaceId, - vpcLinkId, - isAuthCondition, - appClientId, - userPoolId, - envName, - deploymentBucketName, - awaiterS3Key, - } = this.init(); - - this.parameters = parameters; - - this.vpcId = vpcId; - this.vpcCidrBlock = vpcCidrBlock; - this.subnets = subnets; - this.clusterName = clusterName; - this.zipPath = zipPath; - this.cloudMapNamespaceId = cloudMapNamespaceId; - this.vpcLinkId = vpcLinkId; - this.isAuthCondition = isAuthCondition; - this.appClientId = appClientId; - this.userPoolId = userPoolId; - this.envName = envName; - this.deploymentBucketName = deploymentBucketName; - this.awaiterS3Key = awaiterS3Key; - const { service, serviceSecurityGroup, containersInfo, cloudMapService } = this.ecs(); - - this.cloudMapService = cloudMapService; - this.ecsService = service; - this.ecsServiceSecurityGroup = serviceSecurityGroup; - - const { gitHubSourceActionInfo, skipWait } = this.props; - - const { pipelineWithAwaiter } = this.pipeline({ - skipWait, - service, - containersInfo: containersInfo.filter((container) => container.repository), - gitHubSourceActionInfo, - }); - - this.pipelineWithAwaiter = pipelineWithAwaiter; - - new cdk.CfnOutput(this, 'ContainerNames', { - value: cdk.Fn.join( - ',', - containersInfo.map(({ container: { containerName } }) => containerName), - ), - }); - } - - private init() { - const { restrictAccess, dependsOn, deploymentMechanism } = this.props; - - // Unused in this stack, but required by the root stack - new cdk.CfnParameter(this, 'env', { type: 'String' }); - - const paramDomain = new cdk.CfnParameter(this, 'domain', { type: 'String', default: '' }); - const paramRestrictAccess = new cdk.CfnParameter(this, 'restrictAccess', { - type: 'String', - allowedValues: ['true', 'false'], - default: 'false', - }); - - const paramZipPath = new cdk.CfnParameter(this, 'ParamZipPath', { - type: 'String', - // Required only for FULLY_MANAGED - default: deploymentMechanism === DEPLOYMENT_MECHANISM.FULLY_MANAGED ? undefined : '', - }); - - const parameters: Map = new Map(); - - parameters.set('ParamZipPath', paramZipPath); - parameters.set('domain', paramDomain); - parameters.set('restrictAccess', paramRestrictAccess); - - const authParams: { - UserPoolId?: cdk.CfnParameter; - AppClientIDWeb?: cdk.CfnParameter; - } = {}; - - const paramTypes: Record = { - NetworkStackSubnetIds: 'CommaDelimitedList', - }; - - dependsOn.forEach(({ category, resourceName, attributes }) => { - attributes.forEach((attrib) => { - const paramName = [category, resourceName, attrib].join(''); - - const type = paramTypes[paramName] ?? 'String'; - const param = new cdk.CfnParameter(this, paramName, { type }); - - parameters.set(paramName, param); - - if (category === 'auth') { - authParams[attrib as keyof typeof authParams] = param; - } - }); - }); - - const paramVpcId = parameters.get(`${NETWORK_STACK_LOGICAL_ID}VpcId`); - const paramVpcCidrBlock = parameters.get(`${NETWORK_STACK_LOGICAL_ID}VpcCidrBlock`); - const paramSubnetIds = parameters.get(`${NETWORK_STACK_LOGICAL_ID}SubnetIds`); - const paramClusterName = parameters.get(`${NETWORK_STACK_LOGICAL_ID}ClusterName`); - const paramCloudMapNamespaceId = parameters.get(`${NETWORK_STACK_LOGICAL_ID}CloudMapNamespaceId`); - const paramVpcLinkId = parameters.get(`${NETWORK_STACK_LOGICAL_ID}VpcLinkId`); - - const { UserPoolId: paramUserPoolId, AppClientIDWeb: paramAppClientIdWeb } = authParams; - - const isAuthCondition = new cdk.CfnCondition(this, 'isAuthCondition', { - expression: cdk.Fn.conditionAnd( - cdk.Fn.conditionEquals(restrictAccess, true), - cdk.Fn.conditionNot(cdk.Fn.conditionEquals(paramUserPoolId ?? '', '')), - cdk.Fn.conditionNot(cdk.Fn.conditionEquals(paramAppClientIdWeb ?? '', '')), - ), - }); - - const stackNameParameter = new cdk.CfnParameter(this, 'rootStackName', { - type: 'String', - }); - - const deploymentBucketName = new cdk.CfnParameter(this, 'deploymentBucketName', { - type: 'String', - }); - const awaiterS3Key = new cdk.CfnParameter(this, 'awaiterS3Key', { - type: 'String', - default: PIPELINE_AWAITER_ZIP, - }); - return { - parameters, - vpcId: paramVpcId.valueAsString, - vpcCidrBlock: paramVpcCidrBlock.valueAsString, - subnets: paramSubnetIds.valueAsList, - clusterName: paramClusterName.valueAsString, - zipPath: paramZipPath.valueAsString, - cloudMapNamespaceId: paramCloudMapNamespaceId.valueAsString, - vpcLinkId: paramVpcLinkId.valueAsString, - isAuthCondition, - userPoolId: paramUserPoolId && paramUserPoolId.valueAsString, - appClientId: paramAppClientIdWeb && paramAppClientIdWeb.valueAsString, - envName: stackNameParameter.valueAsString, - deploymentBucketName: deploymentBucketName.valueAsString, - awaiterS3Key: awaiterS3Key.valueAsString, - }; - } - - private ecs() { - const { - categoryName, - apiName, - policies, - containers, - secretsArns, - taskEnvironmentVariables, - exposedContainer, - taskPorts, - isInitialDeploy, - desiredCount, - currentStackName, - createCloudMapService, - } = this.props; - - let cloudMapService: cloudmap.CfnService = undefined; - - if (createCloudMapService) { - cloudMapService = new cloudmap.CfnService(this, 'CloudmapService', { - name: apiName, - dnsConfig: { - dnsRecords: [ - { - ttl: 60, - type: cloudmap.DnsRecordType.SRV, - }, - ], - namespaceId: this.cloudMapNamespaceId, - routingPolicy: cloudmap.RoutingPolicy.MULTIVALUE, - }, - }); - } - - const task = new ecs.TaskDefinition(this, 'TaskDefinition', { - compatibility: ecs.Compatibility.FARGATE, - memoryMiB: '1024', - cpu: '512', - family: `${this.envName}-${apiName}`, - }); - (task.node.defaultChild as ecs.CfnTaskDefinition).overrideLogicalId('TaskDefinition'); - policies.forEach((policy) => { - const statement = isPolicyStatement(policy) ? policy : jsonPolicyToCdkPolicyStatement(policy); - task.addToTaskRolePolicy(statement); - }); - - const containersInfo: { - container: ecs.ContainerDefinition; - repository: ecr.IRepository; - }[] = []; - - containers.forEach( - ({ - name, - image, - build, - portMappings, - logConfiguration, - environment, - entrypoint: entryPoint, - command, - working_dir: workingDirectory, - healthcheck: healthCheck, - secrets: containerSecrets, - }) => { - const logGroup = new logs.LogGroup(this, `${name}ContainerLogGroup`, { - logGroupName: `/ecs/${this.envName}-${apiName}-${name}`, - retention: logs.RetentionDays.ONE_MONTH, - removalPolicy: cdk.RemovalPolicy.DESTROY, - }); - - const { logDriver, options: { 'awslogs-stream-prefix': streamPrefix } = {} } = logConfiguration; - - const logging: ecs.LogDriver = - logDriver === 'awslogs' - ? ecs.LogDriver.awsLogs({ - streamPrefix, - logGroup: logs.LogGroup.fromLogGroupName(this, `${name}logGroup`, logGroup.logGroupName), - }) - : undefined; - - let repository: ecr.IRepository; - if (build) { - const logicalId = `${name}Repository`; - - const repositoryName = `${currentStackName}-${categoryName}-${apiName}-${name}`; - - if (this.props.existingEcrRepositories.has(repositoryName)) { - repository = ecr.Repository.fromRepositoryName(this, logicalId, repositoryName); - } else { - repository = new ecr.Repository(this, logicalId, { - repositoryName: `${this.envName}-${categoryName}-${apiName}-${name}`, - removalPolicy: cdk.RemovalPolicy.RETAIN, - lifecycleRules: [ - { - rulePriority: 10, - maxImageCount: 1, - tagPrefixList: ['latest'], - tagStatus: ecr.TagStatus.TAGGED, - }, - { - rulePriority: 100, - maxImageAge: cdk.Duration.days(7), - tagStatus: ecr.TagStatus.ANY, - }, - ], - }); - (repository.node.defaultChild as ecr.CfnRepository).overrideLogicalId(logicalId); - } - - // Needed because the image will be pulled from ecr repository later - repository.grantPull(task.obtainExecutionRole()); - } - - const secrets: ecs.ContainerDefinitionOptions['secrets'] = {}; - const environmentWithoutSecrets = environment || {}; - - containerSecrets.forEach((s, i) => { - if (secretsArns.has(s)) { - secrets[s] = ecs.Secret.fromSecretsManager(ssm.Secret.fromSecretPartialArn(this, `${name}secret${i + 1}`, secretsArns.get(s))); - } - - delete environmentWithoutSecrets[s]; - }); - - const container = task.addContainer(name, { - image: repository ? ecs.ContainerImage.fromEcrRepository(repository) : ecs.ContainerImage.fromRegistry(image), - logging, - environment: { - ...taskEnvironmentVariables, - ...environmentWithoutSecrets, - }, - entryPoint, - command, - workingDirectory, - healthCheck: healthCheck && { - command: healthCheck.command, - interval: cdk.Duration.seconds(healthCheck.interval ?? 30), - retries: healthCheck.retries, - timeout: cdk.Duration.seconds(healthCheck.timeout ?? 5), - startPeriod: cdk.Duration.seconds(healthCheck.start_period ?? 0), - }, - secrets, - }); - - containersInfo.push({ - container, - repository, - }); - - // TODO: should we use hostPort too? check network mode - portMappings?.forEach(({ containerPort, protocol, hostPort }) => { - container.addPortMappings({ - containerPort, - protocol: ecs.Protocol.TCP, - }); - }); - }, - ); - - const serviceSecurityGroup = new ec2.CfnSecurityGroup(this, 'ServiceSG', { - vpcId: this.vpcId, - groupDescription: 'Service SecurityGroup', - securityGroupEgress: [ - { - description: 'Allow all outbound traffic by default', - cidrIp: '0.0.0.0/0', - ipProtocol: '-1', - }, - ], - securityGroupIngress: taskPorts.map((servicePort) => ({ - ipProtocol: 'tcp', - fromPort: servicePort, - toPort: servicePort, - cidrIp: this.vpcCidrBlock, - })), - }); - - let serviceRegistries: ecs.CfnService.ServiceRegistryProperty[] = undefined; - - if (cloudMapService) { - serviceRegistries = [ - { - containerName: exposedContainer.name, - containerPort: exposedContainer.port, - registryArn: cloudMapService.attrArn, - }, - ]; - } - - const service = new ecs.CfnService(this, 'Service', { - serviceName: `${apiName}-service-${exposedContainer.name}-${exposedContainer.port}`, - cluster: this.clusterName, - launchType: 'FARGATE', - desiredCount: isInitialDeploy ? 0 : desiredCount, // This is later adjusted by the Predeploy action in the codepipeline - networkConfiguration: { - awsvpcConfiguration: { - assignPublicIp: 'ENABLED', - securityGroups: [serviceSecurityGroup.attrGroupId], - subnets: this.subnets, - }, - }, - taskDefinition: task.taskDefinitionArn, - serviceRegistries, - }); - - new cdk.CfnOutput(this, 'ServiceName', { - value: service.serviceName, - }); - - new cdk.CfnOutput(this, 'ClusterName', { - value: this.clusterName, - }); - - return { - service, - serviceSecurityGroup, - containersInfo, - cloudMapService, - }; - } - - private pipeline({ - skipWait = false, - service, - containersInfo, - gitHubSourceActionInfo, - }: { - skipWait?: boolean; - service: ecs.CfnService; - containersInfo: { - container: ecs.ContainerDefinition; - repository: ecr.IRepository; - }[]; - gitHubSourceActionInfo?: GitHubSourceActionInfo; - }) { - const { deploymentMechanism, desiredCount } = this.props; - - const s3SourceActionKey = this.zipPath; - - const bucket = s3.Bucket.fromBucketName(this, 'Bucket', this.deploymentBucketName); - - const pipelineWithAwaiter = new PipelineWithAwaiter(this, 'ApiPipeline', { - skipWait, - envName: this.envName, - containersInfo, - service, - bucket, - s3SourceActionKey, - deploymentMechanism, - gitHubSourceActionInfo, - desiredCount, - }); - - pipelineWithAwaiter.node.addDependency(service); - - return { pipelineWithAwaiter }; - } - - protected getPipelineName() { - return this.pipelineWithAwaiter.getPipelineName(); - } - - getPipelineConsoleUrl(region: string) { - const pipelineName = this.getPipelineName(); - return `https://${region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/${pipelineName}/view`; - } - - /** - * This function renderers a full CFN template for this stack. - * It is inspired by - * https://github.com/aws/aws-cdk/blob/bd056d1d38a2d3f43efe4f857c4d38b30fb9b681/packages/%40aws-cdk/assertions/lib/template.ts#L298-L310. - * This replaces private prepareApp (from CDK v1) and this._toCloudFormation() (the latter does not function properly without the former). - */ - private renderCfnTemplate(): any { - const root = this.node.root as cdk.Stage; - const assembly = root.synth(); - if (this.nestedStackParent) { - // if this is a nested stack (it has a parent), then just read the template as a string - return JSON.parse(fs.readFileSync(path.join(assembly.directory, this.templateFile)).toString('utf-8')); - } - return assembly.getStackArtifact(this.artifactId).template; - } - - toCloudFormation() { - this.node - .findAll() - .filter((construct) => construct instanceof CfnFunction) - .map((construct) => construct as CfnFunction) - .forEach((lambdaFunction) => { - if (lambdaFunction.logicalId.includes('AwaiterMyProvider')) { - lambdaFunction.code = { - s3Bucket: this.deploymentBucketName, - s3Key: this.awaiterS3Key, - }; - } - }); - - const cfn = this.renderCfnTemplate(); - - Object.keys(cfn.Parameters).forEach((k) => { - if (k.startsWith('AssetParameters')) { - delete cfn.Parameters[k]; - } - }); - - return cfn; - } -} - -/** - * Return a {iam.PolicyStatement} from JSON IAM policy. - * This allow us tu pass the statements in a way that CDK can use when synthesizing - * - * @param policy JSON object of IAM policy - * @returns {iam.PolicyStatement} CDK policy statement - */ -function jsonPolicyToCdkPolicyStatement(policy: Record): iam.PolicyStatement { - return new iam.PolicyStatement({ - effect: policy.Effect, - actions: Array.isArray(policy.Action) ? policy.Action : [policy.Action], - resources: Array.isArray(policy.Resource) ? policy.Resource.map((r) => cdk.Token.asString(r)) : [cdk.Token.asString(policy.Resource)], - }); -} - -function isPolicyStatement(obj: any): obj is iam.PolicyStatement { - if (obj && typeof (obj).toStatementJson === 'function') { - return true; - } - - return false; -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.ts deleted file mode 100644 index 413ad1e6c2..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.ts +++ /dev/null @@ -1,508 +0,0 @@ -/* eslint-disable jsdoc/require-param-description */ -/* eslint-disable no-use-before-define */ -/* eslint-disable @typescript-eslint/explicit-function-return-type */ -/* eslint-disable no-underscore-dangle */ -import * as apigw from 'aws-cdk-lib/aws-apigateway'; -import * as iam from 'aws-cdk-lib/aws-iam'; -import * as lambda from 'aws-cdk-lib/aws-lambda'; -import * as cdk from 'aws-cdk-lib'; -import { Construct } from 'constructs'; -import { JSONUtilities } from '@aws-amplify/amplify-cli-core'; -import _ from 'lodash'; -import { v4 as uuid } from 'uuid'; -import { ADMIN_QUERIES_NAME } from '../../../category-constants'; -import { AmplifyApigwResourceTemplate, ApigwInputs, ApigwPathPolicy, Path, PermissionSetting } from './types'; - -const CFN_TEMPLATE_FORMAT_VERSION = '2010-09-09'; -const ROOT_CFN_DESCRIPTION = 'API Gateway Resource for AWS Amplify CLI'; - -export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigwResourceTemplate { - restApi: apigw.CfnRestApi; - - deploymentResource: apigw.CfnDeployment; - - paths: Record; - - policies: { [pathName: string]: ApigwPathPolicy }; - - private _scope: Construct; - - private _props: ApigwInputs; - - private _cfnParameterMap: Map = new Map(); - - private _cfnParameterValues: Record; - - private _seenLogicalIds: Set; - - constructor(scope: Construct, id: string, props: ApigwInputs) { - super(scope, id, undefined); - this._scope = scope; - this._props = props; - this.paths = {}; - this._seenLogicalIds = new Set(); - this._cfnParameterValues = {}; - this.policies = {}; - this.templateOptions.templateFormatVersion = CFN_TEMPLATE_FORMAT_VERSION; - this.templateOptions.description = ROOT_CFN_DESCRIPTION; - } - - addCfnOutput(props: cdk.CfnOutputProps, logicalId: string): void { - this.validateLogicalId(logicalId); - new cdk.CfnOutput(this, logicalId, props); - } - - addCfnMapping(props: cdk.CfnMappingProps, logicalId: string): void { - this.validateLogicalId(logicalId); - new cdk.CfnMapping(this, logicalId, props); - } - - addCfnCondition(props: cdk.CfnConditionProps, logicalId: string): void { - this.validateLogicalId(logicalId); - new cdk.CfnCondition(this, logicalId, props); - } - - addCfnResource(props: cdk.CfnResourceProps, logicalId: string): void { - this.validateLogicalId(logicalId); - new cdk.CfnResource(this, logicalId, props); - } - - addCfnLambdaPermissionResource(props: lambda.CfnPermissionProps, logicalId: string): void { - this.validateLogicalId(logicalId); - new lambda.CfnPermission(this, logicalId, props); - } - - // eslint-disable-next-line jsdoc/require-description - /** - * @param props - * @param logicalId - * @param value optional value which will be stored in parameters.json - */ - addCfnParameter(props: cdk.CfnParameterProps, logicalId: string, value?: string | Record): void { - this.validateLogicalId(logicalId); - this._cfnParameterMap.set(logicalId, new cdk.CfnParameter(this, logicalId, props)); - if (value !== undefined) { - this._cfnParameterValues[logicalId] = value; - } - } - - getCfnParameterValues() { - return this._cfnParameterValues; - } - - private validateLogicalId(logicalId: string): void { - if (this._seenLogicalIds.has(logicalId)) { - throw new Error(`logical id "${logicalId}" already exists`); - } - this._seenLogicalIds.add(logicalId); - } - - // eslint-disable-next-line class-methods-use-this - private _craftPolicyDocument(apiResourceName: string, pathName: string, supportedOperations: string[]) { - const policyPathName = pathName.replace(/{[a-zA-Z0-9-]+}/g, '*'); - const paths = [policyPathName, appendToUrlPath(policyPathName, '*')]; - const resources = paths.flatMap((path) => - supportedOperations.map((op) => - cdk.Fn.join('', [ - 'arn:aws:execute-api:', - cdk.Fn.ref('AWS::Region'), - ':', - cdk.Fn.ref('AWS::AccountId'), - ':', - cdk.Fn.ref(apiResourceName), - '/', - cdk.Fn.conditionIf('ShouldNotCreateEnvResources', 'Prod', cdk.Fn.ref('env')).toString(), - op, - path, - ]), - ), - ); - - return new iam.PolicyDocument({ - statements: [ - new iam.PolicyStatement({ - actions: ['execute-api:Invoke'], - effect: iam.Effect.ALLOW, - resources, - }), - ], - }); - } - - addIamPolicyResourceForUserPoolGroup( - apiResourceName: string, - authRoleLogicalId: string, - groupName: string, - pathName: string, - supportedOperations: string[], - ): void { - const alphanumericPathName = pathName.replace(/[^-a-z0-9]/g, ''); - - const policyName = [apiResourceName, alphanumericPathName, groupName, 'group', 'policy'].join('-'); - - const iamPolicy = new iam.CfnPolicy(this, `${groupName}Group${alphanumericPathName}Policy`, { - policyDocument: this._craftPolicyDocument(apiResourceName, pathName, supportedOperations), - policyName, - roles: [cdk.Fn.join('-', [cdk.Fn.ref(authRoleLogicalId), `${groupName}GroupRole`])], - }); - _.set(this.policies, [pathName, 'groups', groupName], iamPolicy); - } - - renderCloudFormationTemplate = (): string => JSONUtilities.stringify(this._toCloudFormation()); - - generateAdminQueriesStack = (resourceName: string, authResourceName: string) => { - this._constructCfnPaths(resourceName); - - this.restApi = new apigw.CfnRestApi(this, resourceName, { - description: '', - name: resourceName, - body: { - swagger: '2.0', - info: { - version: '2018-05-24T17:52:00Z', - title: resourceName, - }, - host: cdk.Fn.join('', ['apigateway.', cdk.Fn.ref('AWS::Region'), '.amazonaws.com']), - basePath: cdk.Fn.conditionIf('ShouldNotCreateEnvResources', '/Prod', cdk.Fn.join('', ['/', cdk.Fn.ref('env')])), - schemes: ['https'], - paths: this.paths, - securityDefinitions: { - Cognito: { - type: 'apiKey', - name: 'Authorization', - in: 'header', - 'x-amazon-apigateway-authtype': 'cognito_user_pools', - 'x-amazon-apigateway-authorizer': { - providerARNs: [ - cdk.Fn.join('', [ - 'arn:aws:cognito-idp:', - cdk.Fn.ref('AWS::Region'), - ':', - cdk.Fn.ref('AWS::AccountId'), - ':userpool/', - cdk.Fn.ref(`auth${authResourceName}UserPoolId`), - ]), - ], - type: 'cognito_user_pools', - }, - }, - }, - definitions: { - Empty: { - type: 'object', - title: 'Empty Schema', - }, - }, - 'x-amazon-apigateway-request-validators': { - 'Validate query string parameters and headers': { - validateRequestParameters: true, - validateRequestBody: false, - }, - }, - }, - }); - - this._setDeploymentResource(resourceName); - }; - - generateStackResources = (resourceName: string) => { - this._constructCfnPaths(resourceName); - - this.restApi = new apigw.CfnRestApi(this, resourceName, { - description: '', - failOnWarnings: true, - name: resourceName, - body: { - swagger: '2.0', - info: { - version: '2018-05-24T17:52:00Z', - title: resourceName, - }, - host: cdk.Fn.join('', ['apigateway.', cdk.Fn.ref('AWS::Region'), '.amazonaws.com']), - basePath: cdk.Fn.conditionIf('ShouldNotCreateEnvResources', '/Prod', cdk.Fn.join('', ['/', cdk.Fn.ref('env')])), - schemes: ['https'], - paths: this.paths, - securityDefinitions: { - sigv4: { - type: 'apiKey', - name: 'Authorization', - in: 'header', - 'x-amazon-apigateway-authtype': 'awsSigv4', - }, - }, - definitions: { - RequestSchema: { - type: 'object', - required: ['request'], - properties: { - request: { - type: 'string', - }, - }, - title: 'Request Schema', - }, - ResponseSchema: { - type: 'object', - required: ['response'], - properties: { - response: { - type: 'string', - }, - }, - title: 'Response Schema', - }, - }, - }, - }); - - // Append a random id to the logical id of the gateway response - // This is required to resolve issue with dropping gateway responses on updating api resource - const [responseRandomId] = uuid().split('-'); - const default4xx = new apigw.CfnGatewayResponse(this, `${resourceName}Default4XXResponse${responseRandomId}`, { - responseType: 'DEFAULT_4XX', - restApiId: cdk.Fn.ref(resourceName), - responseParameters: defaultCorsGatewayResponseParams, - }); - const default5xx = new apigw.CfnGatewayResponse(this, `${resourceName}Default5XXResponse${responseRandomId}`, { - responseType: 'DEFAULT_5XX', - restApiId: cdk.Fn.ref(resourceName), - responseParameters: defaultCorsGatewayResponseParams, - }); - - this._setDeploymentResource(resourceName, [default4xx, default5xx]); - }; - - private _constructCfnPaths(resourceName: string) { - const addedFunctionPermissions = new Set(); - for (const [pathName, path] of Object.entries(this._props.paths)) { - let lambdaPermissionLogicalId: string; - if (resourceName === ADMIN_QUERIES_NAME) { - this.paths['/{proxy+}'] = getAdminQueriesPathObject(path.lambdaFunction); - lambdaPermissionLogicalId = `${ADMIN_QUERIES_NAME}APIGWPolicyForLambda`; - } else { - this.paths[pathName] = createPathObject(path); - this.paths[appendToUrlPath(pathName, '{proxy+}')] = createPathObject(path); - lambdaPermissionLogicalId = `function${path.lambdaFunction}Permission${resourceName}`; - } - - if (!addedFunctionPermissions.has(path.lambdaFunction)) { - addedFunctionPermissions.add(path.lambdaFunction); - this.addCfnLambdaPermissionResource( - { - functionName: cdk.Fn.ref(`function${path.lambdaFunction}Name`), - action: 'lambda:InvokeFunction', - principal: 'apigateway.amazonaws.com', - sourceArn: cdk.Fn.join('', [ - 'arn:aws:execute-api:', - cdk.Fn.ref('AWS::Region'), - ':', - cdk.Fn.ref('AWS::AccountId'), - ':', - cdk.Fn.ref(resourceName), - '/*/*/*', - ]), - }, - lambdaPermissionLogicalId, - ); - } - } - } - - private _setDeploymentResource = (apiName: string, dependencies: cdk.CfnResource[] = []) => { - const [shortId] = uuid().split('-'); - this.deploymentResource = new apigw.CfnDeployment(this, `DeploymentAPIGW${apiName}${shortId}`, { - description: 'The Development stage deployment of your API.', - stageName: cdk.Fn.conditionIf('ShouldNotCreateEnvResources', 'Prod', cdk.Fn.ref('env')).toString(), - restApiId: cdk.Fn.ref(apiName), - }); - dependencies.forEach((dep) => this.deploymentResource.addDependency(dep)); - }; -} - -const appendToUrlPath = (path: string, postfix: string) => - path.charAt(path.length - 1) === '/' ? `${path}${postfix}` : `${path}/${postfix}`; - -const getAdminQueriesPathObject = (lambdaFunctionName: string) => ({ - options: { - consumes: ['application/json'], - produces: ['application/json'], - responses: { - 200: { - description: '200 response', - schema: { - $ref: '#/definitions/Empty', - }, - headers: { - 'Access-Control-Allow-Origin': { - type: 'string', - }, - 'Access-Control-Allow-Methods': { - type: 'string', - }, - 'Access-Control-Allow-Headers': { - type: 'string', - }, - }, - }, - }, - 'x-amazon-apigateway-integration': { - responses: { - default: { - statusCode: '200', - responseParameters: { - 'method.response.header.Access-Control-Allow-Methods': "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'", - 'method.response.header.Access-Control-Allow-Headers': "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'", - 'method.response.header.Access-Control-Allow-Origin': "'*'", - }, - }, - }, - passthroughBehavior: 'when_no_match', - requestTemplates: { - 'application/json': '{"statusCode": 200}', - }, - type: 'mock', - }, - }, - 'x-amazon-apigateway-any-method': { - produces: ['application/json'], - parameters: [ - { - name: 'proxy', - in: 'path', - required: true, - type: 'string', - }, - { - name: 'Authorization', - in: 'header', - required: false, - type: 'string', - }, - ], - responses: {}, - security: [ - { - Cognito: ['aws.cognito.signin.user.admin'], - }, - ], - 'x-amazon-apigateway-request-validator': 'Validate query string parameters and headers', - 'x-amazon-apigateway-integration': { - uri: cdk.Fn.join('', [ - 'arn:aws:apigateway:', - cdk.Fn.ref('AWS::Region'), - ':lambda:path/2015-03-31/functions/', - cdk.Fn.ref(`function${lambdaFunctionName}Arn`), - '/invocations', - ]), - passthroughBehavior: 'when_no_match', - httpMethod: 'POST', - cacheNamespace: 'n40eb9', - cacheKeyParameters: ['method.request.path.proxy'], - contentHandling: 'CONVERT_TO_TEXT', - type: 'aws_proxy', - }, - }, -}); - -const createPathObject = (path: Path) => { - const defaultPathObject: Record = { - options: { - consumes: ['application/json'], - produces: ['application/json'], - responses: { - 200: response200, - }, - 'x-amazon-apigateway-integration': { - responses: { - default: defaultCorsResponseObject, - }, - requestTemplates: { - 'application/json': '{"statusCode": 200}', - }, - passthroughBehavior: 'when_no_match', - type: 'mock', - }, - }, - 'x-amazon-apigateway-any-method': { - consumes: ['application/json'], - produces: ['application/json'], - parameters: [ - { - in: 'body', - name: 'RequestSchema', - required: false, - schema: { - $ref: '#/definitions/RequestSchema', - }, - }, - ], - responses: { - 200: { - description: '200 response', - schema: { - $ref: '#/definitions/ResponseSchema', - }, - }, - }, - 'x-amazon-apigateway-integration': { - responses: { - default: { - statusCode: '200', - }, - }, - uri: cdk.Fn.join('', [ - 'arn:aws:apigateway:', - cdk.Fn.ref('AWS::Region'), - ':lambda:path/2015-03-31/functions/', - cdk.Fn.ref(`function${path.lambdaFunction}Arn`), - '/invocations', - ]), - passthroughBehavior: 'when_no_match', - httpMethod: 'POST', - type: 'aws_proxy', - }, - }, - }; - - if (path.permissions.setting !== PermissionSetting.OPEN) { - defaultPathObject['x-amazon-apigateway-any-method'].security = [ - { - sigv4: [], - }, - ]; - } - - return defaultPathObject; -}; - -const defaultCorsResponseObject = { - statusCode: '200', - responseParameters: { - 'method.response.header.Access-Control-Allow-Methods': "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'", - 'method.response.header.Access-Control-Allow-Headers': - "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent'", - 'method.response.header.Access-Control-Allow-Origin': "'*'", - }, -}; - -const defaultCorsGatewayResponseParams = { - 'gatewayresponse.header.Access-Control-Allow-Origin': "'*'", - 'gatewayresponse.header.Access-Control-Allow-Headers': "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'", - 'gatewayresponse.header.Access-Control-Allow-Methods': "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'", - 'gatewayresponse.header.Access-Control-Expose-Headers': "'Date,X-Amzn-ErrorType'", -}; - -const response200 = { - description: '200 response', - headers: { - 'Access-Control-Allow-Origin': { - type: 'string', - }, - 'Access-Control-Allow-Methods': { - type: 'string', - }, - 'Access-Control-Allow-Headers': { - type: 'string', - }, - }, -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-transform.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-transform.ts deleted file mode 100644 index 3518391211..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-transform.ts +++ /dev/null @@ -1,253 +0,0 @@ -import * as cdk from 'aws-cdk-lib'; -import { - $TSContext, - AmplifyCategories, - AmplifyError, - buildOverrideDir, - getAmplifyResourceByCategories, - JSONUtilities, - PathConstants, - pathManager, - stateManager, - Template, - writeCFNTemplate, -} from '@aws-amplify/amplify-cli-core'; -import * as fs from 'fs-extra'; -import * as path from 'path'; -import { AmplifyApigwResourceStack, ApigwInputs, CrudOperation, Path } from '.'; -import { ApigwInputState } from '../apigw-input-state'; -import { ADMIN_QUERIES_NAME } from '../../../category-constants'; - -export class ApigwStackTransform { - cliInputs: ApigwInputs; - - resourceTemplateObj: AmplifyApigwResourceStack | undefined; - - cliInputsState: ApigwInputState; - - cfn: Template; - - cfnInputParams: Record; - - resourceName: string; - - private _app: cdk.App; - - constructor(context: $TSContext, resourceName: string, cliInputState?: ApigwInputState) { - this._app = new cdk.App(); - this.resourceName = resourceName; - - // Validate the cli-inputs.json for the resource - this.cliInputsState = cliInputState ?? new ApigwInputState(context, resourceName); - this.cliInputs = this.cliInputsState.getCliInputPayload(); - void this.cliInputsState.isCLIInputsValid(); - } - - async transform() { - let authResourceName: string; - - const pathsWithUserPoolGroups = Object.entries(this.cliInputs.paths).filter(([_, path]) => !!path?.permissions?.groups); - - if (this.resourceName === ADMIN_QUERIES_NAME || pathsWithUserPoolGroups.length > 0) { - [authResourceName] = getAmplifyResourceByCategories(AmplifyCategories.AUTH).filter( - (resourceName) => resourceName !== 'userPoolGroups', - ); - } - - // Generate cloudformation stack from cli-inputs.json - this.generateStack(authResourceName, pathsWithUserPoolGroups); - - // Modify cloudformation files based on overrides - await this.applyOverrides(); - // Generate cloudformation stack input params from cli-inputs.json - this.generateCfnInputParameters(); - - // Save generated cloudformation.json and parameters.json files - await this.saveBuildFiles(); - } - - generateCfnInputParameters() { - this.cfnInputParams = this.resourceTemplateObj.getCfnParameterValues(); - } - - generateStack(authResourceName?: string, pathsWithUserPoolGroups: [string, Path][] = []) { - this.resourceTemplateObj = new AmplifyApigwResourceStack(this._app, 'AmplifyApigwResourceStack', this.cliInputs); - - if (authResourceName) { - const authRoleLogicalId = `auth${authResourceName}UserPoolId`; - this.resourceTemplateObj.addCfnParameter( - { - type: 'String', - default: authRoleLogicalId, - }, - authRoleLogicalId, - ); - - const uniqueUserPoolGroupsList = new Set(); - for (const [pathName, path] of pathsWithUserPoolGroups) { - for (const [groupName, crudOps] of Object.entries(path.permissions.groups)) { - uniqueUserPoolGroupsList.add(groupName); - this.resourceTemplateObj.addIamPolicyResourceForUserPoolGroup( - this.resourceName, - authRoleLogicalId, - groupName, - pathName, - convertCrudOperationsToCfnPermissions(crudOps), - ); - } - } - Array.from(uniqueUserPoolGroupsList).forEach((userPoolGroupName) => { - this.resourceTemplateObj.addCfnParameter( - { - type: 'String', - default: `authuserPoolGroups${userPoolGroupName}GroupRole`, - }, - `authuserPoolGroups${userPoolGroupName}GroupRole`, - ); - }); - } - - // Add Parameters - const addedFunctions = new Set(); - for (const path of Object.values(this.cliInputs.paths)) { - if (!addedFunctions.has(path.lambdaFunction)) { - addedFunctions.add(path.lambdaFunction); - this.resourceTemplateObj.addCfnParameter( - { - type: 'String', - default: `function${path.lambdaFunction}Name`, - }, - `function${path.lambdaFunction}Name`, - ); - this.resourceTemplateObj.addCfnParameter( - { - type: 'String', - default: `function${path.lambdaFunction}Arn`, - }, - `function${path.lambdaFunction}Arn`, - ); - } - } - - this.resourceTemplateObj.addCfnParameter( - { - type: 'String', - }, - 'env', - ); - - // Add conditions - this.resourceTemplateObj.addCfnCondition( - { - expression: cdk.Fn.conditionEquals(cdk.Fn.ref('env'), 'NONE'), - }, - 'ShouldNotCreateEnvResources', - ); - - // Add outputs - this.resourceTemplateObj.addCfnOutput( - { - value: cdk.Fn.join('', [ - 'https://', - cdk.Fn.ref(this.cliInputsState.resourceName), - '.execute-api.', - cdk.Fn.ref('AWS::Region'), - '.amazonaws.com/', - cdk.Fn.conditionIf('ShouldNotCreateEnvResources', 'Prod', cdk.Fn.ref('env')) as unknown as string, - ]), - description: 'Root URL of the API gateway', - }, - 'RootUrl', - ); - - this.resourceTemplateObj.addCfnOutput( - { - value: this.resourceName, - description: 'API Friendly name', - }, - 'ApiName', - ); - - this.resourceTemplateObj.addCfnOutput( - { - value: cdk.Fn.ref(this.resourceName), - description: 'API ID (prefix of API URL)', - }, - 'ApiId', - ); - - // Add resources - this.resourceName === ADMIN_QUERIES_NAME - ? this.resourceTemplateObj.generateAdminQueriesStack(this.resourceName, authResourceName) - : this.resourceTemplateObj.generateStackResources(this.resourceName); - } - - async applyOverrides(): Promise { - const backendDir = pathManager.getBackendDirPath(); - const overrideFilePath = pathManager.getResourceDirectoryPath(undefined, AmplifyCategories.API, this.resourceName); - const overrideJSFilePath = path.join(overrideFilePath, 'build', 'override.js'); - - const isBuild = await buildOverrideDir(backendDir, overrideFilePath); - - // skip if packageManager or override.ts not found - if (isBuild) { - const { envName } = stateManager.getLocalEnvInfo(); - const { projectName } = stateManager.getProjectConfig(); - const projectInfo = { - envName, - projectName, - }; - try { - // TODO: Invoke `runOverride` from CLI core once core refactor is done, and - // this function can become async https://github.com/aws-amplify/amplify-cli/blob/7bc0b5654a585104a537c1a3f9615bd672435b58/packages/amplify-cli-core/src/overrides-manager/override-runner.ts#L4 - // before importing the override file, we should clear the require cache to avoid - // importing an outdated version of the override file - // see: https://github.com/nodejs/modules/issues/307 - // and https://stackoverflow.com/questions/9210542/node-js-require-cache-possible-to-invalidate - delete require.cache[require.resolve(overrideJSFilePath)]; - // eslint-disable-next-line import/no-dynamic-require - const overrideImport = require(overrideJSFilePath); - if (overrideImport && overrideImport?.override && typeof overrideImport?.override === 'function') { - await overrideImport.override(this.resourceTemplateObj as AmplifyApigwResourceStack, projectInfo); - } - } catch (err) { - throw new AmplifyError( - 'InvalidOverrideError', - { - message: 'Executing overrides failed.', - details: err.message, - resolution: 'There may be runtime errors in your overrides file. If so, fix the errors and try again.', - }, - err, - ); - } - } - } - - private async saveBuildFiles() { - if (this.resourceTemplateObj) { - this.cfn = JSONUtilities.parse(this.resourceTemplateObj.renderCloudFormationTemplate()); - } - - const resourceDirPath = pathManager.getResourceDirectoryPath(undefined, AmplifyCategories.API, this.resourceName); - fs.ensureDirSync(resourceDirPath); - - const buildDirPath = path.join(resourceDirPath, PathConstants.BuildDirName); - fs.ensureDirSync(buildDirPath); - - stateManager.setResourceParametersJson(undefined, AmplifyCategories.API, this.resourceName, this.cfnInputParams); - - const cfnFilePath = path.resolve(path.join(buildDirPath, `${this.resourceName}-cloudformation-template.json`)); - return writeCFNTemplate(this.cfn, cfnFilePath); - } -} - -export function convertCrudOperationsToCfnPermissions(crudOps: CrudOperation[]) { - const opMap: Record = { - [CrudOperation.CREATE]: ['/POST'], - [CrudOperation.READ]: ['/GET'], - [CrudOperation.UPDATE]: ['/PUT', '/PATCH'], - [CrudOperation.DELETE]: ['/DELETE'], - }; - return crudOps.flatMap((op) => opMap[op]); -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/index.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/index.ts deleted file mode 100644 index 7b96c26fd5..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './apigw-stack-builder'; -export * from './apigw-stack-transform'; -export * from './types'; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/types.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/types.ts deleted file mode 100644 index a1d4fd3870..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/types.ts +++ /dev/null @@ -1,53 +0,0 @@ -import * as cdk from 'aws-cdk-lib'; -import * as apigwCdk from 'aws-cdk-lib/aws-apigateway'; -import * as iamCdk from 'aws-cdk-lib/aws-iam'; - -export type ApigwInputs = { - version: number; - paths: { [pathName: string]: Path }; -}; - -export type Path = { - lambdaFunction: string; - permissions: { - setting: PermissionSetting; - auth?: CrudOperation[]; - guest?: CrudOperation[]; - groups?: { [groupName: string]: CrudOperation[] }; - }; -}; - -export enum CrudOperation { - CREATE = 'create', - READ = 'read', - UPDATE = 'update', - DELETE = 'delete', -} - -export enum PermissionSetting { - PRIVATE = 'private', - PROTECTED = 'protected', - OPEN = 'open', -} - -type AmplifyCDKL1 = { - addCfnCondition(props: cdk.CfnConditionProps, logicalId: string): void; - addCfnMapping(props: cdk.CfnMappingProps, logicalId: string): void; - addCfnOutput(props: cdk.CfnOutputProps, logicalId: string): void; - addCfnParameter(props: cdk.CfnParameterProps, logicalId: string, value?: any): void; - addCfnResource(props: cdk.CfnResourceProps, logicalId: string): void; -}; - -export type AmplifyApigwResourceTemplate = { - restApi: apigwCdk.CfnRestApi; - deploymentResource: apigwCdk.CfnDeployment; - policies?: { - [pathName: string]: ApigwPathPolicy; - }; -} & AmplifyCDKL1; - -export type ApigwPathPolicy = { - auth?: iamCdk.CfnPolicy; - guest?: iamCdk.CfnPolicy; - groups?: { [groupName: string]: iamCdk.CfnPolicy }; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/cfn-api-artifact-handler.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/cfn-api-artifact-handler.ts deleted file mode 100644 index d33a478393..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/cfn-api-artifact-handler.ts +++ /dev/null @@ -1,443 +0,0 @@ -import * as path from 'path'; -import { - $TSContext, - AmplifyError, - AmplifySupportedService, - isResourceNameUnique, - JSONUtilities, - pathManager, - stateManager, -} from '@aws-amplify/amplify-cli-core'; -import { - AddApiRequest, - AppSyncServiceConfiguration, - AppSyncServiceModification, - ConflictResolution, - ResolutionStrategy, - UpdateApiRequest, -} from 'amplify-headless-interface'; -import { printer } from '@aws-amplify/amplify-prompts'; -import * as fs from 'fs-extra'; -import { readTransformerConfiguration, TRANSFORM_CURRENT_VERSION, writeTransformerConfiguration } from 'graphql-transformer-core'; -import _ from 'lodash'; -import { v4 as uuid } from 'uuid'; -import { category } from '../../category-constants'; -import { ApiArtifactHandler, ApiArtifactHandlerOptions } from '../api-artifact-handler'; -import { AppsyncApiInputState } from './api-input-manager/appsync-api-input-state'; -import { cfnParametersFilename, gqlSchemaFilename, provider, rootAssetDir } from './aws-constants'; -import { AppSyncCLIInputs, AppSyncServiceConfig } from './service-walkthrough-types/appsync-user-input-types'; -import { authConfigHasApiKey, checkIfAuthExists, getAppSyncAuthConfig, getAppSyncResourceName } from './utils/amplify-meta-utils'; -import { appSyncAuthTypeToAuthConfig } from './utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; -import { printApiKeyWarnings } from './utils/print-api-key-warnings'; -import { conflictResolutionToResolverConfig } from './utils/resolver-config-to-conflict-resolution-bi-di-mapper'; - -// keep in sync with ServiceName in amplify-category-function, but probably it will not change -const FunctionServiceNameLambdaFunction = 'Lambda'; - -/** - * Factory function that returns an ApiArtifactHandler instance - */ -export const getCfnApiArtifactHandler = (context: $TSContext): ApiArtifactHandler => new CfnApiArtifactHandler(context); - -const resolversDirName = 'resolvers'; -const stacksDirName = 'stacks'; -const defaultStackName = 'CustomResources.json'; - -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -const defaultCfnParameters = (apiName: string) => ({ - AppSyncApiName: apiName, - DynamoDBBillingMode: 'PAY_PER_REQUEST', - DynamoDBEnableServerSideEncryption: false, -}); -class CfnApiArtifactHandler implements ApiArtifactHandler { - private readonly context: $TSContext; - - constructor(context: $TSContext) { - this.context = context; - } - - // TODO once the AddApiRequest contains multiple services this class should depend on an ApiArtifactHandler - // for each service and delegate to the correct one - createArtifacts = async (request: AddApiRequest): Promise => { - const meta = stateManager.getMeta(); - const existingApiName = getAppSyncResourceName(meta); - if (existingApiName) { - throw new AmplifyError('ResourceAlreadyExistsError', { - message: `GraphQL API ${existingApiName} already exists in the project`, - resolution: 'Use amplify update api to make modifications', - }); - } - const serviceConfig = request.serviceConfiguration; - - isResourceNameUnique('api', serviceConfig.apiName); - - const resourceDir = this.getResourceDir(serviceConfig.apiName); - - // Ensure the project directory exists and create the stacks & resolvers directories. - fs.ensureDirSync(resourceDir); - const resolverDirectoryPath = path.join(resourceDir, resolversDirName); - if (!fs.existsSync(resolverDirectoryPath)) { - fs.mkdirSync(resolverDirectoryPath); - } - const stacksDirectoryPath = path.join(resourceDir, stacksDirName); - if (!fs.existsSync(stacksDirectoryPath)) { - fs.mkdirSync(stacksDirectoryPath); - fs.copyFileSync(path.join(rootAssetDir, 'resolver-readme', 'RESOLVER_README.md'), path.join(resolverDirectoryPath, 'README.md')); - } - - // During API add, make sure we're creating a transform.conf.json file with the latest version the CLI supports. - await this.updateTransformerConfigVersion(resourceDir); - - serviceConfig.conflictResolution = await this.createResolverResources(serviceConfig.conflictResolution); - await writeResolverConfig(serviceConfig.conflictResolution, resourceDir); - - const appsyncCLIInputs = await this.generateAppsyncCLIInputs(serviceConfig); - - // Write the default custom resources stack out to disk. - fs.copyFileSync( - path.join(rootAssetDir, 'cloudformation-templates', 'defaultCustomResources.json'), - path.join(resourceDir, stacksDirName, defaultStackName), - ); - - const authConfig = this.extractAuthConfig(appsyncCLIInputs.serviceConfiguration); - const dependsOn = amendDependsOnForAuthConfig([], authConfig); - const apiParameters = this.getCfnParameters(serviceConfig.apiName, authConfig, resourceDir); - this.ensureCfnParametersExist(resourceDir, apiParameters); - this.context.amplify.updateamplifyMetaAfterResourceAdd(category, serviceConfig.apiName, this.createAmplifyMeta(authConfig, dependsOn)); - - if (serviceConfig?.transformSchema) { - // write the template buffer to the project folder - this.writeSchema(path.join(resourceDir, gqlSchemaFilename), serviceConfig.transformSchema); - - await this.context.amplify.executeProviderUtils(this.context, 'awscloudformation', 'compileSchema', { - resourceDir, - parameters: apiParameters, - authConfig, - }); - } - - return serviceConfig.apiName; - }; - - // TODO once the AddApiRequest contains multiple services this class should depend on an ApiArtifactHandler - // for each service and delegate to the correct one - updateArtifacts = async (request: UpdateApiRequest, opts?: ApiArtifactHandlerOptions): Promise => { - const updates = request.serviceModification; - const apiName = getAppSyncResourceName(stateManager.getMeta()); - if (!apiName) { - throw new AmplifyError('NotImplementedError', { - message: `${AmplifySupportedService.APPSYNC} API does not exist`, - resolution: "To add an api, use 'amplify add api'", - }); - } - const resourceDir = this.getResourceDir(apiName); - - // Because we rely on an in-place update for 'NEW' lambda conflictResolution types, we - // execute this behavior before the call to `updateAppsyncCLIInputs`. - if (updates.conflictResolution) { - updates.conflictResolution = await this.createResolverResources(updates.conflictResolution); - await writeResolverConfig(updates.conflictResolution, resourceDir); - } - - // update appsync cli-inputs - const gqlSchemaPath = await this.updateAppsyncCLIInputs(updates, apiName); - if (updates.transformSchema) { - this.writeSchema(gqlSchemaPath, updates.transformSchema); - } - - const authConfig = getAppSyncAuthConfig(stateManager.getMeta()); - const previousAuthConfig = _.cloneDeep(authConfig); - const oldConfigHadApiKey = authConfigHasApiKey(authConfig); - if (updates.defaultAuthType) { - authConfig.defaultAuthentication = appSyncAuthTypeToAuthConfig(updates.defaultAuthType); - } - if (updates.additionalAuthTypes) { - authConfig.additionalAuthenticationProviders = updates.additionalAuthTypes.map(appSyncAuthTypeToAuthConfig); - } - - if (!opts?.skipCompile) { - await this.context.amplify.executeProviderUtils(this.context, 'awscloudformation', 'compileSchema', { - resourceDir, - parameters: this.getCfnParameters(apiName, authConfig, resourceDir), - authConfig, - previousAuthConfig, - }); - } - - this.context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'output', { authConfig }); - this.context.amplify.updateBackendConfigAfterResourceUpdate(category, apiName, 'output', { authConfig }); - - const existingDependsOn = stateManager.getBackendConfig()?.[category]?.[apiName]?.dependsOn || []; - const newDependsOn = amendDependsOnForAuthConfig(existingDependsOn, authConfig); - this.context.amplify.updateBackendConfigAfterResourceUpdate(category, apiName, 'dependsOn', newDependsOn); - this.context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'dependsOn', newDependsOn); - - printApiKeyWarnings(oldConfigHadApiKey, authConfigHasApiKey(authConfig)); - }; - - private writeSchema = (resourceDir: string, schema: string): void => { - fs.writeFileSync(resourceDir, schema); - }; - - private getResourceDir = (apiName: string): string => pathManager.getResourceDirectoryPath(undefined, category, apiName); - - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type - private createAmplifyMeta = (authConfig: AuthConfig, dependsOn?: DependsOnEntry[]) => ({ - service: 'AppSync', - providerPlugin: provider, - dependsOn, - output: { - authConfig, - }, - }); - - private extractAuthConfig = (config: AppSyncServiceConfig): AuthConfig => ({ - defaultAuthentication: appSyncAuthTypeToAuthConfig(config.defaultAuthType), - additionalAuthenticationProviders: (config.additionalAuthTypes || []).map(appSyncAuthTypeToAuthConfig), - }); - - private updateTransformerConfigVersion = async (resourceDir: string): Promise => { - const localTransformerConfig = await readTransformerConfiguration(resourceDir); - localTransformerConfig.Version = TRANSFORM_CURRENT_VERSION; - localTransformerConfig.ElasticsearchWarning = true; - await writeTransformerConfiguration(resourceDir, localTransformerConfig); - }; - - private createResolverResources = async (conflictResolution: ConflictResolution = {}): Promise => { - const newConflictResolution = _.cloneDeep(conflictResolution); - - // if the strategy is a new lambda, generate the lambda and update the strategy to reference the new lambda - const generateLambdaIfNew = async (strategy: ResolutionStrategy): Promise => { - if (strategy && strategy.type === 'LAMBDA' && strategy.resolver.type === 'NEW') { - // eslint-disable-next-line no-param-reassign - strategy.resolver = { - type: 'EXISTING', - name: await this.createSyncFunction(), - }; - } - }; - await generateLambdaIfNew(newConflictResolution.defaultResolutionStrategy); - await Promise.all( - (newConflictResolution.perModelResolutionStrategy || []) - .map((perModelStrategy) => perModelStrategy.resolutionStrategy) - .map(generateLambdaIfNew), - ); - return newConflictResolution; - }; - - private getCfnParameters = (apiName: string, authConfig, resourceDir: string): Record => { - const cfnPath = path.join(resourceDir, cfnParametersFilename); - const params = JSONUtilities.readJson(cfnPath, { throwIfNotExist: false }) || defaultCfnParameters(apiName); - const cognitoPool = this.getCognitoUserPool(authConfig); - if (cognitoPool) { - params.AuthCognitoUserPoolId = cognitoPool; - } else { - delete params.AuthCognitoUserPoolId; - } - return params; - }; - - private getCognitoUserPool = (authConfig: AuthConfig): Record | undefined => { - const additionalUserPoolProvider = (authConfig.additionalAuthenticationProviders || []).find( - (aap) => aap.authenticationType === 'AMAZON_COGNITO_USER_POOLS', - ); - const defaultAuth = authConfig.defaultAuthentication; - if (!(defaultAuth?.authenticationType === 'AMAZON_COGNITO_USER_POOLS') && !additionalUserPoolProvider) { - return undefined; - } - let userPoolId; - const configuredUserPoolName = checkIfAuthExists(); - - if (authConfig.userPoolConfig) { - ({ userPoolId } = authConfig.userPoolConfig); - } else if (additionalUserPoolProvider && additionalUserPoolProvider.userPoolConfig) { - ({ userPoolId } = additionalUserPoolProvider.userPoolConfig); - } else if (configuredUserPoolName) { - userPoolId = `auth${configuredUserPoolName}`; - } else { - throw new Error('Cannot find a configured Cognito User Pool.'); - } - - return { - 'Fn::GetAtt': [userPoolId, 'Outputs.UserPoolId'], - }; - }; - - private createSyncFunction = async (): Promise => { - const targetDir = pathManager.getBackendDirPath(); - const assetDir = path.normalize(path.join(rootAssetDir, 'sync-conflict-handler')); - const [shortId] = uuid().split('-'); - - const functionName = `syncConflictHandler${shortId}`; - - const functionProps = { - functionName: `${functionName}`, - roleName: `${functionName}LambdaRole`, - }; - - const copyJobs = [ - { - dir: assetDir, - template: 'sync-conflict-handler-index.js.ejs', - target: path.join(targetDir, 'function', functionName, 'src', 'index.js'), - }, - { - dir: assetDir, - template: 'sync-conflict-handler-package.json.ejs', - target: path.join(targetDir, 'function', functionName, 'src', 'package.json'), - }, - { - dir: assetDir, - template: 'sync-conflict-handler-template.json.ejs', - target: path.join(targetDir, 'function', functionName, `${functionName}-cloudformation-template.json`), - }, - ]; - - // copy over the files - await this.context.amplify.copyBatch(this.context, copyJobs, functionProps, true); - - const backendConfigs = { - service: FunctionServiceNameLambdaFunction, - providerPlugin: provider, - build: true, - }; - - await this.context.amplify.updateamplifyMetaAfterResourceAdd('function', functionName, backendConfigs); - printer.success(`Successfully added ${functionName} function locally`); - - return `${functionName}-\${env}`; - }; - - private generateAppsyncCLIInputs = async (serviceConfig: AppSyncServiceConfiguration): Promise => { - const appsyncCLIInputs: AppSyncCLIInputs = { - version: 1, - serviceConfiguration: { - apiName: serviceConfig.apiName, - serviceName: serviceConfig.serviceName, - defaultAuthType: serviceConfig.defaultAuthType, - }, - }; - if (!_.isEmpty(serviceConfig.additionalAuthTypes)) { - appsyncCLIInputs.serviceConfiguration.additionalAuthTypes = serviceConfig.additionalAuthTypes; - } - - if (!_.isEmpty(serviceConfig.conflictResolution)) { - appsyncCLIInputs.serviceConfiguration.conflictResolution = { - defaultResolutionStrategy: serviceConfig.conflictResolution.defaultResolutionStrategy, - perModelResolutionStrategy: serviceConfig.conflictResolution.perModelResolutionStrategy, - }; - } - // deploy appsync inputs - const cliState = new AppsyncApiInputState(this.context, serviceConfig.apiName); - await cliState.saveCLIInputPayload(appsyncCLIInputs); - return appsyncCLIInputs; - }; - - private updateAppsyncCLIInputs = async (updates: AppSyncServiceModification, apiName: string) => { - const cliState = new AppsyncApiInputState(this.context, apiName); - const gqlSchemaPath = path.join(this.getResourceDir(apiName), gqlSchemaFilename); - if (!cliState.cliInputFileExists()) { - return gqlSchemaPath; - } - const prevAppsyncInputs = cliState.getCLIInputPayload(); - - const appsyncInputs: AppSyncCLIInputs = prevAppsyncInputs; - if ((appsyncInputs.serviceConfiguration as any)?.gqlSchemaPath) { - delete (appsyncInputs.serviceConfiguration as any).gqlSchemaPath; - } - if (updates.conflictResolution) { - appsyncInputs.serviceConfiguration.conflictResolution = updates.conflictResolution; - } - if (updates.defaultAuthType) { - appsyncInputs.serviceConfiguration.defaultAuthType = updates.defaultAuthType; - } - if (updates.additionalAuthTypes) { - appsyncInputs.serviceConfiguration.additionalAuthTypes = updates.additionalAuthTypes; - } - await cliState.saveCLIInputPayload(appsyncInputs); - return gqlSchemaPath; - }; - - private ensureCfnParametersExist = (resourceDir: string, parameters: Record) => { - const parametersFilePath = path.join(resourceDir, cfnParametersFilename); - if (!fs.existsSync(parametersFilePath)) { - JSONUtilities.writeJson(parametersFilePath, parameters); - } - }; -} - -/** - * This function is defined outside of the class because REST API generation uses it outside of the class above - * Long-term, the class above should be extended to also include REST API generation - * - * write to the transformer conf if the resolverConfig is valid - */ -export const writeResolverConfig = async (conflictResolution: ConflictResolution, resourceDir: string): Promise => { - const localTransformerConfig = await readTransformerConfiguration(resourceDir); - localTransformerConfig.ResolverConfig = conflictResolutionToResolverConfig(conflictResolution); - await writeTransformerConfiguration(resourceDir, localTransformerConfig); -}; - -const amendDependsOnForAuthConfig = (currentDependsOn: DependsOnEntry[], authConfig: AuthConfig): DependsOnEntry[] => { - if (hasCognitoAuthMode(authConfig)) { - return ensureDependsOnAuth(currentDependsOn); - } - return ensureNoDependsOnAuth(currentDependsOn); -}; - -const hasCognitoAuthMode = (authConfig: AuthConfig): boolean => - authConfig?.defaultAuthentication?.authenticationType === 'AMAZON_COGNITO_USER_POOLS' || - authConfig?.additionalAuthenticationProviders?.find((aap) => aap.authenticationType === 'AMAZON_COGNITO_USER_POOLS') !== undefined; - -// returns a new dependsOn array that has a single depends on auth block -const ensureDependsOnAuth = (currentDependsOn: DependsOnEntry[]): DependsOnEntry[] => { - const authResourceName = checkIfAuthExists(); - if (!authResourceName) { - return []; - } - // if dependency already exists, don't add it again - if (currentDependsOn.find((dep) => dep.category === 'auth' && dep.resourceName === authResourceName)) { - return currentDependsOn; - } - return currentDependsOn.concat({ - category: 'auth', - resourceName: authResourceName, - attributes: ['UserPoolId'], - }); -}; - -// returns a new dependsOn array that does not have a depends on auth block -const ensureNoDependsOnAuth = (currentDependsOn: DependsOnEntry[]): DependsOnEntry[] => { - const authResourceName = checkIfAuthExists(); - if (!authResourceName) { - return currentDependsOn; - } - const authIdx = currentDependsOn.findIndex((dep) => dep.category === 'auth' && dep.resourceName === authResourceName); - if (authIdx < 0) { - return currentDependsOn; - } - const newDependsOn = Array.from(currentDependsOn); - newDependsOn.splice(authIdx, 1); - return newDependsOn; -}; - -type DependsOnEntry = { - category: string; - resourceName: string; - attributes: string[]; -}; - -type AuthConfig = { - defaultAuthentication?: AuthType; - additionalAuthenticationProviders?: (AuthType & UserPoolConfig)[]; -} & UserPoolConfig; - -type UserPoolConfig = { - userPoolConfig?: { - userPoolId: string; - }; -}; - -type AuthType = { - authenticationType: string; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/containers-handler.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/containers-handler.ts deleted file mode 100644 index 7ab2f5ec46..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/containers-handler.ts +++ /dev/null @@ -1,260 +0,0 @@ -import * as path from 'path'; -import { $TSContext, createDefaultCustomPoliciesFile, pathManager } from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; -import * as fs from 'fs-extra'; -import { v4 as uuid } from 'uuid'; -import { NETWORK_STACK_LOGICAL_ID } from '../../category-constants'; -import { DEPLOYMENT_MECHANISM } from './base-api-stack'; -import { GitHubSourceActionInfo } from './pipeline-with-awaiter'; -import { API_TYPE, IMAGE_SOURCE_TYPE, ResourceDependency, ServiceConfiguration } from './service-walkthroughs/containers-walkthrough'; -import { ApiResource, generateContainersArtifacts } from './utils/containers-artifacts'; - -export const addResource = async ( - serviceWalkthroughPromise: Promise, - context: $TSContext, - category: string, - service, - options, - apiType: API_TYPE, -) => { - const walkthroughOptions = await serviceWalkthroughPromise; - - const { - resourceName, - restrictAccess, - imageSource, - gitHubPath, - gitHubToken, - deploymentMechanism, - categoryPolicies, - environmentMap, - dependsOn = [], - mutableParametersState, - } = walkthroughOptions; - const resourceDirPath = pathManager.getResourceDirectoryPath(undefined, category, resourceName); - - let [authName, updatedDependsOn] = await getResourceDependencies({ dependsOn, restrictAccess, category, resourceName, context }); - - let gitHubInfo: GitHubSourceActionInfo; - - if (deploymentMechanism === DEPLOYMENT_MECHANISM.INDENPENDENTLY_MANAGED) { - const { StackName } = context.amplify.getProjectDetails().amplifyMeta.providers['awscloudformation']; - - const secretName = `${StackName}-${category}-${resourceName}-github-token`; - const { ARN: secretArn } = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'newSecret', { - secret: gitHubToken, - description: 'GitHub OAuth token', - name: secretName, - version: secretName, - }); - - const gitHubTokenSecretArn = secretArn; - - gitHubInfo = { - path: gitHubPath, - tokenSecretArn: gitHubTokenSecretArn, - }; - } - - const build = deploymentMechanism === DEPLOYMENT_MECHANISM.FULLY_MANAGED; - - options = { - resourceName, - dependsOn: updatedDependsOn, - deploymentMechanism, - imageSource, - restrictAccess, - build, - providerPlugin: 'awscloudformation', - service: 'ElasticContainer', - gitHubInfo, - authName, - environmentMap, - categoryPolicies, - mutableParametersState, - skipHashing: false, - apiType, - iamAccessUnavailable: true, // this is because we dont support IAM access to the API yet - }; - - await context.amplify.updateamplifyMetaAfterResourceAdd(category, resourceName, options); - - const apiResource = (await context.amplify.getProjectMeta().api[resourceName]) as ApiResource; - apiResource.category = category; - - fs.ensureDirSync(resourceDirPath); - - fs.ensureDirSync(path.join(resourceDirPath, 'src')); - - if (imageSource.type === IMAGE_SOURCE_TYPE.TEMPLATE) { - fs.copySync( - path.join(__dirname, '..', '..', '..', 'resources', 'awscloudformation/container-templates', imageSource.template), - path.join(resourceDirPath, 'src'), - { recursive: true }, - ); - const { exposedContainer } = await generateContainersArtifacts(context, apiResource); - await context.amplify.updateamplifyMetaAfterResourceUpdate(category, options.resourceName, 'exposedContainer', exposedContainer); - } - - createDefaultCustomPoliciesFile(category, resourceName); - - const customPoliciesPath = pathManager.getCustomPoliciesPath(category, resourceName); - - printer.success(`Successfully added resource ${resourceName} locally.`); - printer.info(''); - printer.success('Next steps:'); - - if (deploymentMechanism === DEPLOYMENT_MECHANISM.FULLY_MANAGED) { - printer.info( - `- Place your Dockerfile, docker-compose.yml and any related container source files in "amplify/backend/api/${resourceName}/src"`, - ); - } else if (deploymentMechanism === DEPLOYMENT_MECHANISM.INDENPENDENTLY_MANAGED) { - printer.info( - `- Ensure you have the Dockerfile, docker-compose.yml and any related container source files in your Github path: ${gitHubInfo.path}`, - ); - } - - printer.info( - `- Amplify CLI infers many configuration settings from the "docker-compose.yaml" file. Learn more: docs.amplify.aws/cli/usage/containers`, - ); - printer.info(`- To access AWS resources outside of this Amplify app, edit the ${customPoliciesPath}`); - printer.info('- Run "amplify push" to build and deploy your image'); - - return resourceName; -}; - -const getResourceDependencies = async ({ - restrictAccess, - dependsOn, - context, - resourceName, - category, -}: { - restrictAccess: boolean; - dependsOn: ResourceDependency[]; - context: $TSContext; - category: string; - resourceName: string; -}) => { - let authName; - const updatedDependsOn: ResourceDependency[] = [].concat(dependsOn); - - updatedDependsOn.push({ - category: '', - resourceName: NETWORK_STACK_LOGICAL_ID, - attributes: ['ClusterName', 'VpcId', 'VpcCidrBlock', 'SubnetIds', 'VpcLinkId', 'CloudMapNamespaceId'], - }); - - if (restrictAccess) { - const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; - // getting requirement satisfaction map - const satisfiedRequirements = await context.amplify.invokePluginMethod(context, 'auth', undefined, 'checkRequirements', [ - apiRequirements, - context, - 'api', - resourceName, - ]); - // checking to see if any requirements are unsatisfied - const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); - - if (foundUnmetRequirements) { - try { - authName = await context.amplify.invokePluginMethod(context, 'auth', undefined, 'externalAuthEnable', [ - context, - 'api', - resourceName, - apiRequirements, - ]); - } catch (e) { - printer.error(e); - throw e; - } - } else { - [authName] = Object.keys(context.amplify.getProjectDetails().amplifyMeta.auth); - } - - // get auth dependency if exists to avoid duplication - const authDependency = updatedDependsOn.find((dependency) => dependency.category === 'auth'); - - if (authDependency === undefined) { - updatedDependsOn.push({ - category: 'auth', - resourceName: authName, - attributes: ['UserPoolId', 'AppClientIDWeb'], - }); - } else { - const existingAttributes = authDependency.attributes; - - const newAttributes = new Set([...existingAttributes, 'UserPoolId', 'AppClientIDWeb']); - - authDependency.attributes = Array.from(newAttributes); - } - } - return [authName, updatedDependsOn]; -}; - -export const updateResource = async (serviceWalkthroughPromise: Promise, context: $TSContext, category: string) => { - const options = await serviceWalkthroughPromise; - - const { - dependsOn, - restrictAccess, - resourceName, - gitHubPath, - gitHubToken, - gitHubInfo, - mutableParametersState, - categoryPolicies, - environmentMap, - deploymentMechanism, - } = options; - - let [authResourceName, updatedDependsOn] = await getResourceDependencies({ dependsOn, restrictAccess, category, resourceName, context }); - - let newGithubInfo: GitHubSourceActionInfo = { - path: gitHubPath, - tokenSecretArn: gitHubInfo && gitHubInfo.tokenSecretArn, - }; - if (gitHubToken) { - // #region Add token to secrets manager and get arn - const { StackName } = context.amplify.getProjectDetails().amplifyMeta.providers['awscloudformation']; - - const secretName = `${StackName}-${category}-${resourceName}-github-token`; - const { ARN: secretArn } = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'updateSecret', { - secret: gitHubToken, - description: 'GitHub OAuth token', - name: secretName, - version: uuid(), - }); - - newGithubInfo.tokenSecretArn = secretArn; - // #endregion - } - - if (deploymentMechanism === DEPLOYMENT_MECHANISM.INDENPENDENTLY_MANAGED) { - await context.amplify.updateamplifyMetaAfterResourceUpdate(category, options.resourceName, 'gitHubInfo', newGithubInfo); - } - - await context.amplify.updateamplifyMetaAfterResourceUpdate(category, options.resourceName, 'restrictAccess', restrictAccess); - await context.amplify.updateamplifyMetaAfterResourceUpdate(category, options.resourceName, 'authName', authResourceName); - await context.amplify.updateamplifyMetaAfterResourceUpdate(category, options.resourceName, 'environmentMap', environmentMap); - await context.amplify.updateamplifyMetaAfterResourceUpdate(category, options.resourceName, 'dependsOn', updatedDependsOn); - await context.amplify.updateamplifyMetaAfterResourceUpdate( - category, - options.resourceName, - 'mutableParametersState', - mutableParametersState, - ); - await context.amplify.updateamplifyMetaAfterResourceUpdate(category, options.resourceName, 'categoryPolicies', categoryPolicies); - - const apiResource = (await context.amplify.getProjectMeta().api[options.resourceName]) as ApiResource; - apiResource.category = category; - - try { - const askForExposedContainer = true; - const { exposedContainer } = await generateContainersArtifacts(context, apiResource, askForExposedContainer); - await context.amplify.updateamplifyMetaAfterResourceUpdate(category, options.resourceName, 'exposedContainer', exposedContainer); - } catch (err) { - // Best effort to create templates - } -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/convert-deprecated-apigw-paths.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/convert-deprecated-apigw-paths.ts deleted file mode 100644 index 480cbfb707..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/convert-deprecated-apigw-paths.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { JSONUtilities } from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; -import { CrudOperation, PermissionSetting } from './cdk-stack-builder/types'; - -export function convertDeperecatedRestApiPaths( - deprecatedParametersFileName: string, - deprecatedParametersFilePath: string, - resourceName: string, -) { - let deprecatedParameters: Record; - try { - deprecatedParameters = JSONUtilities.readJson>(deprecatedParametersFilePath); - } catch (e) { - printer.error(`Error reading ${deprecatedParametersFileName} file for ${resourceName} resource`); - throw e; - } - - let paths = {}; - - if (!Array.isArray(deprecatedParameters.paths) || deprecatedParameters.paths.length < 1) { - throw new Error(`Expected paths to be defined in "${deprecatedParametersFilePath}", but none found.`); - } - - deprecatedParameters.paths.forEach((path: Record) => { - let pathPermissionSetting = - path.privacy?.open === true - ? PermissionSetting.OPEN - : path.privacy?.private === true - ? PermissionSetting.PRIVATE - : PermissionSetting.PROTECTED; - - let auth; - let guest; - let groups; - // convert deprecated permissions to CRUD structure - if (typeof path.privacy?.auth === 'string' && ['r', 'rw'].includes(path.privacy.auth)) { - auth = _convertDeprecatedPermissionStringToCRUD(path.privacy.auth); - } else if (Array.isArray(path.privacy?.auth)) { - auth = _convertDeprecatedPermissionArrayToCRUD(path.privacy.auth); - } - - if (typeof path.privacy?.unauth === 'string' && ['r', 'rw'].includes(path.privacy.unauth)) { - guest = _convertDeprecatedPermissionStringToCRUD(path.privacy.unauth); - } else if (Array.isArray(path.privacy?.unauth)) { - guest = _convertDeprecatedPermissionArrayToCRUD(path.privacy.unauth); - } - - if (path.privacy?.userPoolGroups) { - groups = {}; - for (const [userPoolGroupName, crudOperations] of Object.entries(path.privacy.userPoolGroups)) { - if (typeof crudOperations === 'string' && ['r', 'rw'].includes(crudOperations)) { - groups[userPoolGroupName] = _convertDeprecatedPermissionStringToCRUD(crudOperations); - } else if (Array.isArray(crudOperations)) { - groups[userPoolGroupName] = _convertDeprecatedPermissionArrayToCRUD(crudOperations); - } - } - } - - paths[path.name] = { - permissions: { - setting: pathPermissionSetting, - auth, - guest, - groups, - }, - lambdaFunction: path.lambdaFunction, - }; - }); - - return paths; -} - -function _convertDeprecatedPermissionStringToCRUD(deprecatedPrivacy: string): CrudOperation[] { - let privacyList: CrudOperation[]; - if (deprecatedPrivacy === 'r') { - privacyList = [CrudOperation.READ]; - } else if (deprecatedPrivacy === 'rw') { - privacyList = [CrudOperation.CREATE, CrudOperation.READ, CrudOperation.UPDATE, CrudOperation.DELETE]; - } - return privacyList; -} - -function _convertDeprecatedPermissionArrayToCRUD(deprecatedPrivacyArray: string[]): CrudOperation[] { - const opMap: Record = { - '/POST': CrudOperation.CREATE, - '/GET': CrudOperation.READ, - '/PUT': CrudOperation.UPDATE, - '/PATCH': CrudOperation.UPDATE, - '/DELETE': CrudOperation.DELETE, - }; - return Array.from(new Set(deprecatedPrivacyArray.map((op) => opMap[op]))); -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/current-backend-state/searchable-node-to-node-encryption.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/current-backend-state/searchable-node-to-node-encryption.ts deleted file mode 100644 index 9d73c4bd1d..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/current-backend-state/searchable-node-to-node-encryption.ts +++ /dev/null @@ -1,78 +0,0 @@ -import * as path from 'path'; -import { ResourceConstants } from 'graphql-transformer-common'; -import * as fs from 'fs-extra'; -import { TransformConfig } from '@aws-amplify/graphql-transformer-core/lib'; -import { TRANSFORM_CONFIG_FILE_NAME } from 'graphql-transformer-core'; -import { printer } from '@aws-amplify/amplify-prompts'; -import { JSONUtilities } from '@aws-amplify/amplify-cli-core'; - -/** - * Return whether or not NodeToNodeEncryption should be enabled for the API. - * If an explicit value is set in the api configuration by the user, apply that value. - * If the #current-cloud-backend has it enabled in any stack, then leave it enabled. - * Else leave it disabled. - * @param projectDir the root directory for the project. - * @param apiName the name of the api to attempt and pull the flag from. - * @returns whether or not NodeToNodeEncryption should be enabled on a searchable instance as well as any warning message. - */ -export const shouldEnableNodeToNodeEncryption = (apiName: string, projectRoot: string, currentCloudBackendDir: string): boolean => { - try { - const nodeToNodeEncryptionParameter = getNodeToNodeEncryptionConfigValue(projectRoot, apiName); - const doesExistingBackendHaveNodeToNodeEncryption = getCurrentCloudBackendStackFiles(currentCloudBackendDir, apiName).some( - (definition) => hasNodeToNodeEncryptionOptions(definition), - ); - - warnOnExistingNodeToNodeEncryption(doesExistingBackendHaveNodeToNodeEncryption); - - if (nodeToNodeEncryptionParameter !== undefined) { - return nodeToNodeEncryptionParameter; - } - - return doesExistingBackendHaveNodeToNodeEncryption; - } catch (e) { - // Fail open, and don't set the flag for the purposes of this workaround phase. - return false; - } -}; - -const warnOnExistingNodeToNodeEncryption = (doesExistingBackendHaveNodeToNodeEncryption: boolean): void => { - if (!doesExistingBackendHaveNodeToNodeEncryption) { - return; - } - - printer.warn(` -NodeToNodeEncryption is enabled for this Search Domain, disabling this flag or reverting to Amplify CLI <= 10.5.2 will result in this being disabled, triggering a rebuild of the Search Index. To backfill your search domain see https://docs.amplify.aws/cli/graphql/troubleshooting/#backfill-opensearch-index-from-dynamodb-table. -`); -}; - -const getCurrentCloudBackendStackFiles = (currentCloudBackendDir: string, apiName: string): any[] => { - const backendPath = path.join(currentCloudBackendDir, 'api', apiName, 'build', 'stacks'); - try { - return fs.readdirSync(backendPath).map((stackFile) => JSONUtilities.readJson(path.join(backendPath, stackFile))); - } catch (e) { - return []; - } -}; - -/** - * Given a Stack file, determine whether or not NodeToNodeEncryption is defined in a search domain - * @param stackDefinition the stack to inspect - * @returns whether or not NodeToNodeEncryption was found, else false - */ -export const hasNodeToNodeEncryptionOptions = (stackDefinition: any): boolean => { - try { - const domain = stackDefinition['Resources'][ResourceConstants.RESOURCES.OpenSearchDomainLogicalID]; - const nodeToNodeEncryptionOption = domain['Properties']['NodeToNodeEncryptionOptions']['Enabled']; - return nodeToNodeEncryptionOption === true; - } catch (e) {} - return false; -}; - -const getNodeToNodeEncryptionConfigValue = (projectRoot: string, apiName: string): boolean | undefined => { - const configPath = projectRoot ? path.join(projectRoot, 'amplify', 'backend', 'api', apiName, TRANSFORM_CONFIG_FILE_NAME) : undefined; - if (configPath && fs.existsSync(configPath)) { - const config = JSON.parse(fs.readFileSync(configPath, 'utf-8')) as TransformConfig; - return config.NodeToNodeEncryption; - } - return undefined; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.ts deleted file mode 100644 index 60dbcd9da4..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { v4 as uuid } from 'uuid'; - -export const getAllDefaults = (project: { projectConfig: { projectName: string } }) => { - const name = project.projectConfig.projectName.toLowerCase().replace(/[^0-9a-zA-Z]/gi, ''); - const [shortId] = uuid().split('-'); - const defaults = { - resourceName: `api${shortId}`, - apiName: `${name}${shortId}`, - paths: [], - }; - - return defaults; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.ts deleted file mode 100644 index 001797b34d..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { $TSMeta } from '@aws-amplify/amplify-cli-core'; -import { v4 as uuid } from 'uuid'; - -export const getAllDefaults = (project: { amplifyMeta: $TSMeta; projectConfig: { projectName: string } }) => { - const name = project.projectConfig.projectName.toLowerCase(); - const region = project.amplifyMeta.providers.awscloudformation.Region; - const [shortId] = uuid().split('-'); - const defaults = { - resourceName: `appsync${shortId}`, - apiName: `${name}`, - serviceRoleName: `serviceRole${shortId}`, - servicePolicyName: `servicePolicy${shortId}`, - apiCreationChoice: false, - region, - defaultTableName: `Posts${shortId}`, - }; - - return defaults; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/containers-defaults.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/containers-defaults.ts deleted file mode 100644 index 0f77dee83e..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/containers-defaults.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { v4 as uuid } from 'uuid'; - -export const getAllDefaults = () => { - const [shortId] = uuid().split('-'); - const defaults = { - resourceName: `container${shortId}`, - }; - - return defaults; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/DockerUtils.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/DockerUtils.ts deleted file mode 100644 index c567c1b5ed..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/DockerUtils.ts +++ /dev/null @@ -1,81 +0,0 @@ -import * as yaml from 'js-yaml'; -import * as v1Types from './compose-spec/v1'; -import * as v2Types from './compose-spec/v2'; -import { BuildHashMap } from './ecs-objects/types'; - -export const dockerComposeToObject = (yamlFileContents: string): v2Types.ConfigSchemaV24Json | v1Types.ConfigSchemaV1Json => { - try { - const doc = yaml.load(yamlFileContents); - return doc as v2Types.ConfigSchemaV24Json | v1Types.ConfigSchemaV1Json; - } catch (e) { - console.log(e); - - throw e; - } -}; - -export const dockerfileToObject = (dockerfileContents: string): v2Types.ConfigSchemaV24Json | v1Types.ConfigSchemaV1Json => { - const lines = dockerfileContents?.split('\n') ?? []; - const ports = lines.filter((line) => /^\s*EXPOSE\s+/.test(line)).map((line) => line.match(/\s+(\d+)/)[1]); - - const composeContents = `version: "3" -services: - api: - build: .${ - ports.length > 0 - ? ` - ports: ${ports - .map( - (port) => ` - - '${port}:${port}'`, - ) - .join('')}` - : `` - } -`; - - return dockerComposeToObject(composeContents); -}; - -export const generateBuildSpec = (containerMap: BuildHashMap) => { - return `# Auto-Generated by Amplify. Do not modify -version: 0.2 - -phases: - install: - runtime-versions: - docker: 19 - pre_build: - commands: - - echo Logging in to Amazon ECR... - - aws --version - - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com - - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | md5sum | cut -c 1-7) - - IMAGE_TAG=\${COMMIT_HASH:=latest} - build: - commands: - - echo Build started on \`date\` - - echo Building the Docker image...${Object.keys(containerMap) - .map( - (item) => ` - - docker build -t $${item}_REPOSITORY_URI:latest ./${containerMap[item]} - - docker tag $${item}_REPOSITORY_URI:latest $${item}_REPOSITORY_URI:$IMAGE_TAG`, - ) - .join('\n')} - post_build: - commands: - - echo Build completed on \`date\` - - echo Pushing the Docker images..${Object.keys(containerMap) - .map( - (item) => ` - - docker push $${item}_REPOSITORY_URI:latest - - docker push $${item}_REPOSITORY_URI:$IMAGE_TAG`, - ) - .join('\n')} - - "echo \\"[${Object.keys(containerMap) - .map((name) => `{\\\\\\\"name\\\\\\\":\\\\\\\"${name}\\\\\\\", \\\\\\\"imageUri\\\\\\\":\\\\\\\"$${name}_REPOSITORY_URI\\\\\\\"}`) - .join(',')}]\\" > imagedefinitions.json" -artifacts: - files: imagedefinitions.json -`; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v1.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v1.ts deleted file mode 100644 index 771160d6cd..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v1.ts +++ /dev/null @@ -1,103 +0,0 @@ -/** - * This file was automatically generated by json-schema-to-typescript. - * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, - * and run json-schema-to-typescript to regenerate this file. - */ - -export type StringOrList = string | ListOfStrings; -export type ListOfStrings = string[]; -export type ListOrDict = - | { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` ".+". - */ - [k: string]: string | number | null; - } - | string[]; -export type Labels = - | { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` ".+". - */ - [k: string]: string; - } - | string[]; - -export interface ConfigSchemaV1Json { - [k: string]: DefinitionsService; -} -/** - * This interface was referenced by `ConfigSchemaV1Json`'s JSON-Schema definition - * via the `patternProperty` "^[a-zA-Z0-9._-]+$". - */ -export interface DefinitionsService { - build?: string; - cap_add?: string[]; - cap_drop?: string[]; - cgroup_parent?: string; - command?: string | string[]; - container_name?: string; - cpu_shares?: number | string; - cpu_quota?: number | string; - cpuset?: string; - devices?: string[]; - dns?: StringOrList; - dns_search?: StringOrList; - dockerfile?: string; - domainname?: string; - entrypoint?: string | string[]; - env_file?: StringOrList; - environment?: ListOrDict; - expose?: (string | number)[]; - extends?: - | string - | { - service: string; - file?: string; - }; - extra_hosts?: ListOrDict; - external_links?: string[]; - hostname?: string; - image?: string; - ipc?: string; - labels?: Labels; - links?: string[]; - log_driver?: string; - log_opt?: { - [k: string]: any; - }; - mac_address?: string; - mem_limit?: number | string; - memswap_limit?: number | string; - mem_swappiness?: number; - net?: string; - pid?: string | null; - ports?: (string | number)[]; - privileged?: boolean; - read_only?: boolean; - restart?: string; - security_opt?: string[]; - shm_size?: number | string; - stdin_open?: boolean; - stop_signal?: string; - tty?: boolean; - ulimits?: { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^[a-z]+$". - */ - [k: string]: - | number - | { - hard: number; - soft: number; - }; - }; - user?: string; - volumes?: string[]; - volume_driver?: string; - volumes_from?: string[]; - working_dir?: string; -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v2.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v2.ts deleted file mode 100644 index a16b147f4d..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v2.ts +++ /dev/null @@ -1,294 +0,0 @@ -/** - * This file was automatically generated by json-schema-to-typescript. - * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, - * and run json-schema-to-typescript to regenerate this file. - */ - -export type ListOrDict = - | { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` ".+". - */ - [k: string]: string | number | null; - } - | string[]; -export type Labels = - | { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` ".+". - */ - [k: string]: string; - } - | string[]; -export type ListOfStrings = string[]; -export type StringOrList = string | ListOfStrings; -/** - * This interface was referenced by `PropertiesVolumes`'s JSON-Schema definition - * via the `patternProperty` "^[a-zA-Z0-9._-]+$". - */ -export type DefinitionsVolume = { - [k: string]: any; -} | null; - -export interface ConfigSchemaV24Json { - version?: string; - services?: PropertiesServices; - networks?: PropertiesNetworks; - volumes?: PropertiesVolumes; - /** - * This interface was referenced by `ConfigSchemaV24Json`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: any; -} -export interface PropertiesServices { - [k: string]: DefinitionsService; -} -/** - * This interface was referenced by `PropertiesServices`'s JSON-Schema definition - * via the `patternProperty` "^[a-zA-Z0-9._-]+$". - */ -export interface DefinitionsService { - blkio_config?: { - device_read_bps?: BlkioLimit[]; - device_read_iops?: BlkioLimit[]; - device_write_bps?: BlkioLimit[]; - device_write_iops?: BlkioLimit[]; - weight?: number; - weight_device?: BlkioWeight[]; - }; - build?: - | string - | { - context?: string; - dockerfile?: string; - args?: ListOrDict; - labels?: Labels; - cache_from?: ListOfStrings; - network?: string; - target?: string; - shm_size?: number | string; - extra_hosts?: ListOrDict; - isolation?: string; - }; - cap_add?: ListOfStrings; - cap_drop?: ListOfStrings; - cgroup_parent?: string; - command?: string | string[]; - container_name?: string; - cpu_count?: number; - cpu_percent?: number; - cpu_shares?: number | string; - cpu_quota?: number | string; - cpu_period?: number | string; - cpu_rt_period?: number | string; - cpu_rt_runtime?: number | string; - cpus?: number; - cpuset?: string; - depends_on?: - | ListOfStrings - | { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^[a-zA-Z0-9._-]+$". - */ - [k: string]: { - condition: 'service_started' | 'service_healthy'; - }; - }; - device_cgroup_rules?: ListOfStrings; - devices?: ListOfStrings; - dns_opt?: string[]; - dns?: StringOrList; - dns_search?: StringOrList; - domainname?: string; - entrypoint?: string | string[]; - env_file?: StringOrList; - environment?: ListOrDict; - expose?: (string | number)[]; - extends?: - | string - | { - service: string; - file?: string; - }; - external_links?: ListOfStrings; - extra_hosts?: ListOrDict; - group_add?: (string | number)[]; - healthcheck?: DefinitionsHealthcheck; - hostname?: string; - image?: string; - init?: boolean | string; - ipc?: string; - isolation?: string; - labels?: Labels; - links?: ListOfStrings; - logging?: { - driver?: string; - options?: { - [k: string]: any; - }; - }; - mac_address?: string; - mem_limit?: number | string; - mem_reservation?: string | number; - mem_swappiness?: number; - memswap_limit?: number | string; - network_mode?: string; - networks?: - | ListOfStrings - | { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^[a-zA-Z0-9._-]+$". - */ - [k: string]: { - aliases?: ListOfStrings; - ipv4_address?: string; - ipv6_address?: string; - link_local_ips?: ListOfStrings; - priority?: number; - } | null; - }; - oom_kill_disable?: boolean; - oom_score_adj?: number; - pid?: string | null; - platform?: string; - ports?: (string | number)[]; - privileged?: boolean; - read_only?: boolean; - restart?: string; - runtime?: string; - scale?: number; - security_opt?: ListOfStrings; - shm_size?: number | string; - sysctls?: ListOrDict; - pids_limit?: number | string; - stdin_open?: boolean; - stop_grace_period?: string; - stop_signal?: string; - storage_opt?: { - [k: string]: any; - }; - tmpfs?: StringOrList; - tty?: boolean; - ulimits?: { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^[a-z]+$". - */ - [k: string]: - | number - | { - hard: number; - soft: number; - }; - }; - user?: string; - userns_mode?: string; - volumes?: ( - | string - | { - type: string; - source?: string; - target?: string; - read_only?: boolean; - consistency?: string; - bind?: { - propagation?: string; - [k: string]: any; - }; - volume?: { - nocopy?: boolean; - [k: string]: any; - }; - tmpfs?: { - size?: number | string; - [k: string]: any; - }; - } - )[]; - volume_driver?: string; - volumes_from?: ListOfStrings; - working_dir?: string; - /** - * This interface was referenced by `DefinitionsService`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: any; -} -export interface BlkioLimit { - path?: string; - rate?: number | string; -} -export interface BlkioWeight { - path?: string; - weight?: number; -} -export interface DefinitionsHealthcheck { - disable?: boolean; - interval?: string; - retries?: number; - start_period?: string; - test?: string | string[]; - timeout?: string; -} -export interface PropertiesNetworks { - [k: string]: DefinitionsNetwork; -} -/** - * This interface was referenced by `PropertiesNetworks`'s JSON-Schema definition - * via the `patternProperty` "^[a-zA-Z0-9._-]+$". - */ -export interface DefinitionsNetwork { - driver?: string; - driver_opts?: { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^.+$". - */ - [k: string]: string | number; - }; - ipam?: { - driver?: string; - config?: DefinitionsIpamConfig[]; - options?: { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^.+$". - */ - [k: string]: string; - }; - }; - external?: - | boolean - | { - [k: string]: any; - }; - internal?: boolean; - enable_ipv6?: boolean; - labels?: Labels; - name?: string; - /** - * This interface was referenced by `DefinitionsNetwork`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: any; -} -export interface DefinitionsIpamConfig { - subnet?: string; - ip_range?: string; - gateway?: string; - aux_addresses?: { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^.+$". - */ - [k: string]: string; - }; -} -export interface PropertiesVolumes { - [k: string]: DefinitionsVolume; -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v3.8.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v3.8.ts deleted file mode 100644 index 81cd2529eb..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v3.8.ts +++ /dev/null @@ -1,596 +0,0 @@ -/* tslint:disable */ -/** - * This file was automatically generated by json-schema-to-typescript. - * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, - * and run json-schema-to-typescript to regenerate this file. - */ - -export type DefinitionsDeployment2 = DefinitionsDeployment | DefinitionsDeployment1; -export type ListOrDict = - | { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` ".+". - */ - [k: string]: string | number | null; - } - | string[]; -export type DefinitionsGenericResources = { - discrete_resource_spec?: { - kind?: string; - value?: number; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; -}[]; -export type DefinitionsDeployment1 = null; -export type ListOfStrings = string[]; -export type StringOrList = string | ListOfStrings; -/** - * This interface was referenced by `PropertiesNetworks`'s JSON-Schema definition - * via the `patternProperty` "^[a-zA-Z0-9._-]+$". - */ -export type DefinitionsNetwork2 = DefinitionsNetwork | DefinitionsNetwork1; -export type DefinitionsNetwork1 = null; -/** - * This interface was referenced by `PropertiesVolumes`'s JSON-Schema definition - * via the `patternProperty` "^[a-zA-Z0-9._-]+$". - */ -export type DefinitionsVolume2 = DefinitionsVolume | DefinitionsVolume1; -export type DefinitionsVolume1 = null; - -/** - * The Compose file is a YAML file defining a multi-containers based application. - */ -export interface ComposeSpecification { - /** - * Version of the Compose specification used. Tools not implementing required version MUST reject the configuration file. - */ - version?: string; - services?: PropertiesServices; - networks?: PropertiesNetworks; - volumes?: PropertiesVolumes; - secrets?: PropertiesSecrets; - configs?: PropertiesConfigs; - /** - * This interface was referenced by `ComposeSpecification`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; -} -export interface PropertiesServices { - [k: string]: DefinitionsService; -} -/** - * This interface was referenced by `PropertiesServices`'s JSON-Schema definition - * via the `patternProperty` "^[a-zA-Z0-9._-]+$". - */ -export interface DefinitionsService { - deploy?: DefinitionsDeployment2; - build?: - | string - | { - context?: string; - dockerfile?: string; - args?: ListOrDict; - labels?: ListOrDict; - cache_from?: ListOfStrings; - network?: string; - target?: string; - shm_size?: number | string; - extra_hosts?: ListOrDict; - isolation?: string; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - blkio_config?: { - device_read_bps?: BlkioLimit[]; - device_read_iops?: BlkioLimit[]; - device_write_bps?: BlkioLimit[]; - device_write_iops?: BlkioLimit[]; - weight?: number; - weight_device?: BlkioWeight[]; - }; - cap_add?: string[]; - cap_drop?: string[]; - cgroup_parent?: string; - command?: string | string[]; - configs?: ( - | string - | { - source?: string; - target?: string; - uid?: string; - gid?: string; - mode?: number; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - } - )[]; - container_name?: string; - cpu_count?: number; - cpu_percent?: number; - cpu_shares?: number | string; - cpu_quota?: number | string; - cpu_period?: number | string; - cpu_rt_period?: number | string; - cpu_rt_runtime?: number | string; - cpus?: number | string; - cpuset?: string; - credential_spec?: { - config?: string; - file?: string; - registry?: string; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - depends_on?: - | ListOfStrings - | { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^[a-zA-Z0-9._-]+$". - */ - [k: string]: { - condition: 'service_started' | 'service_healthy'; - }; - }; - device_cgroup_rules?: ListOfStrings; - devices?: string[]; - dns?: StringOrList; - dns_opt?: string[]; - dns_search?: StringOrList; - domainname?: string; - entrypoint?: string | string[]; - env_file?: StringOrList; - environment?: ListOrDict; - expose?: (string | number)[]; - extends?: - | string - | { - service: string; - file?: string; - }; - external_links?: string[]; - extra_hosts?: ListOrDict; - group_add?: (string | number)[]; - healthcheck?: DefinitionsHealthcheck; - hostname?: string; - image?: string; - init?: boolean; - ipc?: string; - isolation?: string; - labels?: ListOrDict; - links?: string[]; - logging?: { - driver?: string; - options?: { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^.+$". - */ - [k: string]: string | number | null; - }; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - mac_address?: string; - mem_limit?: string; - mem_reservation?: string | number; - mem_swappiness?: number; - memswap_limit?: number | string; - network_mode?: string; - networks?: - | ListOfStrings - | { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^[a-zA-Z0-9._-]+$". - */ - [k: string]: { - aliases?: ListOfStrings; - ipv4_address?: string; - ipv6_address?: string; - link_local_ips?: ListOfStrings; - priority?: number; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - } | null; - }; - oom_kill_disable?: boolean; - oom_score_adj?: number; - pid?: string | null; - pids_limit?: number | string; - platform?: string; - ports?: ( - | number - | string - | { - mode?: string; - target?: number; - published?: number; - protocol?: string; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - } - )[]; - privileged?: boolean; - pull_policy?: 'always' | 'never' | 'if_not_present'; - read_only?: boolean; - restart?: string; - runtime?: string; - scale?: number; - security_opt?: string[]; - shm_size?: number | string; - secrets?: ( - | string - | { - source?: string; - target?: string; - uid?: string; - gid?: string; - mode?: number; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - } - )[]; - sysctls?: ListOrDict; - stdin_open?: boolean; - stop_grace_period?: string; - stop_signal?: string; - tmpfs?: StringOrList; - tty?: boolean; - ulimits?: { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^[a-z]+$". - */ - [k: string]: - | number - | { - hard: number; - soft: number; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - }; - user?: string; - userns_mode?: string; - volumes?: ( - | string - | { - type: string; - source?: string; - target?: string; - read_only?: boolean; - consistency?: string; - bind?: { - propagation?: string; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - volume?: { - nocopy?: boolean; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - tmpfs?: { - size?: number; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - } - )[]; - volumes_from?: string[]; - working_dir?: string; - /** - * This interface was referenced by `DefinitionsService`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; -} -export interface DefinitionsDeployment { - mode?: string; - endpoint_mode?: string; - replicas?: number; - labels?: ListOrDict; - rollback_config?: { - parallelism?: number; - delay?: string; - failure_action?: string; - monitor?: string; - max_failure_ratio?: number; - order?: 'start-first' | 'stop-first'; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - update_config?: { - parallelism?: number; - delay?: string; - failure_action?: string; - monitor?: string; - max_failure_ratio?: number; - order?: 'start-first' | 'stop-first'; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - resources?: { - limits?: { - cpus?: number | string; - memory?: string; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - reservations?: { - cpus?: number | string; - memory?: string; - generic_resources?: DefinitionsGenericResources; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - restart_policy?: { - condition?: string; - delay?: string; - max_attempts?: number; - window?: string; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - placement?: { - constraints?: string[]; - preferences?: { - spread?: string; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }[]; - max_replicas_per_node?: number; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - /** - * This interface was referenced by `DefinitionsDeployment`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; -} -export interface BlkioLimit { - path?: string; - rate?: number | string; -} -export interface BlkioWeight { - path?: string; - weight?: number; -} -export interface DefinitionsHealthcheck { - disable?: boolean; - interval?: string; - retries?: number; - test?: string | string[]; - timeout?: string; - start_period?: string; - /** - * This interface was referenced by `DefinitionsHealthcheck`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; -} -export interface PropertiesNetworks { - [k: string]: DefinitionsNetwork2; -} -export interface DefinitionsNetwork { - name?: string; - driver?: string; - driver_opts?: { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^.+$". - */ - [k: string]: string | number; - }; - ipam?: { - driver?: string; - config?: { - subnet?: string; - ip_range?: string; - gateway?: string; - aux_addresses?: { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^.+$". - */ - [k: string]: string; - }; - [k: string]: unknown; - }[]; - options?: { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^.+$". - */ - [k: string]: string; - }; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - external?: - | boolean - | { - name?: string; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - internal?: boolean; - enable_ipv6?: boolean; - attachable?: boolean; - labels?: ListOrDict; - /** - * This interface was referenced by `DefinitionsNetwork`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; -} -export interface PropertiesVolumes { - [k: string]: DefinitionsVolume2; -} -export interface DefinitionsVolume { - name?: string; - driver?: string; - driver_opts?: { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^.+$". - */ - [k: string]: string | number; - }; - external?: - | boolean - | { - name?: string; - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; - }; - labels?: ListOrDict; - /** - * This interface was referenced by `DefinitionsVolume`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; -} -export interface PropertiesSecrets { - [k: string]: DefinitionsSecret; -} -/** - * This interface was referenced by `PropertiesSecrets`'s JSON-Schema definition - * via the `patternProperty` "^[a-zA-Z0-9._-]+$". - */ -export interface DefinitionsSecret { - name?: string; - file?: string; - external?: - | boolean - | { - name?: string; - [k: string]: unknown; - }; - labels?: ListOrDict; - driver?: string; - driver_opts?: { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^.+$". - */ - [k: string]: string | number; - }; - template_driver?: string; - /** - * This interface was referenced by `DefinitionsSecret`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; -} -export interface PropertiesConfigs { - [k: string]: DefinitionsConfig; -} -/** - * This interface was referenced by `PropertiesConfigs`'s JSON-Schema definition - * via the `patternProperty` "^[a-zA-Z0-9._-]+$". - */ -export interface DefinitionsConfig { - name?: string; - file?: string; - external?: - | boolean - | { - name?: string; - [k: string]: unknown; - }; - labels?: ListOrDict; - template_driver?: string; - /** - * This interface was referenced by `DefinitionsConfig`'s JSON-Schema definition - * via the `patternProperty` "^x-". - */ - [k: string]: unknown; -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v3.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v3.ts deleted file mode 100644 index 605b7e86ec..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v3.ts +++ /dev/null @@ -1,156 +0,0 @@ -/** - * This file was automatically generated by json-schema-to-typescript. - * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, - * and run json-schema-to-typescript to regenerate this file. - */ - -export type DefinitionsDeployment = { - [k: string]: any; -} | null; -export type ListOrDict = - | { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` ".+". - */ - [k: string]: string | number | null; - } - | string[]; -export type ListOfStrings = string[]; -export type StringOrList = string | ListOfStrings; -export type Labels = - | { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` ".+". - */ - [k: string]: string; - } - | string[]; -/** - * This interface was referenced by `PropertiesNetworks`'s JSON-Schema definition - * via the `patternProperty` "^[a-zA-Z0-9._-]+$". - */ -export type DefinitionsNetwork = { - [k: string]: any; -} | null; -/** - * This interface was referenced by `PropertiesVolumes`'s JSON-Schema definition - * via the `patternProperty` "^[a-zA-Z0-9._-]+$". - */ -export type DefinitionsVolume = { - [k: string]: any; -} | null; - -export interface ConfigSchemaV30Json { - version: string; - services?: PropertiesServices; - networks?: PropertiesNetworks; - volumes?: PropertiesVolumes; -} -export interface PropertiesServices { - [k: string]: DefinitionsService; -} -/** - * This interface was referenced by `PropertiesServices`'s JSON-Schema definition - * via the `patternProperty` "^[a-zA-Z0-9._-]+$". - */ -export interface DefinitionsService { - deploy?: DefinitionsDeployment; - build?: - | string - | { - context?: string; - dockerfile?: string; - args?: ListOrDict; - }; - cap_add?: string[]; - cap_drop?: string[]; - cgroup_parent?: string; - command?: string | string[]; - container_name?: string; - depends_on?: ListOfStrings; - devices?: string[]; - dns?: StringOrList; - dns_search?: StringOrList; - domainname?: string; - entrypoint?: string | string[]; - env_file?: StringOrList; - environment?: ListOrDict; - expose?: (string | number)[]; - external_links?: string[]; - extra_hosts?: ListOrDict; - healthcheck?: DefinitionsHealthcheck; - hostname?: string; - image?: string; - ipc?: string; - labels?: Labels; - links?: string[]; - logging?: { - driver?: string; - options?: { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^.+$". - */ - [k: string]: string | number | null; - }; - }; - mac_address?: string; - network_mode?: string; - networks?: - | ListOfStrings - | { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^[a-zA-Z0-9._-]+$". - */ - [k: string]: { - aliases?: ListOfStrings; - ipv4_address?: string; - ipv6_address?: string; - } | null; - }; - pid?: string | null; - ports?: (string | number)[]; - privileged?: boolean; - read_only?: boolean; - restart?: string; - security_opt?: string[]; - shm_size?: number | string; - sysctls?: ListOrDict; - stdin_open?: boolean; - stop_grace_period?: string; - stop_signal?: string; - tmpfs?: StringOrList; - tty?: boolean; - ulimits?: { - /** - * This interface was referenced by `undefined`'s JSON-Schema definition - * via the `patternProperty` "^[a-z]+$". - */ - [k: string]: - | number - | { - hard: number; - soft: number; - }; - }; - user?: string; - userns_mode?: string; - volumes?: string[]; - working_dir?: string; -} -export interface DefinitionsHealthcheck { - disable?: boolean; - interval?: string; - retries?: number; - test?: string | string[]; - timeout?: string; -} -export interface PropertiesNetworks { - [k: string]: DefinitionsNetwork; -} -export interface PropertiesVolumes { - [k: string]: DefinitionsVolume; -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/converter.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/converter.ts deleted file mode 100644 index 87158916b1..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/converter.ts +++ /dev/null @@ -1,171 +0,0 @@ -import * as v1Types from './compose-spec/v1'; -import * as v2Types from './compose-spec/v2'; -import * as v38Types from './compose-spec/v3.8'; -import { dockerComposeToObject, dockerfileToObject, generateBuildSpec } from './DockerUtils'; -import Container from './ecs-objects/container'; -import { BuildHashMap, PortMappings } from './ecs-objects/types'; - -const isv1Schema = (obj: any): obj is v1Types.ConfigSchemaV1Json => { - return obj && obj.version === undefined; -}; - -const hasHealthCheck = (obj: any): obj is v2Types.DefinitionsHealthcheck => { - return obj.healthcheck !== undefined; -}; - -function isV38Service(obj: any): obj is v38Types.DefinitionsService { - return obj && (obj).secrets !== undefined; -} -const mapComposeEntriesToContainer = (record: [string, v1Types.DefinitionsService | v2Types.DefinitionsService]): Container => { - const [k, v] = record; - - const { image, ports, build, command, entrypoint, env_file, environment, working_dir, user } = v; - const { container_name: name = k } = v; - - let healthcheck: v2Types.DefinitionsHealthcheck = {}; - if (hasHealthCheck(v)) { - Object.entries(v).forEach((item: [string, v2Types.DefinitionsHealthcheck]) => { - const [, healthVal] = item; - if (healthVal.test !== undefined) { - healthcheck = healthVal; - } - }); - } - - let portArray: PortMappings = []; - ports?.forEach((item) => { - // For task definitions that use the awsvpc network mode, you should only specify the containerPort. - // The hostPort can be left blank or it must be the same value as the containerPort. - const [containerPort, hostPort = containerPort] = item.toString().split(':'); - - portArray.push({ - containerPort: parseInt(containerPort, 10), - hostPort: parseInt(hostPort, 10), - protocol: 'tcp', - }); - }); - - const secrets = new Set(); - if (isV38Service(v)) { - v.secrets.filter((s) => typeof s === 'string').forEach((s) => secrets.add(s)); - } - - return new Container( - build, - name, - portArray, - command, - entrypoint, - env_file, - environment, - image, - { - command: healthcheck.test, - ...healthcheck, - }, - working_dir, - user, - secrets, - ); -}; - -const convertDockerObjectToContainerArray = (yamlObject: v2Types.ConfigSchemaV24Json | v1Types.ConfigSchemaV1Json) => { - let containerArr: Container[] = []; - - if (isv1Schema(yamlObject)) { - Object.entries(yamlObject).forEach((record: [string, v1Types.DefinitionsService]) => { - const container = mapComposeEntriesToContainer(record); - containerArr.push(container); - }); - } else { - Object.entries(yamlObject.services ?? {}).forEach((record: [string, v2Types.DefinitionsService]) => { - const container = mapComposeEntriesToContainer(record); - containerArr.push(container); - }); - } - return containerArr; -}; - -const findServiceDeployment = ( - yamlObject: v38Types.ComposeSpecification | v2Types.ConfigSchemaV24Json | v1Types.ConfigSchemaV1Json, -): v38Types.DefinitionsDeployment2 => { - let result: v38Types.DefinitionsDeployment2 = {}; - - Object.entries(yamlObject.services ?? {}).forEach((record: [string, v38Types.DefinitionsService]) => { - const [, v] = record; - const { deploy } = v; - - if (deploy !== undefined) { - // TODO: This is returning the deploy obj of the last service that had it, it should probably be an array - result = deploy!; - } - }); - - return result; -}; - -type DockerServiceInfo = { - buildspec: string; - service: v38Types.DefinitionsDeployment; - containers: Container[]; - secrets: Record; -}; -export function getContainers(composeContents?: string, dockerfileContents?: string): DockerServiceInfo { - // Step 1: Detect if there is a docker-compose or just a Dockerfile. - // Just Dockerfile-> create registry using function name, buildspec, zip and put on S3 - // Compose file -> Begin by parsing it: - const dockerCompose = composeContents ? dockerComposeToObject(composeContents) : dockerfileToObject(dockerfileContents); - - const secrets: Record = {}; - - const { secrets: composeSecrets = {} }: { secrets?: v38Types.PropertiesSecrets } = dockerCompose; - - for (const secretName of Object.keys(composeSecrets)) { - if (composeSecrets[secretName].file) { - secrets[composeSecrets[secretName].name ?? secretName] = composeSecrets[secretName].file; - } - } - - // Step 2: Take compose object and pull all the containers out: - const containers = convertDockerObjectToContainerArray(dockerCompose); - - // Step 3: Populate Build mapping for creation of the buildpsec - const buildmapping: BuildHashMap = {}; - containers.forEach((res) => { - if (typeof res.build === 'object') { - // console.log(res.build.args); - } - if (typeof res.healthcheck === 'object') { - // console.log(res.healthcheck.command) - } - // Step 4: Create ECR Entry if build is specified - TODO with Francisco..... - this will go in registryArn - if (res.build != undefined) { - let buildContext: string = ''; - - if (typeof res.build === 'object') { - buildContext = res.build.context!; - } else { - buildContext = res.build; - } - - // Wont need this if statement later, just using for testing - /** This will look like this for each container where res.build != undefined: - * let registryArn = new ecr.Repository(this, res.name, {}); - * buildmapping[res.name] = {buildPath: buildContext, registryArn }; - */ - buildmapping[res.name] = buildContext; - } - }); - - // Step 5: Generate the buildfiles - const buildspec = generateBuildSpec(buildmapping); - - const service = findServiceDeployment(dockerCompose); - - return { - buildspec, - service, - containers, - secrets, - }; -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/container.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/container.ts deleted file mode 100644 index 4a2456c37c..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/container.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { ListOrDict } from '../compose-spec/v1'; -import { IContainerDefinitions, PortMappings, IBuildConfig, ContainerHealthCheck, IContainerHealthCheckItem } from './types'; - -class Container implements IContainerDefinitions { - readonly defaultLogConfiguration = { - logDriver: 'awslogs', - options: { - 'awslogs-stream-prefix': 'ecs', // use cluster name - }, - }; - - build: string | IBuildConfig | undefined; - - name: string; - - portMappings: PortMappings; - - logConfiguration = this.defaultLogConfiguration; - - command?: string[]; - - entrypoint?: string[]; - - env_file?: string[]; - - environment?: Record; - - image?: string; - - healthcheck?: ContainerHealthCheck; - - working_dir?: string; - - user?: string; - - secrets: Set; - - constructor( - build: string | IBuildConfig | undefined, // Really for CodeBuild. Do we need in this class? - name: string, - portMappings: PortMappings, - command?: string | string[] | undefined, - entrypoint?: string | string[] | undefined, - env_file?: string | string[] | undefined, - environment?: ListOrDict | undefined, - image?: string | undefined, - healthcheck?: IContainerHealthCheckItem | undefined, - working_dir?: string | undefined, - user?: string | undefined, - secrets?: Set | undefined, - ) { - this.build = build; - this.name = name; - this.portMappings = portMappings; - this.command = [].concat(command); - this.entrypoint = [].concat(entrypoint); - this.env_file = [].concat(env_file); - this.environment = Array.isArray(environment) - ? environment.reduce((acc, element) => { - const [key, value] = element.split('='); - - acc[key] = value; - return acc; - }, {} as Record) - : (environment as Record); - this.image = image; - - this.healthcheck = (({ interval, command, start_period, timeout, retries }) => - command - ? { - interval: toSeconds(interval), - command: [].concat(command), - start_period: toSeconds(start_period), - timeout: toSeconds(timeout), - retries, - } - : undefined)(healthcheck); - - this.working_dir = working_dir; - this.user = user; - this.secrets = secrets ?? new Set(); - } -} - -function toSeconds(str: string | number): number { - const [, seconds] = `${str}`.match(/^(\d+)s\s*$/) || []; - - if (seconds === undefined) { - return undefined; - } - - return parseInt(seconds, 10); -} - -export default Container; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/service.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/service.ts deleted file mode 100644 index 73e02c87cd..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/service.ts +++ /dev/null @@ -1,75 +0,0 @@ -import * as v38Types from '../compose-spec/v3.8'; -import { IServiceDefinition, ServiceHealthCheck, DeploymentConfiguration, ContainerConfig, TaskConfig } from './types'; -import Container from './container'; - -// ALB Healthcheck, should be overriden by CLI command -const DEFAULT_API_HEALTHCHECK = { - path: '/', - port: 443, -}; - -/* This will ensure that there is always at least 1 task running during deployment - */ -const DEFAULT_SERVICE_DEPLYMENT_CONFIG = { - MaximumPercent: 200, - MinimumHealthyPercent: 100, -}; -const DEFAULT_DESIRED_COUNT = 1; // Should this be 3? - -const DEFAULT_TASK_MEMORY_CPU = { - memory: 1, // In GB: .5, 1, 2, ...6 - vCPU: 1, // 0.25, .5, 1, 2, ...4 -}; - -const DEFAULT_CONTAINER_MEMORY_MAX = 1024; -const DEFAULT_CPU_UNIT_RESERVATION = DEFAULT_CONTAINER_MEMORY_MAX * 0.1; // Do we even need this? -const DEFAULT_CONTAINER_MEMORY_CPU = { - memory: DEFAULT_CONTAINER_MEMORY_MAX, - cpu: DEFAULT_CPU_UNIT_RESERVATION, -}; - -class Service implements IServiceDefinition { - containers: Container[] = []; - - apiHealthcheck?: ServiceHealthCheck; - - taskResources: TaskConfig = DEFAULT_TASK_MEMORY_CPU; - - containerResources: ContainerConfig = DEFAULT_CONTAINER_MEMORY_CPU; - - deploymentConfiguration: DeploymentConfiguration = DEFAULT_SERVICE_DEPLYMENT_CONFIG; - - desiredCount: number = DEFAULT_DESIRED_COUNT; - - constructor( - containers: Container[], - apiHealthcheck: ServiceHealthCheck = DEFAULT_API_HEALTHCHECK, - dockerDeploymentConfig?: v38Types.DefinitionsDeployment2, - ) { - containers.forEach((instance) => { - this.containers.push(instance); - }); - - this.apiHealthcheck = apiHealthcheck; // Potentially exposed via CLI inputs, not Docker Compose - - // Docker compose optional inputs// - - /* SERVICE-specific settings*/ - dockerDeploymentConfig?.replicas !== undefined && (this.desiredCount = dockerDeploymentConfig?.replicas); // Main control, replica ~= task count - - dockerDeploymentConfig?.placement?.max_replicas_per_node !== undefined && - (this.deploymentConfiguration.MaximumPercent = dockerDeploymentConfig?.placement?.max_replicas_per_node); - - /* CONTAINER-specific settings*/ - // ECS recommends 300-500 MiB as a starting point for web applications. - dockerDeploymentConfig?.resources?.limits?.memory !== undefined && - (this.containerResources.memory = dockerDeploymentConfig?.resources?.limits?.memory.slice(0, -1) as unknown as number); - - // Note: when you don’t specify any CPU units for a container - // ECS intrinsically enforces two Linux CPU shares for the cgroup (which is the minimum allowed). - dockerDeploymentConfig?.resources?.limits?.cpus !== undefined && - (this.containerResources.cpu = dockerDeploymentConfig?.resources?.reservations?.cpus as number); - } -} - -export default Service; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/types.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/types.ts deleted file mode 100644 index 4f844a78e0..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/types.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { ListOrDict } from '../compose-spec/v2'; - -export interface IServiceDefinition { - containers: IContainerDefinitions[]; - cpu?: number | string; - memory?: number | string; - tags?: string[]; -} - -export type ContainerHealthCheck = { - command?: string[]; - interval?: number; - retries?: number; - start_period?: number; - timeout?: number; -}; - -export interface IContainerDefinitions { - build: string | IBuildConfig | undefined; - image?: string; - name: string; - // entrypoint?: string | string[] | undefined; - logConfiguration: ILogConfiguration; - portMappings: PortMappings; - - command?: string[] | undefined; - entrypoint?: string[] | undefined; - env_file?: string[] | undefined; - environment?: Record | undefined; - // image?: string | undefined; - healthcheck?: ContainerHealthCheck; - working_dir?: string; - user?: string; -} - -export interface ILogConfiguration { - logDriver: string; - options: { - 'awslogs-stream-prefix': string; - }; -} - -export interface IBuildConfig { - context?: string; - dockerfile?: string; - args?: ListOrDict; -} - -export type PortMappings = IPortMappingItem[]; - -interface IPortMappingItem { - containerPort: number; - hostPort?: number; - protocol: string; -} - -export interface IContainerHealthCheckItem { - command?: string | string[]; - interval?: number | string; - retries?: number; - start_period?: string; - timeout?: string; -} - -export type ServiceHealthCheck = IALBHealthCheckItem; - -interface IALBHealthCheckItem { - path: string; - port: number; -} - -export type DeploymentConfiguration = IDeploymentConfiguration; - -interface IDeploymentConfiguration { - MaximumPercent: number; - MinimumHealthyPercent: number; -} - -export type TaskConfig = ITaskConfig; - -interface ITaskConfig { - memory: number; - vCPU: number; -} - -export type ContainerConfig = IContainerConfig; - -interface IContainerConfig { - memory: number; - cpu: number; -} - -export type BuildHashMap = Record; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/index.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/index.ts deleted file mode 100644 index a66729ca10..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { getContainers } from './converter'; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/ecs-alb-stack.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/ecs-alb-stack.ts deleted file mode 100644 index e9a64044e9..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/ecs-alb-stack.ts +++ /dev/null @@ -1,300 +0,0 @@ -import * as acm from 'aws-cdk-lib/aws-certificatemanager'; -import * as cloudfront from 'aws-cdk-lib/aws-cloudfront'; -import * as cognito from 'aws-cdk-lib/aws-cognito'; -import * as ec2 from 'aws-cdk-lib/aws-ec2'; -import * as ecs from 'aws-cdk-lib/aws-ecs'; -import * as elb2 from 'aws-cdk-lib/aws-elasticloadbalancingv2'; -import * as route53 from 'aws-cdk-lib/aws-route53'; -import * as route53targets from 'aws-cdk-lib/aws-route53-targets'; -import * as cdk from 'aws-cdk-lib'; -import { Construct } from 'constructs'; -import { v4 as uuid } from 'uuid'; -import { ContainersStack, ContainersStackProps } from './base-api-stack'; - -type EcsStackProps = ContainersStackProps & - Readonly<{ - domainName: string; - hostedZoneId?: string; - authName: string; - }>; -export class EcsAlbStack extends ContainersStack { - private readonly userPoolDomain: string; - - constructor(scope: Construct, id: string, private readonly ecsProps: EcsStackProps) { - super(scope, id, { - ...ecsProps, - skipWait: true, - createCloudMapService: false, - }); - - const { authName, restrictAccess } = ecsProps; - - if (restrictAccess) { - const param = this.parameters.get(`auth${authName}HostedUIDomain`); - - this.userPoolDomain = param.valueAsString; - } - - this.parameters.get('ParamZipPath').default = 'site.zip'; - - this.alb(); - } - - private alb() { - const { - domainName, - hostedZoneId, - exposedContainer: { name: containerName, port }, - restrictAccess, - } = this.ecsProps; - - const sharedSecretHeaderName = 'x-cf-token'; - const sharedSecretHeader = uuid(); - - const userPoolDomain = this.userPoolDomain; - - const vpcId = this.vpcId; - const subnets = this.subnets; - - const userPoolArn = cdk.Fn.join('', [ - 'arn:', - cdk.Aws.PARTITION, - ':cognito-idp:', - cdk.Aws.REGION, - ':', - cdk.Aws.ACCOUNT_ID, - ':userpool/', - this.userPoolId, - ]); - - const [distributionDomainName, , domainNameSuffix] = domainName.match(/([^\.]+)\.(.*)/); - const lbPrefix = `lb-${this.envName}`; - const albDomainName = `${lbPrefix}.${domainNameSuffix}`; - const wildcardDomainName = `*.${domainNameSuffix}`; - - const wildcardCertificate = new acm.CfnCertificate(this, 'Certificate', { - domainName: wildcardDomainName, - validationMethod: hostedZoneId ? acm.ValidationMethod.DNS : acm.ValidationMethod.EMAIL, - domainValidationOptions: [ - { - domainName: wildcardDomainName, - validationDomain: hostedZoneId === undefined ? domainNameSuffix : undefined, - hostedZoneId, - }, - ], - }); - - const userPoolClient = restrictAccess - ? new cognito.CfnUserPoolClient(this, 'UserPoolClient', { - userPoolId: this.userPoolId, - allowedOAuthFlows: [ - // 'implicit', - 'code', - ], - allowedOAuthFlowsUserPoolClient: true, - allowedOAuthScopes: ['profile', 'phone', 'email', 'openid', 'aws.cognito.signin.user.admin'], - generateSecret: true, - supportedIdentityProviders: ['COGNITO'], - callbackUrLs: [`https://${distributionDomainName}/oauth2/idpresponse`], - logoutUrLs: [`https://${distributionDomainName}/oauth2/idpresponse`], - }) - : undefined; - - const targetGroup = new elb2.CfnTargetGroup(this, 'TargetGroup', { - healthCheckIntervalSeconds: cdk.Duration.seconds(90).toSeconds(), - healthCheckPath: '/', - healthCheckTimeoutSeconds: cdk.Duration.minutes(1).toSeconds(), - healthyThresholdCount: 2, - port, - protocol: elb2.Protocol.HTTP, - targetType: elb2.TargetType.IP, - unhealthyThresholdCount: 2, - vpcId, - }); - - const albSecurityGroup = new ec2.CfnSecurityGroup(this, 'AlbSecurityGroup', { - vpcId, - groupDescription: 'ALB Security Group', - securityGroupEgress: [ - { - description: 'Allow all outbound traffic by default', - ipProtocol: '-1', - cidrIp: '0.0.0.0/0', - }, - ], - securityGroupIngress: [ - { - description: 'Allow from anyone on port 443', - ipProtocol: ec2.Protocol.TCP, - cidrIp: '0.0.0.0/0', - fromPort: 443, - toPort: 443, - }, - ], - }); - - const loadBalancer = new elb2.CfnLoadBalancer(this, 'LoadBalancer', { - type: 'application', - securityGroups: [albSecurityGroup.attrGroupId], - loadBalancerAttributes: [ - { - key: 'deletion_protection.enabled', - value: 'false', - }, - ], - scheme: 'internet-facing', - subnets, - }); - - (this.ecsService.loadBalancers) = [ - { - containerName, - containerPort: port, - targetGroupArn: targetGroup.ref, - }, - ]; - (this.ecsServiceSecurityGroup.securityGroupIngress).push({ - ipProtocol: ec2.Protocol.TCP, - fromPort: port, - toPort: port, - sourceSecurityGroupId: albSecurityGroup.attrGroupId, - }); - - const listener = new elb2.CfnListener(this, 'AlbListener', { - defaultActions: [ - { - fixedResponseConfig: { - statusCode: '403', - }, - type: 'fixed-response', - }, - ], - loadBalancerArn: loadBalancer.ref, - port: 443, - protocol: elb2.Protocol.HTTPS, - certificates: [{ certificateArn: wildcardCertificate.ref }], - }); - - this.ecsService.addDependency(listener); - - let actionsOrderCounter = 1; - const listenerRule = new elb2.CfnListenerRule(this, 'AlbListenerRule', { - priority: 1, - listenerArn: listener.ref, - actions: [].concat( - restrictAccess - ? { - order: actionsOrderCounter++, - type: 'authenticate-cognito', - authenticateCognitoConfig: { - userPoolArn, - userPoolClientId: userPoolClient.ref, - userPoolDomain, - }, - } - : undefined, - { - order: actionsOrderCounter++, - type: 'forward', - targetGroupArn: targetGroup.ref, - }, - ), - conditions: [ - { - field: 'host-header', - hostHeaderConfig: { - values: [distributionDomainName], - }, - }, - { - field: 'http-header', - httpHeaderConfig: { - httpHeaderName: sharedSecretHeaderName, - values: [sharedSecretHeader], - }, - }, - ], - }); - - this.ecsService.addDependency(listenerRule); - - const originId = `${loadBalancer.logicalId}-origin`; - - const distribution = new cloudfront.CfnDistribution(this, 'Distribution', { - distributionConfig: { - enabled: true, - httpVersion: 'http2', - ipv6Enabled: true, - aliases: [distributionDomainName], - defaultCacheBehavior: { - forwardedValues: { - cookies: { forward: 'all' }, - headers: ['*'], - queryString: true, - }, - targetOriginId: originId, - viewerProtocolPolicy: 'redirect-to-https', - }, - origins: [ - { - customOriginConfig: { - originProtocolPolicy: 'https-only', - }, - domainName: albDomainName, - id: originId, - originCustomHeaders: [ - { - headerName: sharedSecretHeaderName, - headerValue: sharedSecretHeader, - }, - ], - }, - ], - viewerCertificate: { - acmCertificateArn: wildcardCertificate.ref, - minimumProtocolVersion: 'TLSv1.2_2019', - sslSupportMethod: 'sni-only', - }, - }, - }); - - if (hostedZoneId) { - new route53.CfnRecordSetGroup(this, 'RecordSetGroup', { - hostedZoneId, - recordSets: [ - { - name: albDomainName, - type: route53.RecordType.A, - aliasTarget: { - hostedZoneId: loadBalancer.attrCanonicalHostedZoneId, - dnsName: loadBalancer.attrDnsName, - }, - }, - { - name: distributionDomainName, - type: route53.RecordType.A, - aliasTarget: { - hostedZoneId: route53targets.CloudFrontTarget.CLOUDFRONT_ZONE_ID, - dnsName: distribution.attrDomainName, - }, - }, - ], - }); - } - - new cdk.CfnOutput(this, 'PipelineUrl', { - value: cdk.Fn.join('', [ - 'https://', - cdk.Aws.REGION, - '.console.aws.amazon.com/codesuite/codepipeline/pipelines/', - this.getPipelineName(), - '/view', - ]), - }); - - new cdk.CfnOutput(this, 'LoadBalancerAliasDomainName', { value: loadBalancer.attrDnsName }); - new cdk.CfnOutput(this, 'LoadBalancerCnameDomainName', { value: albDomainName }); - new cdk.CfnOutput(this, 'CloudfrontDistributionAliasDomainName', { value: distribution.attrDomainName }); - new cdk.CfnOutput(this, 'CloudfrontDistributionCnameDomainName', { value: distributionDomainName }); - } -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/ecs-apigw-stack.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/ecs-apigw-stack.ts deleted file mode 100644 index a0102d218b..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/ecs-apigw-stack.ts +++ /dev/null @@ -1,100 +0,0 @@ -import * as apigw2 from 'aws-cdk-lib/aws-apigatewayv2'; -import * as apigw2alpha from '@aws-cdk/aws-apigatewayv2-alpha'; -import * as cdk from 'aws-cdk-lib'; -import { Construct } from 'constructs'; -import { ContainersStack, ContainersStackProps } from './base-api-stack'; -import { API_TYPE } from './service-walkthroughs/containers-walkthrough'; - -type EcsStackProps = Readonly< - ContainersStackProps & { - apiType: API_TYPE; - } ->; -export class EcsStack extends ContainersStack { - constructor(scope: Construct, id: string, private readonly ecsProps: EcsStackProps) { - super(scope, id, { - ...ecsProps, - createCloudMapService: true, - }); - - const { apiType } = this.ecsProps; - - const { api } = this.apiGateway(); - - switch (apiType) { - case API_TYPE.GRAPHQL: - new cdk.CfnOutput(this, 'GraphQLAPIEndpointOutput', { value: api.attrApiEndpoint }); - break; - case API_TYPE.REST: - new cdk.CfnOutput(this, 'ApiName', { value: ecsProps.apiName }); - new cdk.CfnOutput(this, 'RootUrl', { value: api.attrApiEndpoint }); - break; - default: { - const invalidApiType: never = apiType; - throw new Error(`Invalid api type ${invalidApiType}`); - } - } - } - - private apiGateway() { - const { apiName } = this.ecsProps; - - const api = new apigw2.CfnApi(this, 'Api', { - name: `${this.envName}-${apiName}`, - protocolType: 'HTTP', - corsConfiguration: { - allowHeaders: ['*'], - allowOrigins: ['*'], - allowMethods: Object.values(apigw2alpha.HttpMethod).filter((m) => m !== apigw2alpha.HttpMethod.ANY), - }, - }); - - new apigw2.CfnStage(this, 'Stage', { - apiId: cdk.Fn.ref(api.logicalId), - stageName: '$default', - autoDeploy: true, - }); - - const integration = new apigw2.CfnIntegration(this, 'ANYIntegration', { - apiId: cdk.Fn.ref(api.logicalId), - integrationType: apigw2alpha.HttpIntegrationType.HTTP_PROXY, - connectionId: this.vpcLinkId, - connectionType: apigw2alpha.HttpConnectionType.VPC_LINK, - integrationMethod: 'ANY', - integrationUri: this.cloudMapService.attrArn, - payloadFormatVersion: '1.0', - }); - - const authorizer = new apigw2.CfnAuthorizer(this, 'Authorizer', { - name: `${apiName}Authorizer`, - apiId: cdk.Fn.ref(api.logicalId), - authorizerType: 'JWT', - jwtConfiguration: { - audience: [this.appClientId], - issuer: cdk.Fn.join('', ['https://cognito-idp.', cdk.Aws.REGION, '.amazonaws.com/', this.userPoolId]), - }, - identitySource: ['$request.header.Authorization'], - }); - - authorizer.cfnOptions.condition = this.isAuthCondition; - - new apigw2.CfnRoute(this, 'DefaultRoute', { - apiId: cdk.Fn.ref(api.logicalId), - routeKey: '$default', - target: cdk.Fn.join('', ['integrations/', cdk.Fn.ref(integration.logicalId)]), - authorizationScopes: [], - authorizationType: cdk.Fn.conditionIf(this.isAuthCondition.logicalId, 'JWT', 'NONE'), - authorizerId: cdk.Fn.conditionIf(this.isAuthCondition.logicalId, cdk.Fn.ref(authorizer.logicalId), ''), - }); - - new apigw2.CfnRoute(this, 'OptionsRoute', { - apiId: cdk.Fn.ref(api.logicalId), - routeKey: 'OPTIONS /{proxy+}', - target: cdk.Fn.join('', ['integrations/', cdk.Fn.ref(integration.logicalId)]), - }); - - return { - api, - }; - } -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts deleted file mode 100644 index 167ce9c425..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts +++ /dev/null @@ -1,331 +0,0 @@ -import * as path from 'path'; -import { $TSContext, AmplifySupportedService, exitOnNextTick, NotImplementedError } from '@aws-amplify/amplify-cli-core'; -import { UpdateApiRequest } from 'amplify-headless-interface'; -import { printer } from '@aws-amplify/amplify-prompts'; -import inquirer from 'inquirer'; -import { category } from '../../category-constants'; -import { ApigwInputState } from './apigw-input-state'; -import { getCfnApiArtifactHandler } from './cfn-api-artifact-handler'; -import { addResource as addContainer, updateResource as updateContainer } from './containers-handler'; -import { legacyAddResource } from './legacy-add-resource'; -import { - API_TYPE, - getPermissionPolicies as getContainerPermissionPolicies, - ServiceConfiguration, -} from './service-walkthroughs/containers-walkthrough'; -import { datasourceMetadataFor, getServiceWalkthrough, serviceMetadataFor } from './utils/dynamic-imports'; -import { editSchemaFlow } from './utils/edit-schema-flow'; -import { serviceWalkthroughResultToAddApiRequest } from './utils/service-walkthrough-result-to-add-api-request'; - -export async function addAdminQueriesApi( - context: $TSContext, - apiProps: { apiName: string; functionName: string; authResourceName: string; dependsOn: Record[] }, -) { - const apigwInputState = new ApigwInputState(context, apiProps.apiName); - return apigwInputState.addAdminQueriesResource(apiProps); -} - -export async function updateAdminQueriesApi( - context: $TSContext, - apiProps: { apiName: string; functionName: string; authResourceName: string; dependsOn: Record[] }, -) { - const apigwInputState = new ApigwInputState(context, apiProps.apiName); - // Check for migration - - if (!apigwInputState.cliInputsFileExists()) { - await apigwInputState.migrateAdminQueries(apiProps); - } else { - return apigwInputState.updateAdminQueriesResource(apiProps); - } -} - -export async function console(context: $TSContext, service: string) { - const { serviceWalkthroughFilename } = await serviceMetadataFor(service); - const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); - const { openConsole } = await import(serviceWalkthroughSrc); - - if (!openConsole) { - const errMessage = 'Opening console functionality not available for this option'; - printer.error(errMessage); - await context.usageData.emitError(new NotImplementedError(errMessage)); - exitOnNextTick(0); - } - - return openConsole(context); -} - -async function addContainerResource(context: $TSContext, service: string, options, apiType: API_TYPE) { - const serviceWalkthroughFilename = 'containers-walkthrough.js'; - - const serviceWalkthrough = await getServiceWalkthrough(serviceWalkthroughFilename); - const serviceWalkthroughPromise: Promise = serviceWalkthrough(context, apiType); - - return await addContainer(serviceWalkthroughPromise, context, category, service, options, apiType); -} - -async function addNonContainerResource(context: $TSContext, service: string, options) { - const serviceMetadata = await serviceMetadataFor(service); - const { serviceWalkthroughFilename, defaultValuesFilename } = serviceMetadata; - const serviceWalkthrough = await getServiceWalkthrough(serviceWalkthroughFilename); - - const serviceWalkthroughPromise: Promise = serviceWalkthrough(context, serviceMetadata); - switch (service) { - case AmplifySupportedService.APPSYNC: { - const walkthroughResult = await serviceWalkthroughPromise; - const askToEdit = walkthroughResult.askToEdit; - const apiName = await getCfnApiArtifactHandler(context).createArtifacts(serviceWalkthroughResultToAddApiRequest(walkthroughResult)); - if (askToEdit) { - await editSchemaFlow(context, apiName); - } - return apiName; - } - case AmplifySupportedService.APIGW: { - const apigwInputState = new ApigwInputState(context); - return apigwInputState.addApigwResource(serviceWalkthroughPromise, options); - } - default: - return legacyAddResource(serviceWalkthroughPromise, context, category, service, options); - } -} - -export async function addResource(context: $TSContext, service: string, options) { - let useContainerResource = false; - let apiType = API_TYPE.GRAPHQL; - - if (isContainersEnabled(context)) { - switch (service) { - case AmplifySupportedService.APPSYNC: - useContainerResource = await isGraphQLContainer(); - apiType = API_TYPE.GRAPHQL; - break; - case AmplifySupportedService.APIGW: - useContainerResource = await isRestContainer(); - apiType = API_TYPE.REST; - break; - default: - throw new Error(`${service} not exists`); - } - } - - return useContainerResource - ? addContainerResource(context, service, options, apiType) - : addNonContainerResource(context, service, options); -} - -function isContainersEnabled(context: $TSContext) { - const { frontend } = context.amplify.getProjectConfig(); - if (frontend) { - const { config: { ServerlessContainers = false } = {} } = context.amplify.getProjectConfig()[frontend] || {}; - - return ServerlessContainers; - } - - return false; -} - -async function isGraphQLContainer(): Promise { - const { graphqlSelection } = await inquirer.prompt({ - name: 'graphqlSelection', - message: 'Which service would you like to use', - type: 'list', - choices: [ - { - name: AmplifySupportedService.APPSYNC, - value: false, - }, - { - name: 'AWS Fargate (Container-based)', - value: true, - }, - ], - }); - - return graphqlSelection; -} - -async function isRestContainer() { - const { restSelection } = await inquirer.prompt({ - name: 'restSelection', - message: 'Which service would you like to use', - type: 'list', - choices: [ - { - name: 'API Gateway + Lambda', - value: false, - }, - { - name: 'API Gateway + AWS Fargate (Container-based)', - value: true, - }, - ], - }); - - return restSelection; -} - -export async function updateResource(context: $TSContext, category: string, service: string, options) { - const allowContainers = options?.allowContainers ?? true; - let useContainerResource = false; - let apiType = API_TYPE.GRAPHQL; - if (allowContainers && isContainersEnabled(context)) { - const { hasAPIGatewayContainerResource, hasAPIGatewayLambdaResource, hasGraphQLAppSyncResource, hasGraphqlContainerResource } = - await describeApiResourcesBySubCategory(context); - - switch (service) { - case AmplifySupportedService.APPSYNC: - if (hasGraphQLAppSyncResource && hasGraphqlContainerResource) { - useContainerResource = await isGraphQLContainer(); - } else if (hasGraphqlContainerResource) { - useContainerResource = true; - } else { - useContainerResource = false; - } - apiType = API_TYPE.GRAPHQL; - break; - case AmplifySupportedService.APIGW: - if (hasAPIGatewayContainerResource && hasAPIGatewayLambdaResource) { - useContainerResource = await isRestContainer(); - } else if (hasAPIGatewayContainerResource) { - useContainerResource = true; - } else { - useContainerResource = false; - } - apiType = API_TYPE.REST; - break; - default: - throw new Error(`${service} not exists`); - } - } - - return useContainerResource ? updateContainerResource(context, category, service, apiType) : updateNonContainerResource(context, service); -} - -async function describeApiResourcesBySubCategory(context: $TSContext) { - const { allResources } = await context.amplify.getResourceStatus(); - const resources = allResources.filter((resource) => resource.category === category && resource.mobileHubMigrated !== true); - - let hasAPIGatewayContainerResource = false; - let hasAPIGatewayLambdaResource = false; - let hasGraphQLAppSyncResource = false; - let hasGraphqlContainerResource = false; - - resources.forEach((resource) => { - hasAPIGatewayContainerResource = - hasAPIGatewayContainerResource || (resource.service === 'ElasticContainer' && resource.apiType === API_TYPE.REST); - - hasAPIGatewayLambdaResource = hasAPIGatewayLambdaResource || resource.service === AmplifySupportedService.APIGW; - - hasGraphQLAppSyncResource = hasGraphQLAppSyncResource || resource.service === AmplifySupportedService.APPSYNC; - - hasGraphqlContainerResource = - hasGraphqlContainerResource || (resource.service === 'ElasticContainer' && resource.apiType === API_TYPE.GRAPHQL); - }); - - return { - hasAPIGatewayLambdaResource, - hasAPIGatewayContainerResource, - hasGraphQLAppSyncResource, - hasGraphqlContainerResource, - }; -} - -async function updateContainerResource(context: $TSContext, category: string, service: string, apiType: API_TYPE) { - const serviceWalkthroughFilename = 'containers-walkthrough'; - const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); - const { updateWalkthrough } = await import(serviceWalkthroughSrc); - - if (!updateWalkthrough) { - const errMessage = 'Update functionality not available for this option'; - printer.error(errMessage); - await context.usageData.emitError(new NotImplementedError(errMessage)); - exitOnNextTick(0); - } - - const updateWalkthroughPromise: Promise = updateWalkthrough(context, apiType); - - await updateContainer(updateWalkthroughPromise, context, category); -} - -async function updateNonContainerResource(context: $TSContext, service: string) { - const serviceMetadata = await serviceMetadataFor(service); - const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; - const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); - const { updateWalkthrough } = await import(serviceWalkthroughSrc); - - if (!updateWalkthrough) { - const errMessage = 'Update functionality not available for this option'; - printer.error(errMessage); - await context.usageData.emitError(new NotImplementedError(errMessage)); - exitOnNextTick(0); - } - - const updateWalkthroughPromise: Promise = updateWalkthrough(context, defaultValuesFilename, serviceMetadata); - - switch (service) { - case AmplifySupportedService.APPSYNC: - return updateWalkthroughPromise.then(getCfnApiArtifactHandler(context).updateArtifacts); - default: { - const apigwInputState = new ApigwInputState(context); - return apigwInputState.updateApigwResource(updateWalkthroughPromise); - } - } -} - -export async function migrateResource(context: $TSContext, projectPath: string, service: string, resourceName: string) { - if (service === 'ElasticContainer') { - return migrateResourceContainer(context, projectPath, service, resourceName); - } else { - return migrateResourceNonContainer(context, projectPath, service, resourceName); - } -} - -async function migrateResourceContainer(context: $TSContext, projectPath: string, service: string, resourceName: string) { - printer.info(`No migration required for ${resourceName}`); - return; -} - -async function migrateResourceNonContainer(context: $TSContext, projectPath: string, service: string, resourceName: string) { - const serviceMetadata = await serviceMetadataFor(service); - const { serviceWalkthroughFilename } = serviceMetadata; - const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); - const { migrate } = await import(serviceWalkthroughSrc); - - if (!migrate) { - printer.info(`No migration required for ${resourceName}`); - return; - } - - return await migrate(context, projectPath, resourceName); -} - -export async function addDatasource(context: $TSContext, category, datasource) { - const serviceMetadata = await datasourceMetadataFor(datasource); - const { serviceWalkthroughFilename } = serviceMetadata; - return (await getServiceWalkthrough(serviceWalkthroughFilename))(context, serviceMetadata); -} - -export async function getPermissionPolicies(context: $TSContext, service: string, resourceName: string, crudOptions) { - if (service === 'ElasticContainer') { - return getPermissionPoliciesContainer(context, service, resourceName, crudOptions); - } else { - return getPermissionPoliciesNonContainer(service, resourceName, crudOptions); - } -} - -async function getPermissionPoliciesContainer(context: $TSContext, service: string, resourceName: string, crudOptions) { - return getContainerPermissionPolicies(context, service, resourceName, crudOptions); -} - -async function getPermissionPoliciesNonContainer(service: string, resourceName: string, crudOptions: string[]) { - const serviceMetadata = await serviceMetadataFor(service); - const { serviceWalkthroughFilename } = serviceMetadata; - const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); - const { getIAMPolicies } = await import(serviceWalkthroughSrc); - - if (!getIAMPolicies) { - printer.info(`No policies found for ${resourceName}`); - return; - } - - return getIAMPolicies(resourceName, crudOptions); -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/legacy-add-resource.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/legacy-add-resource.ts deleted file mode 100644 index f3387d3913..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/legacy-add-resource.ts +++ /dev/null @@ -1,79 +0,0 @@ -import * as path from 'path'; -import { $TSContext, isResourceNameUnique, JSONUtilities, pathManager } from '@aws-amplify/amplify-cli-core'; -import * as fs from 'fs-extra'; -import { cfnParametersFilename, parametersFileName, rootAssetDir } from './aws-constants'; -import { serviceMetadataFor } from './utils/dynamic-imports'; - -// this is the old logic for generating resources in the project directory -// it is still used for adding REST APIs -export const legacyAddResource = async ( - serviceWalkthroughPromise: Promise, - context: $TSContext, - category: string, - service: string, - options: Record, -) => { - let answers; - let { cfnFilename } = await serviceMetadataFor(service); - - const result = await serviceWalkthroughPromise; - - if (result.answers) { - ({ answers } = result); - options.dependsOn = result.dependsOn; - } else { - answers = result; - } - if (result.output) { - options.output = result.output; - } - if (!result.noCfnFile) { - if (answers.customCfnFile) { - cfnFilename = answers.customCfnFile; - } - addPolicyResourceNameToPaths(answers.paths); - copyCfnTemplate(context, category, answers, cfnFilename); - - const parameters = { ...answers }; - const resourceDirPath = pathManager.getResourceDirectoryPath(undefined, category, parameters.resourceName); - - isResourceNameUnique(category, parameters.resourceName); - - fs.ensureDirSync(resourceDirPath); - - const parametersFilePath = path.join(resourceDirPath, parametersFileName); - JSONUtilities.writeJson(parametersFilePath, parameters); - - const cfnParametersFilePath = path.join(resourceDirPath, cfnParametersFilename); - JSONUtilities.writeJson(cfnParametersFilePath, {}); - } - context.amplify.updateamplifyMetaAfterResourceAdd(category, answers.resourceName, options); - return answers.resourceName; -}; - -// exported because the update flow still uses this method directly for now -export const copyCfnTemplate = (context: $TSContext, category: string, options, cfnFilename) => { - const resourceDirPath = pathManager.getResourceDirectoryPath(undefined, category, options.resourceName); - - const copyJobs = [ - { - dir: path.join(rootAssetDir, 'cloudformation-templates'), - template: cfnFilename, - target: path.join(resourceDirPath, `${options.resourceName}-cloudformation-template.json`), - }, - ]; - - // copy over the files - return context.amplify.copyBatch(context, copyJobs, options, true, false); -}; - -export const addPolicyResourceNameToPaths = (paths) => { - if (Array.isArray(paths)) { - paths.forEach((p) => { - const pathName = p.name; - if (typeof pathName === 'string') { - p.policyResourceName = pathName.replace(/{[a-zA-Z0-9\-]+}/g, '*'); - } - }); - } -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/legacy-update-resource.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/legacy-update-resource.ts deleted file mode 100644 index 0cb878c77f..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/legacy-update-resource.ts +++ /dev/null @@ -1,35 +0,0 @@ -import * as path from 'path'; -import { $TSContext, JSONUtilities, pathManager } from '@aws-amplify/amplify-cli-core'; -import * as fs from 'fs-extra'; -import { parametersFileName } from './aws-constants'; -import { addPolicyResourceNameToPaths, copyCfnTemplate } from './legacy-add-resource'; -import { serviceMetadataFor } from './utils/dynamic-imports'; - -export const legacyUpdateResource = async (updateWalkthroughPromise: Promise, context: $TSContext, category: string, service) => { - let answers; - let { cfnFilename } = await serviceMetadataFor(service); - const result = await updateWalkthroughPromise; - const options: any = {}; - if (result) { - if (result.answers) { - ({ answers } = result); - options.dependsOn = result.dependsOn; - } else { - answers = result; - } - - if (!result.noCfnFile) { - if (answers.customCfnFile) { - cfnFilename = answers.customCfnFile; - } - addPolicyResourceNameToPaths(answers.paths); - copyCfnTemplate(context, category, answers, cfnFilename); - const parameters = { ...answers }; - const resourceDirPath = pathManager.getResourceDirectoryPath(undefined, category, parameters.resourceName); - fs.ensureDirSync(resourceDirPath); - const parametersFilePath = path.join(resourceDirPath, parametersFileName); - JSONUtilities.writeJson(parametersFilePath, parameters); - context.amplify.updateamplifyMetaAfterResourceUpdate(category, answers.resourceName, 'dependsOn', answers.dependsOn); - } - } -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/pipeline-with-awaiter.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/pipeline-with-awaiter.ts deleted file mode 100644 index 6721ac52e4..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/pipeline-with-awaiter.ts +++ /dev/null @@ -1,396 +0,0 @@ -import * as path from 'path'; -import * as codebuild from 'aws-cdk-lib/aws-codebuild'; -import * as codepipeline from 'aws-cdk-lib/aws-codepipeline'; -import * as codepipelineactions from 'aws-cdk-lib/aws-codepipeline-actions'; -import * as ecr from 'aws-cdk-lib/aws-ecr'; -import * as ecs from 'aws-cdk-lib/aws-ecs'; -import * as iam from 'aws-cdk-lib/aws-iam'; -import * as lambda from 'aws-cdk-lib/aws-lambda'; -import * as s3 from 'aws-cdk-lib/aws-s3'; -import * as cdk from 'aws-cdk-lib'; -import * as custom from 'aws-cdk-lib/custom-resources'; -import { Construct } from 'constructs'; -import * as fs from 'fs-extra'; -import { DEPLOYMENT_MECHANISM } from './base-api-stack'; -import { getGitHubOwnerRepoFromPath } from './utils/github'; - -type PipelineAwaiterProps = { - pipeline: codepipeline.Pipeline; - artifactBucketName?: string; - artifactKey?: string; - deploymentMechanism: DEPLOYMENT_MECHANISM; -}; - -export type GitHubSourceActionInfo = { - path: string; - tokenSecretArn: string; -}; - -const lambdaRuntimeNodeVersion = lambda.Runtime.NODEJS_18_X; - -const lambdasDir = path.resolve(__dirname, '../../../resources/awscloudformation/lambdas'); - -class PipelineAwaiter extends Construct { - constructor(scope: Construct, id: string, props: PipelineAwaiterProps) { - const { pipeline, artifactBucketName, artifactKey, deploymentMechanism } = props; - - const { pipelineArn, pipelineName } = pipeline; - - const pipelineOnEventCodeFilePath = path.join(lambdasDir, 'pipeline-on-event.js'); - const onEventHandlerCode = fs.readFileSync(pipelineOnEventCodeFilePath, 'utf8'); - - const onEventHandler = new lambda.Function(scope, `${id}CustomEventHandler`, { - runtime: lambdaRuntimeNodeVersion, - handler: 'index.handler', - code: lambda.Code.fromInline(onEventHandlerCode), - timeout: cdk.Duration.seconds(15), - }); - - const pipelineCodeFilePath = path.join(lambdasDir, 'pipeline.js'); - const isCompleteHandlerCode = fs.readFileSync(pipelineCodeFilePath, 'utf8'); - - const isCompleteHandler = new lambda.Function(scope, `${id}CustomCompleteHandler`, { - runtime: lambdaRuntimeNodeVersion, - handler: 'index.handler', - timeout: cdk.Duration.seconds(15), - code: lambda.Code.fromInline(isCompleteHandlerCode), - }); - isCompleteHandler.addToRolePolicy( - new iam.PolicyStatement({ - effect: iam.Effect.ALLOW, - actions: ['codepipeline:GetPipeline', 'codepipeline:ListPipelineExecutions'], - resources: [pipelineArn], - }), - ); - isCompleteHandler.addToRolePolicy( - new iam.PolicyStatement({ - effect: iam.Effect.ALLOW, - actions: ['cloudformation:DescribeStacks'], - resources: [cdk.Stack.of(scope).stackId], - }), - ); - - const myProvider = new custom.Provider(scope, `${id}MyProvider`, { - onEventHandler, - isCompleteHandler, - queryInterval: cdk.Duration.seconds(10), - }); - - new cdk.CustomResource(scope, `Deployment${id}`, { - serviceToken: myProvider.serviceToken, - properties: { - artifactBucketName, - artifactKey, - pipelineName, - deploymentMechanism, - }, - }); - - super(scope, id); - } -} - -export class PipelineWithAwaiter extends Construct { - pipelineName: string; - - constructor( - scope: Construct, - id: string, - { - skipWait = false, - bucket, - s3SourceActionKey, - service, - deploymentMechanism, - gitHubSourceActionInfo, - containersInfo, - desiredCount, - envName, - }: { - skipWait?: boolean; - bucket: s3.IBucket; - s3SourceActionKey?: string; - deploymentMechanism: DEPLOYMENT_MECHANISM; - gitHubSourceActionInfo?: GitHubSourceActionInfo; - service: ecs.CfnService; - containersInfo: { - container: ecs.ContainerDefinition; - repository: ecr.IRepository; - }[]; - desiredCount: number; - envName: string; - }, - ) { - super(scope, id); - - const sourceOutput = new codepipeline.Artifact('SourceArtifact'); - const buildOutput = new codepipeline.Artifact('BuildArtifact'); - - const codeBuildProject = new codebuild.PipelineProject(scope, `${id}CodeBuildProject`, { - environment: { - buildImage: codebuild.LinuxBuildImage.STANDARD_4_0, - // See: https://docs.aws.amazon.com/codebuild/latest/userguide/troubleshooting.html#troubleshooting-cannot-connect-to-docker-daemon - privileged: true, - }, - }); - - if (gitHubSourceActionInfo && gitHubSourceActionInfo.tokenSecretArn) { - codeBuildProject.addToRolePolicy( - new iam.PolicyStatement({ - effect: iam.Effect.ALLOW, - actions: [ - 'secretsmanager:GetRandomPassword', - 'secretsmanager:GetResourcePolicy', - 'secretsmanager:GetSecretValue', - 'secretsmanager:DescribeSecret', - 'secretsmanager:ListSecretVersionIds', - ], - resources: [gitHubSourceActionInfo.tokenSecretArn], - }), - ); - } - - codeBuildProject.role.addToPrincipalPolicy( - new iam.PolicyStatement({ - resources: ['*'], - actions: [ - 'ecr:GetAuthorizationToken', - 'ecr:BatchGetImage', - 'ecr:GetDownloadUrlForLayer', - 'ecr:InitiateLayerUpload', - 'ecr:BatchCheckLayerAvailability', - 'ecr:UploadLayerPart', - 'ecr:CompleteLayerUpload', - 'ecr:PutImage', - ], - effect: iam.Effect.ALLOW, - }), - ); - - const prebuildStages = createPreBuildStages(scope, { - bucket, - s3SourceActionKey, - gitHubSourceActionInfo, - roleName: 'UpdateSource', - sourceOutput, - }); - - const environmentVariables = containersInfo.reduce( - (acc, c) => { - acc[`${c.container.containerName}_REPOSITORY_URI`] = { - type: codebuild.BuildEnvironmentVariableType.PLAINTEXT, - value: c.repository.repositoryUri, - }; - - return acc; - }, - { - AWS_ACCOUNT_ID: { - type: codebuild.BuildEnvironmentVariableType.PLAINTEXT, - value: cdk.Aws.ACCOUNT_ID, - }, - } as Record, - ); - - // TODO: Remove this custom role if we upgrade the CDK version to >= 2.132.0 - // since this ecs:TagResource permission will be present in the default deploy role policy generated by CDK - const ecsDeployActionRole = new iam.Role(scope, 'EcsDeployActionRole', { - assumedBy: new iam.AccountRootPrincipal(), - }); - ecsDeployActionRole.addToPolicy( - new iam.PolicyStatement({ - actions: ['ecs:TagResource'], - effect: iam.Effect.ALLOW, - resources: ['*'], - }), - ); - - const ecsDeployAction = new codepipelineactions.EcsDeployAction({ - actionName: 'Deploy', - service: new (class extends Construct implements ecs.IBaseService { - cluster = { - clusterName: service.cluster, - env: {}, - } as ecs.ICluster; - - serviceArn = cdk.Fn.ref(service.attrServiceArn); - - serviceName = service.serviceName; - - stack = cdk.Stack.of(this); - - env = {} as any; - - node = service.node; - - public applyRemovalPolicy(policy: cdk.RemovalPolicy): void { - // TODO: This is added for CDK upgrade. Modify the behavior if required. - } - })(this, 'tmpService'), - input: buildOutput, - role: ecsDeployActionRole, - }); - - const stagesWithDeploy = ([] as codepipeline.StageOptions[]).concat(prebuildStages, [ - { - stageName: 'Build', - actions: [ - new codepipelineactions.CodeBuildAction({ - actionName: 'Build', - type: codepipelineactions.CodeBuildActionType.BUILD, - project: codeBuildProject, - input: sourceOutput, - outputs: [buildOutput], - environmentVariables, - }), - ], - }, - { - stageName: 'Predeploy', - actions: [ - new codepipelineactions.LambdaInvokeAction({ - actionName: 'Predeploy', - lambda: (() => { - const preDeployCodeFilePath = path.join(lambdasDir, 'predeploy.js'); - const lambdaHandlerCode = fs.readFileSync(preDeployCodeFilePath, 'utf8'); - - const action = new lambda.Function(scope, 'PreDeployLambda', { - code: lambda.Code.fromInline(lambdaHandlerCode), - handler: 'index.handler', - runtime: lambdaRuntimeNodeVersion, - environment: { - DESIRED_COUNT: `${desiredCount}`, - CLUSTER_NAME: service.cluster, - SERVICE_NAME: service.serviceName, - }, - timeout: cdk.Duration.seconds(15), - }); - - action.addToRolePolicy( - new iam.PolicyStatement({ - actions: ['ecs:UpdateService'], - effect: iam.Effect.ALLOW, - resources: [cdk.Fn.ref(service.logicalId)], - }), - ); - - return action; - })(), - inputs: [], - outputs: [], - }), - ], - }, - { - stageName: 'Deploy', - actions: [ecsDeployAction], - }, - ]); - - this.pipelineName = `${envName}-${service.serviceName}`; - - const pipeline = new codepipeline.Pipeline(scope, `${id}Pipeline`, { - pipelineName: this.pipelineName, - crossAccountKeys: false, - artifactBucket: bucket, - stages: stagesWithDeploy, - }); - - pipeline.node.addDependency(service); - - if (!skipWait) { - new PipelineAwaiter(scope, 'Awaiter', { - pipeline, - artifactBucketName: bucket.bucketName, - artifactKey: s3SourceActionKey, - deploymentMechanism, - }); - } - - new cdk.CfnOutput(scope, 'PipelineName', { value: this.pipelineName }); - } - - getPipelineName(): string { - return this.pipelineName; - } -} - -function createPreBuildStages( - scope: Construct, - { - bucket, - s3SourceActionKey, - gitHubSourceActionInfo, - sourceOutput, - roleName, - }: { - bucket: s3.IBucket; - s3SourceActionKey: string; - gitHubSourceActionInfo?: GitHubSourceActionInfo; - sourceOutput: codepipeline.Artifact; - roleName: string; - }, -) { - const stages: codepipeline.StageOptions[] = []; - - const stage = { - stageName: 'Source', - actions: [], - }; - - stages.push(stage); - - if (gitHubSourceActionInfo && gitHubSourceActionInfo.path) { - const { path, tokenSecretArn } = gitHubSourceActionInfo; - const { owner, repo, branch } = getGitHubOwnerRepoFromPath(path); - - const preBuildOutput = new codepipeline.Artifact('PreBuildArtifact'); - - stage.actions = [ - new codepipelineactions.GitHubSourceAction({ - actionName: 'Source', - oauthToken: cdk.SecretValue.secretsManager(tokenSecretArn), - owner, - repo, - branch, - output: preBuildOutput, - }), - ]; - - stages.push({ - stageName: 'PreBuild', - actions: [ - new codepipelineactions.LambdaInvokeAction({ - actionName: 'PreBuild', - lambda: new lambda.Function(scope, 'PreBuildLambda', { - code: lambda.S3Code.fromBucket(bucket, 'codepipeline-action-buildspec-generator-lambda.zip'), - handler: 'index.handler', - runtime: lambdaRuntimeNodeVersion, - timeout: cdk.Duration.seconds(15), - }), - inputs: [preBuildOutput], - outputs: [sourceOutput], - }), - ], - }); - } else { - stage.actions = [ - new codepipelineactions.S3SourceAction({ - actionName: 'Source', - bucket, - bucketKey: s3SourceActionKey, - output: sourceOutput, - }), - ]; - } - - return stages; -} - -export type ContainerStackProps = { - deploymentBucket: string; - containerPort: number; - awaiterZipPath: string; - gitHubPath?: string; - gitHubTokenSecretsManagerArn: string; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/prompt-to-add-api-key.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/prompt-to-add-api-key.ts deleted file mode 100644 index 21b7ebf172..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/prompt-to-add-api-key.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { prompter } from '@aws-amplify/amplify-prompts'; -import { askApiKeyQuestions } from './service-walkthroughs/appSync-walkthrough'; -import { authConfigToAppSyncAuthType } from './utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; -import { getCfnApiArtifactHandler } from './cfn-api-artifact-handler'; - -export async function promptToAddApiKey(context: $TSContext): Promise { - if (await prompter.confirmContinue('Would you like to create an API Key?')) { - const apiKeyConfig = await askApiKeyQuestions(); - const authConfig = [apiKeyConfig]; - - await getCfnApiArtifactHandler(context).updateArtifacts( - { - version: 1, - serviceModification: { - serviceName: 'AppSync', - additionalAuthTypes: authConfig.map(authConfigToAppSyncAuthType), - }, - }, - { - skipCompile: true, - }, - ); - - return apiKeyConfig; - } -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/aPIGateway-user-input-types.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/aPIGateway-user-input-types.ts deleted file mode 100644 index 9844234707..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/aPIGateway-user-input-types.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Defines the json object expected by the amplify api category - */ -export interface APIGatewayCLIInputs { - /** - * The schema version. - */ - version: 1; - - /** - * map of paths in the REST API. - */ - paths: { [pathName: string]: Path }; -} - -type Path = { - lambdaFunction: string; - permissions: { - setting: PermissionSetting; - auth?: CrudOperation[]; - guest?: CrudOperation[]; - groups?: { [groupName: string]: CrudOperation[] }; - }; -}; - -enum CrudOperation { - CREATE = 'create', - READ = 'read', - UPDATE = 'update', - DELETE = 'delete', -} - -enum PermissionSetting { - PRIVATE = 'private', - PROTECTED = 'protected', - OPEN = 'open', -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/apigw-types.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/apigw-types.ts deleted file mode 100644 index 2aa78758ce..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/apigw-types.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { CrudOperation, PermissionSetting } from '../cdk-stack-builder'; - -export type ApigwPath = { - name: string; - permissions: { - setting: PermissionSetting; - auth?: CrudOperation[]; - guest?: CrudOperation[]; - groups?: { - [userPoolGroupName: string]: CrudOperation[]; - }; - }; - lambdaFunction: string; -}; - -export type ApiRequirements = { authSelections: 'identityPoolAndUserPool'; allowUnauthenticatedIdentities?: boolean }; - -export type ApigwWalkthroughReturnPromise = Promise<{ - answers: ApigwAnswers; -}>; - -export type ApigwAnswers = { - paths: { [pathName: string]: ApigwPath }; - resourceName: string; - functionArns?: string[]; - dependsOn?: Record[]; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/appsync-user-input-types.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/appsync-user-input-types.ts deleted file mode 100644 index ea2bbe2414..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/appsync-user-input-types.ts +++ /dev/null @@ -1,171 +0,0 @@ -/** - * Defines the json object expected by `amplify api category - */ -export interface AppSyncCLIInputs { - /** - * The schema version. - */ - version: 1; - /** - * The service configuration that will be interpreted by Amplify. - */ - serviceConfiguration: AppSyncServiceConfig; -} - -/** - * Configuration exposed by AppSync. Currently this is the only API type supported by Amplify headless mode. - */ -export interface AppSyncServiceConfig { - /** - * The service name of the resource provider. - */ - serviceName: 'AppSync'; - /** - * The name of the API that will be created. - */ - apiName: string; - /** - * The auth type that will be used by default. - */ - defaultAuthType: AppSyncAuthType; - /** - * Additional methods of authenticating API requests. - */ - additionalAuthTypes?: AppSyncAuthType[]; - /** - * The strategy for resolving API write conflicts. - */ - conflictResolution?: ConflictResolution; -} - -/** - * Defines a strategy for resolving API write conflicts. - */ -export interface ConflictResolution { - /** - * The strategy that will be used for all models by default. - */ - defaultResolutionStrategy?: ResolutionStrategy; - /** - * Strategies that will be used for individual models. - */ - perModelResolutionStrategy?: PerModelResolutionstrategy[]; -} - -/** - * Defines a resolution strategy for a single model. - */ -export interface PerModelResolutionstrategy { - /** - * The resolution strategy for the model. - */ - resolutionStrategy: ResolutionStrategy; - /** - * The model name. - */ - entityName: string; -} - -/** - * Resolution strategies provided by AppSync. See https://docs.aws.amazon.com/appsync/latest/devguide/conflict-detection-and-sync.html for details. - */ -export interface PredefinedResolutionStrategy { - type: 'OPTIMISTIC_CONCURRENCY' | 'AUTOMERGE' | 'NONE'; -} - -/** - * Resolution strategy using a custom lambda function. - */ -export interface LambdaResolutionStrategy { - type: 'LAMBDA'; - /** - * The lambda function used to resolve conflicts. - */ - resolver: LambdaConflictResolver; -} - -export type LambdaConflictResolver = NewLambdaConflictResolver | ExistingLambdaConflictResolver; - -/** - * Defines a new lambda conflict resolver. Using this resolver type will create a new lambda function with boilerplate resolver logic. - */ -export interface NewLambdaConflictResolver { - type: 'NEW'; -} - -/** - * Defines an lambda conflict resolver that uses an existing lambda function. - */ -export interface ExistingLambdaConflictResolver { - type: 'EXISTING'; - /** - * The name of the lambda function (this must be a lambda function that exists in the Amplify project). - */ - name: string; - /** - * The lambda function region. - */ - region?: string; - /** - * A lambda function ARN. This could be an ARN outside of the Amplify project but in that case extra care must be taken to ensure the AppSync API has access to the Lambda. - */ - arn?: string; -} - -export type ResolutionStrategy = PredefinedResolutionStrategy | LambdaResolutionStrategy; - -export type AppSyncAuthType = - | AppSyncAPIKeyAuthType - | AppSyncAWSIAMAuthType - | AppSyncCognitoUserPoolsAuthType - | AppSyncOpenIDConnectAuthType - | AppSyncLambdaAuthType; - -/** - * Specifies that the AppSync API should be secured using an API key. - */ -export interface AppSyncAPIKeyAuthType { - mode: 'API_KEY'; - expirationTime?: number; - apiKeyExpirationDate?: Date; - keyDescription?: string; -} - -/** - * Specifies that the AppSync API should be secured using AWS IAM. - */ -export interface AppSyncAWSIAMAuthType { - mode: 'AWS_IAM'; -} - -/** - * Specifies that the AppSync API should be secured using Cognito. - */ -export interface AppSyncCognitoUserPoolsAuthType { - mode: 'AMAZON_COGNITO_USER_POOLS'; - /** - * The user pool that will be used to authenticate requests. - */ - cognitoUserPoolId?: string; -} - -/** - * Specifies that the AppSync API should be secured using OpenID. - */ -export interface AppSyncOpenIDConnectAuthType { - mode: 'OPENID_CONNECT'; - openIDProviderName: string; - openIDIssuerURL: string; - openIDClientID: string; - openIDAuthTTL?: string; - openIDIatTTL?: string; -} - -/** - * Specifies that the AppSync API should be secured using Lambda. - */ -export interface AppSyncLambdaAuthType { - mode: 'AWS_LAMBDA'; - lambdaFunction: string; - ttlSeconds?: string; -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.ts deleted file mode 100644 index a970ed484f..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.ts +++ /dev/null @@ -1,739 +0,0 @@ -import os from 'os'; -import { - $TSContext, - AmplifyCategories, - AmplifySupportedService, - exitOnNextTick, - isResourceNameUnique, - open, - pathManager, - ResourceDoesNotExistError, - stateManager, -} from '@aws-amplify/amplify-cli-core'; -import { byValues, printer, prompter } from '@aws-amplify/amplify-prompts'; -import inquirer from 'inquirer'; -import _ from 'lodash'; -import { v4 as uuid } from 'uuid'; -import { ADMIN_QUERIES_NAME } from '../../../category-constants'; -import { ApigwInputState } from '../apigw-input-state'; -import { CrudOperation, PermissionSetting } from '../cdk-stack-builder'; -import { getAllDefaults } from '../default-values/apigw-defaults'; -import { ApigwAnswers, ApigwPath, ApigwWalkthroughReturnPromise, ApiRequirements } from '../service-walkthrough-types/apigw-types'; -import { checkForPathOverlap, formatCFNPathParamsForExpressJs, validatePathName } from '../utils/rest-api-path-utils'; - -const category = AmplifyCategories.API; -const serviceName = AmplifySupportedService.APIGW; -const elasticContainerServiceName = 'ElasticContainer'; - -export async function serviceWalkthrough(context: $TSContext): ApigwWalkthroughReturnPromise { - const allDefaultValues = getAllDefaults(context.amplify.getProjectDetails()); - - const resourceName = await askApiName(context, allDefaultValues.resourceName); - const answers = { paths: {}, resourceName, dependsOn: undefined }; - - return pathFlow(context, answers); -} - -export async function updateWalkthrough(context: $TSContext) { - const { allResources } = await context.amplify.getResourceStatus(); - const allDefaultValues = getAllDefaults(context.amplify.getProjectDetails()); - const resources = allResources - .filter((resource) => resource.service === serviceName && resource.mobileHubMigrated !== true) - .map((resource) => resource.resourceName); - - if (resources.length === 0) { - const errMessage = 'No REST API resource to update. Use "amplify add api" command to create a new REST API'; - printer.error(errMessage); - await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - exitOnNextTick(0); - return; - } - - let answers: any = { - paths: [], - }; - - const selectedApiName = await prompter.pick<'one', string>('Select the REST API you want to update:', resources); - let updateApiOperation = await prompter.pick<'one', string>('What would you like to do?', [ - { name: 'Add another path', value: 'add' }, - { name: 'Update path', value: 'update' }, - { name: 'Remove path', value: 'remove' }, - ]); - - // Inquirer does not currently support combining 'when' and 'default', so - // manually set the operation if the user ended up here via amplify api add. - if (context.input.command === 'add') { - updateApiOperation = 'add'; - } - - if (selectedApiName === ADMIN_QUERIES_NAME) { - const errMessage = `The Admin Queries API is maintained through the Auth category and should be updated using 'amplify update auth' command`; - printer.warn(errMessage); - await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - exitOnNextTick(0); - } - - const projRoot = pathManager.findProjectRoot(); - if (!stateManager.resourceInputsJsonExists(projRoot, category, selectedApiName)) { - // Not yet migrated - await migrate(context, projRoot, selectedApiName); - - // chose not to migrate - if (!stateManager.resourceInputsJsonExists(projRoot, category, selectedApiName)) { - exitOnNextTick(0); - } - } - - const parameters = stateManager.getResourceInputsJson(projRoot, category, selectedApiName); - parameters.resourceName = selectedApiName; - - Object.assign(allDefaultValues, parameters); - answers = { ...answers, ...parameters }; - [answers.uuid] = uuid().split('-'); - const pathNames = Object.keys(answers.paths); - let updatedResult = {}; - - switch (updateApiOperation) { - case 'add': { - updatedResult = pathFlow(context, answers); - break; - } - case 'remove': { - const pathToRemove = await inquirer.prompt({ - name: 'path', - message: 'Select the path to remove', - type: 'list', - choices: pathNames, - }); - - delete answers.paths[pathToRemove.path]; - - const { dependsOn, functionArns } = await findDependsOn(answers.paths); - answers.dependsOn = dependsOn; - answers.functionArns = functionArns; - - updatedResult = { answers }; - break; - } - case 'update': { - const pathToEdit = await inquirer.prompt({ - name: 'pathName', - message: 'Select the path to edit', - type: 'list', - choices: pathNames, - }); - - // removing path from paths list - const currentPath: ApigwPath = answers.paths[pathToEdit.pathName]; - delete answers.paths[pathToEdit.pathName]; - - updatedResult = pathFlow(context, answers, currentPath); - break; - } - default: { - throw new Error(`Unrecognized API update operation "${updateApiOperation}"`); - } - } - - return updatedResult; -} - -async function pathFlow(context: $TSContext, answers: ApigwAnswers, currentPath?: ApigwPath): ApigwWalkthroughReturnPromise { - const pathsAnswer = await askPaths(context, answers, currentPath); - return { answers: pathsAnswer }; -} - -async function askApiName(context: $TSContext, defaultResourceName: string) { - const apiNameValidator = (input: string) => { - const amplifyValidatorOutput = context.amplify.inputValidation({ - validation: { - operator: 'regex', - value: '^[a-zA-Z0-9]+$', - onErrorMsg: 'Resource name should be alphanumeric', - }, - required: true, - })(input); - - const adminQueriesName = 'AdminQueries'; - if (input === adminQueriesName) { - return `${adminQueriesName} is a reserved name for REST API resources for use by the auth category. Run "amplify update auth" to create an Admin Queries API.`; - } - - let uniqueCheck = false; - try { - uniqueCheck = isResourceNameUnique(category, input); - } catch (e) { - return e.message || e; - } - return typeof amplifyValidatorOutput === 'string' ? amplifyValidatorOutput : uniqueCheck; - }; - - const resourceName = await prompter.input<'one', string>( - 'Provide a friendly name for your resource to be used as a label for this category in the project:', - { initial: defaultResourceName, validate: apiNameValidator }, - ); - - return resourceName; -} - -async function askPermissions( - context: $TSContext, - answers: Record, - currentPath?: ApigwPath, -): Promise<{ - setting?: PermissionSetting; - auth?: CrudOperation[]; - open?: boolean; - userPoolGroups?: Record; - guest?: CrudOperation[]; -}> { - while (true) { - const apiAccess = await prompter.yesOrNo('Restrict API access?', currentPath?.permissions?.setting !== PermissionSetting.OPEN); - - if (!apiAccess) { - return { setting: PermissionSetting.OPEN }; - } - - const userPoolGroupList = context.amplify.getUserPoolGroupList(); - - let permissionSelected = 'Auth/Guest Users'; - const permissions: Record = {}; - - if (userPoolGroupList.length > 0) { - do { - if (permissionSelected === 'Learn more') { - printer.blankLine(); - printer.info( - 'You can restrict access using CRUD policies for Authenticated Users, Guest Users, or on individual Group that users belong to' + - ' in a User Pool. If a user logs into your application and is not a member of any group they will use policy set for ' + - '“Authenticated Users”, however if they belong to a group they will only get the policy associated with that specific group.', - ); - printer.blankLine(); - } - const permissionSelection = await prompter.pick<'one', string>('Restrict access by:', [ - 'Auth/Guest Users', - 'Individual Groups', - 'Both', - 'Learn more', - ]); - - permissionSelected = permissionSelection; - } while (permissionSelected === 'Learn more'); - } - - if (permissionSelected === 'Both' || permissionSelected === 'Auth/Guest Users') { - const permissionSetting = await prompter.pick<'one', string>( - 'Who should have access?', - [ - { - name: 'Authenticated users only', - value: PermissionSetting.PRIVATE, - }, - { - name: 'Authenticated and Guest users', - value: PermissionSetting.PROTECTED, - }, - ], - { initial: currentPath?.permissions?.setting === PermissionSetting.PROTECTED ? 1 : 0 }, - ); - - permissions.setting = permissionSetting; - - let { - permissions: { auth: authPermissions }, - } = currentPath || { permissions: { auth: [] } }; - let { - permissions: { guest: unauthPermissions }, - } = currentPath || { permissions: { guest: [] } }; - - if (permissionSetting === PermissionSetting.PRIVATE) { - permissions.auth = await askCRUD('Authenticated', authPermissions); - - const apiRequirements: ApiRequirements = { authSelections: 'identityPoolAndUserPool' }; - - await ensureAuth(context, apiRequirements, answers.resourceName); - } - - if (permissionSetting === PermissionSetting.PROTECTED) { - permissions.auth = await askCRUD('Authenticated', authPermissions); - permissions.guest = await askCRUD('Guest', unauthPermissions); - const apiRequirements: ApiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }; - - await ensureAuth(context, apiRequirements, answers.resourceName); - } - } - - if (permissionSelected === 'Both' || permissionSelected === 'Individual Groups') { - // Enable Auth if not enabled - - const apiRequirements: ApiRequirements = { authSelections: 'identityPoolAndUserPool' }; - - await ensureAuth(context, apiRequirements, answers.resourceName); - - // Get Auth resource name - const authResourceName = getAuthResourceName(); - answers.authResourceName = authResourceName; - - let defaultSelectedGroups: string[] = []; - - if (currentPath?.permissions?.groups) { - defaultSelectedGroups = Object.keys(currentPath.permissions.groups); - } - - let selectedUserPoolGroupList = await prompter.pick<'many', string>('Select groups:', userPoolGroupList, { - initial: byValues(defaultSelectedGroups)(userPoolGroupList), - returnSize: 'many', - pickAtLeast: 1, - }); - - // if single user pool group is selected, convert to array - if (selectedUserPoolGroupList && !Array.isArray(selectedUserPoolGroupList)) { - selectedUserPoolGroupList = [selectedUserPoolGroupList]; - } - - for (const selectedUserPoolGroup of selectedUserPoolGroupList) { - let defaults = []; - if (currentPath?.permissions?.groups?.[selectedUserPoolGroup]) { - defaults = currentPath.permissions.groups[selectedUserPoolGroup]; - } - if (!permissions.groups) { - permissions.groups = {}; - } - permissions.groups[selectedUserPoolGroup] = await askCRUD(selectedUserPoolGroup, defaults); - } - - if (!permissions.setting) { - permissions.setting = PermissionSetting.PRIVATE; - } - } - return permissions; - } -} - -async function ensureAuth(context: $TSContext, apiRequirements: ApiRequirements, resourceName: string) { - const checkResult: any = await context.amplify.invokePluginMethod(context, 'auth', undefined, 'checkRequirements', [ - apiRequirements, - context, - 'api', - resourceName, - ]); - - // If auth is imported and configured, we have to throw the error instead of printing since there is no way to adjust the auth - // configuration. - if (checkResult.authImported === true && checkResult.errors && checkResult.errors.length > 0) { - throw new Error(checkResult.errors.join(os.EOL)); - } - - if (checkResult.errors && checkResult.errors.length > 0) { - printer.warn(checkResult.errors.join(os.EOL)); - } - - // If auth is not imported and there were errors, adjust or enable auth configuration - if (!checkResult.authEnabled || !checkResult.requirementsMet) { - try { - await context.amplify.invokePluginMethod(context, 'auth', undefined, 'externalAuthEnable', [ - context, - AmplifyCategories.API, - resourceName, - apiRequirements, - ]); - } catch (error) { - printer.error(error); - throw error; - } - } -} - -async function askCRUD(userType: string, permissions: CrudOperation[] = []) { - const crudOptions = [CrudOperation.CREATE, CrudOperation.READ, CrudOperation.UPDATE, CrudOperation.DELETE]; - const crudAnswers = await prompter.pick<'many', string>(`What permissions do you want to grant to ${userType} users?`, crudOptions, { - returnSize: 'many', - initial: byValues(permissions), - pickAtLeast: 1, - }); - - return crudAnswers; -} - -async function askPaths(context: $TSContext, answers: Record, currentPath?: ApigwPath): Promise { - const existingFunctions = functionsExist(); - - let defaultFunctionType = 'newFunction'; - const defaultChoice = { - name: 'Create a new Lambda function', - value: defaultFunctionType, - }; - const choices = [defaultChoice]; - - if (existingFunctions) { - choices.push({ - name: 'Use a Lambda function already added in the current Amplify project', - value: 'projectFunction', - }); - } - - const paths = answers.paths; - - let addAnotherPath: boolean; - do { - let pathName: string; - let isPathValid: boolean; - do { - pathName = await prompter.input('Provide a path (e.g., /book/{isbn}):', { - initial: currentPath ? currentPath.name : '/items', - validate: validatePathName, - }); - - const overlapCheckResult = checkForPathOverlap(pathName, Object.keys(paths)); - if (overlapCheckResult === false) { - // The path provided by the user is valid, and doesn't overlap with any other endpoints that they've stood up with API Gateway. - isPathValid = true; - } else { - // The path provided by the user overlaps with another endpoint that they've stood up with API Gateway. - // Ask them if they're okay with this. If they are, then we'll consider their provided path to be valid. - const higherOrderPath = overlapCheckResult.higherOrderPath; - const lowerOrderPath = overlapCheckResult.lowerOrderPath; - - isPathValid = await prompter.confirmContinue( - `The path ${lowerOrderPath} overlaps with ${higherOrderPath}. Users authorized to access ${higherOrderPath} will also have access` + - ` to ${lowerOrderPath}. Are you sure you want to continue?`, - ); - } - } while (!isPathValid); - - const functionType = await prompter.pick<'one', string>('Choose a Lambda source', choices, { initial: choices.indexOf(defaultChoice) }); - - let path = { name: pathName }; - let lambda; - do { - lambda = await askLambdaSource(context, functionType, pathName, currentPath); - } while (!lambda); - const permissions = await askPermissions(context, answers, currentPath); - path = { ...path, ...lambda, permissions }; - paths[pathName] = path; - - if (currentPath) { - break; - } - - addAnotherPath = await prompter.confirmContinue('Do you want to add another path?'); - } while (addAnotherPath); - - const { dependsOn, functionArns } = await findDependsOn(paths); - - return { paths, dependsOn, resourceName: answers.resourceName, functionArns }; -} - -async function findDependsOn(paths: Record[]) { - // go thru all paths and add lambdaFunctions to dependsOn and functionArns uniquely - const dependsOn = []; - const functionArns = []; - - for (const path of Object.values(paths)) { - if (path.lambdaFunction && !path.lambdaArn) { - if (!dependsOn.find((func) => func.resourceName === path.lambdaFunction)) { - dependsOn.push({ - category: 'function', - resourceName: path.lambdaFunction, - attributes: ['Name', 'Arn'], - }); - } - } - - if (!functionArns.find((func) => func.lambdaFunction === path.lambdaFunction)) { - functionArns.push({ - lambdaFunction: path.lambdaFunction, - lambdaArn: path.lambdaArn, - }); - } - - if (path?.permissions?.groups) { - const userPoolGroups = Object.keys(path.permissions.groups); - if (userPoolGroups.length > 0) { - // Get auth resource name - - const authResourceName = getAuthResourceName(); - - if (!dependsOn.find((resource) => resource.resourceName === authResourceName)) { - dependsOn.push({ - category: 'auth', - resourceName: authResourceName, - attributes: ['UserPoolId'], - }); - } - - userPoolGroups.forEach((group) => { - if (!dependsOn.find((resource) => resource.attributes[0] === `${group}GroupRole`)) { - dependsOn.push({ - category: 'auth', - resourceName: 'userPoolGroups', - attributes: [`${group}GroupRole`], - }); - } - }); - } - } - } - return { dependsOn, functionArns }; -} - -function getAuthResourceName(): string { - const meta = stateManager.getMeta(); - const authResources = (Object.entries(meta?.auth) || []).filter( - ([_, resource]: [key: string, resource: Record]) => resource.service === AmplifySupportedService.COGNITO, - ); - if (authResources.length === 0) { - throw new Error('No auth resource found. Add it using amplify add auth'); - } - - const [authResourceName] = authResources[0]; - return authResourceName; -} - -function functionsExist() { - const meta = stateManager.getMeta(); - if (!meta.function) { - return false; - } - - const functionResources = meta.function; - const lambdaFunctions = []; - Object.keys(functionResources).forEach((resourceName) => { - if (functionResources[resourceName].service === AmplifySupportedService.LAMBDA) { - lambdaFunctions.push(resourceName); - } - }); - - if (lambdaFunctions.length === 0) { - return false; - } - - return true; -} - -async function askLambdaSource(context: $TSContext, functionType: string, path: string, currentPath?: ApigwPath) { - switch (functionType) { - case 'arn': - return askLambdaArn(context, currentPath); - case 'projectFunction': - return askLambdaFromProject(currentPath); - case 'newFunction': - return newLambdaFunction(context as any, path); - default: - throw new Error('Type not supported'); - } -} - -async function newLambdaFunction(context: $TSContext, path: string) { - let params = { - functionTemplate: { - parameters: { - path, - expressPath: formatCFNPathParamsForExpressJs(path), - }, - }, - }; - - const resourceName = await context.amplify.invokePluginMethod(context, AmplifyCategories.FUNCTION, undefined, 'add', [ - context, - 'awscloudformation', - AmplifySupportedService.LAMBDA, - params, - ]); - - printer.success('Succesfully added the Lambda function locally'); - - return { lambdaFunction: resourceName }; -} - -async function askLambdaFromProject(currentPath?: ApigwPath) { - const meta = stateManager.getMeta(); - const lambdaFunctions = []; - Object.keys(meta?.function || {}).forEach((resourceName) => { - if (meta.function[resourceName].service === AmplifySupportedService.LAMBDA) { - lambdaFunctions.push(resourceName); - } - }); - - const lambdaFunction = await prompter.pick<'one', string>('Choose the Lambda function to invoke by this path', lambdaFunctions, { - initial: currentPath ? lambdaFunctions.indexOf(currentPath.lambdaFunction) : 0, - }); - - return { lambdaFunction }; -} - -async function askLambdaArn(context: $TSContext, currentPath?: ApigwPath) { - const lambdaFunctions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getLambdaFunctions'); - - const lambdaOptions = lambdaFunctions.map((lambdaFunction) => ({ - value: lambdaFunction.FunctionArn, - name: `${lambdaFunction.FunctionName} (${lambdaFunction.FunctionArn})`, - })); - - if (lambdaOptions.length === 0) { - printer.error('You do not have any Lambda functions configured for the selected Region'); - return null; - } - - const lambdaCloudOptionQuestion = { - type: 'list', - name: 'lambdaChoice', - message: 'Select a Lambda function', - choices: lambdaOptions, - default: currentPath && currentPath.lambdaFunction ? `${currentPath.lambdaFunction}` : `${lambdaOptions[0].value}`, - }; - - let lambdaOption; - while (!lambdaOption) { - try { - lambdaOption = await inquirer.prompt([lambdaCloudOptionQuestion]); - } catch (err) { - printer.error('Select a Lambda Function'); - } - } - - const lambdaCloudOptionAnswer = lambdaFunctions.find((lambda) => lambda.FunctionArn === lambdaOption.lambdaChoice); - - return { - lambdaArn: lambdaCloudOptionAnswer.FunctionArn, - lambdaFunction: lambdaCloudOptionAnswer.FunctionName, - }; -} - -export async function migrate(context: $TSContext, projectPath: string, resourceName: string) { - const apigwInputState = new ApigwInputState(context, resourceName); - - if (resourceName === ADMIN_QUERIES_NAME) { - const meta = stateManager.getMeta(); - const adminQueriesDependsOn = _.get(meta, [AmplifyCategories.API, ADMIN_QUERIES_NAME, 'dependsOn'], undefined); - - if (!adminQueriesDependsOn) { - throw new Error('Failed to migrate Admin Queries API. Could not find expected information in amplify-meta.json.'); - } - - const functionName = adminQueriesDependsOn.filter((dependency) => dependency.category === AmplifyCategories.FUNCTION)?.[0] - ?.resourceName; - - const adminQueriesProps = { - apiName: resourceName, - authResourceName: getAuthResourceName(), - functionName, - dependsOn: adminQueriesDependsOn, - }; - - return apigwInputState.migrateAdminQueries(adminQueriesProps); - } - - return apigwInputState.migrateApigwResource(resourceName); -} - -export function getIAMPolicies(resourceName: string, crudOptions: string[]) { - let policy = {}; - const actions = []; - - crudOptions.forEach((crudOption) => { - switch (crudOption) { - case CrudOperation.CREATE: - actions.push('apigateway:POST', 'apigateway:PUT'); - break; - case CrudOperation.UPDATE: - actions.push('apigateway:PATCH'); - break; - case CrudOperation.READ: - actions.push('apigateway:GET', 'apigateway:HEAD', 'apigateway:OPTIONS'); - break; - case CrudOperation.DELETE: - actions.push('apigateway:DELETE'); - break; - default: - printer.info(`${crudOption} not supported`); - } - }); - - policy = { - Effect: 'Allow', - Action: actions, - Resource: [ - { - 'Fn::Join': [ - '', - [ - 'arn:aws:apigateway:', - { - Ref: 'AWS::Region', - }, - '::/restapis/', - { - Ref: `${category}${resourceName}ApiName`, - }, - '/*', - ], - ], - }, - ], - }; - - const attributes = ['ApiName', 'ApiId']; - - return { policy, attributes }; -} - -export const openConsole = async (context?: $TSContext) => { - const amplifyMeta = stateManager.getMeta(); - const categoryAmplifyMeta = amplifyMeta[category]; - const { Region } = amplifyMeta.providers.awscloudformation; - - const restApis = Object.keys(categoryAmplifyMeta).filter((resourceName) => { - const resource = categoryAmplifyMeta[resourceName]; - return ( - resource.output && - (resource.service === serviceName || (resource.service === elasticContainerServiceName && resource.apiType === 'REST')) - ); - }); - - if (restApis) { - let url; - - const selectedApi = await prompter.pick<'one', string>('Select the API', restApis); - const selectedResource = categoryAmplifyMeta[selectedApi]; - - if (selectedResource.service === serviceName) { - const { - output: { ApiId }, - } = selectedResource; - - url = `https://${Region}.console.aws.amazon.com/apigateway/home?region=${Region}#/apis/${ApiId}/resources/`; - } else { - // Elastic Container API - const { - output: { PipelineName, ServiceName, ClusterName }, - } = selectedResource; - const codePipeline = 'CodePipeline'; - const elasticContainer = 'ElasticContainer'; - - const selectedConsole = await prompter.pick<'one', string>('Which console do you want to open?', [ - { - name: 'Elastic Container Service (Deployed container status)', - value: elasticContainer, - }, - { - name: 'CodePipeline (Container build status)', - value: codePipeline, - }, - ]); - - if (selectedConsole === elasticContainer) { - url = `https://console.aws.amazon.com/ecs/home?region=${Region}#/clusters/${ClusterName}/services/${ServiceName}/details`; - } else if (selectedConsole === codePipeline) { - url = `https://${Region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/${PipelineName}/view`; - } else { - printer.error('Option not available'); - return; - } - } - - await open(url, { wait: false }); - } else { - printer.error('There are no REST APIs pushed to the cloud'); - } -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-db-config.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-db-config.ts deleted file mode 100644 index 70f461d702..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-db-config.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { prompter, printer, minLength, integer } from '@aws-amplify/amplify-prompts'; -import { ImportedDataSourceType, ImportedDataSourceConfig } from '@aws-amplify/graphql-transformer-core'; -import { ImportedRDSType } from '@aws-amplify/graphql-transformer-core'; -import { parseDatabaseUrl } from '../utils/database-url'; - -/** - * Gathers database configuration information - * @param engine the database engine - * @returns a promise resolving to the database configuration to be used as an AppSync Data Source - */ -export const databaseConfigurationInputWalkthrough = async (engine: ImportedDataSourceType): Promise => { - const defaultPorts = { - [ImportedRDSType.MYSQL]: 3306, - [ImportedRDSType.POSTGRESQL]: 5432, - }; - - printer.info('Please provide the following database connection information:'); - const url = await prompter.input('Enter the database url or host name:', { - validate: minLength(1), - }); - - let isValidUrl = true; - const parsedDatabaseUrl = parseDatabaseUrl(url); - let { host, port, database, username, password } = parsedDatabaseUrl; - - if (!host) { - isValidUrl = false; - host = url; - } - if (!isValidUrl || !port) { - port = await prompter.input<'one', number>('Enter the port number:', { - transform: (input) => Number.parseInt(input, 10), - validate: integer(), - initial: defaultPorts[engine] ?? 3306, - }); - } - - // Get the database user credentials - if (!isValidUrl || !username) { - username = await prompter.input('Enter the username:', { - validate: minLength(1), - }); - } - - if (!isValidUrl || !password) { - password = await prompter.input('Enter the password:', { hidden: true, validate: minLength(1) }); - } - - if (!isValidUrl || !database) { - database = await prompter.input('Enter the database name:', { - validate: minLength(1), - }); - } - - return { - engine, - database, - host, - port, - username, - password, - }; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.ts deleted file mode 100644 index 3d97a399ea..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.ts +++ /dev/null @@ -1,292 +0,0 @@ -import * as path from 'path'; -import { - $TSContext, - exitOnNextTick, - ResourceCredentialsNotFoundError, - ResourceDoesNotExistError, - pathManager, - JSONUtilities, -} from '@aws-amplify/amplify-cli-core'; -import { printer, prompter } from '@aws-amplify/amplify-prompts'; -import chalk from 'chalk'; -import { DataApiParams } from 'graphql-relational-schema-transformer'; -import ora from 'ora'; -import { rootStackFileName } from '@aws-amplify/amplify-provider-awscloudformation'; - -const spinner = ora(''); -const category = 'api'; -const providerName = 'awscloudformation'; - -export async function serviceWalkthrough(context: $TSContext, datasourceMetadata: Record) { - const amplifyMeta = context.amplify.getProjectMeta(); - - // Verify that an API exists in the project before proceeding. - if (amplifyMeta == null || amplifyMeta[category] == null || Object.keys(amplifyMeta[category]).length === 0) { - const errMessage = - 'You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.'; - printer.error(errMessage); - await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - exitOnNextTick(0); - } - - // Loop through to find the AppSync API Resource Name - let appSyncApi: string; - const apis = Object.keys(amplifyMeta[category]); - - for (const api of apis) { - if (amplifyMeta[category][api].service === 'AppSync') { - appSyncApi = api; - break; - } - } - - // If an AppSync API does not exist, inform the user to create the AppSync API - if (!appSyncApi) { - const errMessage = - 'You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.'; - printer.error(errMessage); - await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - exitOnNextTick(0); - } - - const { inputs, availableRegions } = datasourceMetadata; - - // FIXME: We should NOT be treating CloudFormation templates as inputs to prompts! This a temporary exception while we move team-provider-info to a service. - const cfnJson: any = JSONUtilities.readJson( - path.join(pathManager.getCurrentCloudRootStackDirPath(pathManager.findProjectRoot()), rootStackFileName), - ); - const cfnJsonParameters = cfnJson?.Resources[`api${appSyncApi}`]?.Properties?.Parameters || {}; - let selectedRegion = cfnJsonParameters?.rdsRegion; - // Region Question - if (!selectedRegion) { - selectedRegion = await promptWalkthroughQuestion(inputs, 0, availableRegions); - } - - const AWS = await getAwsClient(context, 'list'); - - // Prepare the SDK with the region - AWS.config.update({ - region: selectedRegion, - }); - - // RDS Cluster Question - let selectedClusterArn = cfnJsonParameters?.rdsClusterIdentifier; - let clusterResourceId = getRdsClusterResourceIdFromArn(selectedClusterArn, AWS); - if (!selectedClusterArn || !clusterResourceId) { - ({ selectedClusterArn, clusterResourceId } = await selectCluster(context, inputs, AWS)); - } - - // Secret Store Question - let selectedSecretArn = cfnJsonParameters?.rdsSecretStoreArn; - if (!selectedSecretArn) { - selectedSecretArn = await getSecretStoreArn(context, inputs, clusterResourceId, AWS); - } - - // Database Name Question - let selectedDatabase = cfnJsonParameters?.rdsDatabaseName; - if (!selectedDatabase) { - selectedDatabase = await selectDatabase(context, inputs, selectedClusterArn, selectedSecretArn, AWS); - } - - return { - region: selectedRegion, - dbClusterArn: selectedClusterArn, - secretStoreArn: selectedSecretArn, - databaseName: selectedDatabase, - resourceName: appSyncApi, - }; -} - -async function getRdsClusterResourceIdFromArn(arn: string | undefined, AWS) { - // If the arn was not already existing in cloudformation template, return undefined to prompt for input. - if (!arn) { - return; - } - - const RDS = new AWS.RDS(); - const describeDBClustersResult = await RDS.describeDBClusters().promise(); - const rawClusters = describeDBClustersResult.DBClusters; - const identifiedCluster = rawClusters.find((cluster) => cluster.DBClusterArn === arn); - return identifiedCluster.DBClusterIdentifier; -} - -/** - * - * @param {*} inputs - */ -async function selectCluster(context: $TSContext, inputs, AWS) { - const RDS = new AWS.RDS(); - - const describeDBClustersResult = await RDS.describeDBClusters().promise(); - const rawClusters = describeDBClustersResult.DBClusters; - - const clusters = new Map(); - const serverlessClusters = rawClusters.filter((cluster) => cluster.EngineMode === 'serverless'); - - if (serverlessClusters.length === 0) { - const errMessage = 'No properly configured Aurora Serverless clusters found.'; - - printer.error(errMessage); - - await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - - exitOnNextTick(0); - } - - for (const cluster of serverlessClusters) { - clusters.set(cluster.DBClusterIdentifier, cluster); - } - - if (clusters.size > 1) { - const clusterIdentifier = await promptWalkthroughQuestion(inputs, 1, Array.from(clusters.keys())); - const selectedCluster = clusters.get(clusterIdentifier); - - return { - selectedClusterArn: selectedCluster.DBClusterArn, - clusterResourceId: selectedCluster.DbClusterResourceId, - }; - } - - // Pick first and only value - const firstCluster = Array.from(clusters.values())[0]; - - printer.info(`${chalk.green('✔')} Only one Cluster was found: '${firstCluster.DBClusterIdentifier}' was automatically selected.`); - - return { - selectedClusterArn: firstCluster.DBClusterArn, - clusterResourceId: firstCluster.DbClusterResourceId, - }; -} - -/** - * - * @param {*} inputs - * @param {*} clusterResourceId - */ -async function getSecretStoreArn(context: $TSContext, inputs, clusterResourceId, AWS) { - const SecretsManager = new AWS.SecretsManager(); - const NextToken = 'NextToken'; - let rawSecrets = []; - const params = { - MaxResults: 20, - }; - - const listSecretsResult = await SecretsManager.listSecrets(params).promise(); - - rawSecrets = listSecretsResult.SecretList; - let token = listSecretsResult.NextToken; - while (token) { - params[NextToken] = token; - const tempSecretsResult = await SecretsManager.listSecrets(params).promise(); - rawSecrets = [...rawSecrets, ...tempSecretsResult.SecretList]; - token = tempSecretsResult.NextToken; - } - - const secrets = new Map(); - const secretsForCluster = rawSecrets.filter((secret) => secret.Name.startsWith(`rds-db-credentials/${clusterResourceId}`)); - - if (secretsForCluster.length === 0) { - const errMessage = 'No RDS access credentials found in the AWS Secrect Manager.'; - - printer.error(errMessage); - - await context.usageData.emitError(new ResourceCredentialsNotFoundError(errMessage)); - - exitOnNextTick(0); - } - - for (const secret of secretsForCluster) { - secrets.set(secret.Name, secret.ARN); - } - - let selectedSecretArn; - - if (secrets.size > 1) { - // Kick off questions flow - const selectedSecretName = await promptWalkthroughQuestion(inputs, 2, Array.from(secrets.keys())); - selectedSecretArn = secrets.get(selectedSecretName); - } else { - // Pick first and only value - selectedSecretArn = Array.from(secrets.values())[0]; - - printer.info(`${chalk.green('✔')} Only one Secret was found for the cluster: '${selectedSecretArn}' was automatically selected.`); - } - - return selectedSecretArn; -} - -/** - * - * @param {*} inputs - * @param {*} clusterArn - * @param {*} secretArn - */ -async function selectDatabase(context: $TSContext, inputs, clusterArn, secretArn, AWS) { - // Database Name Question - const DataApi = new AWS.RDSDataService(); - const params = new DataApiParams(); - const databaseList = []; - params.secretArn = secretArn; - params.resourceArn = clusterArn; - params.sql = 'SHOW databases'; - - spinner.start('Fetching Aurora Serverless cluster...'); - - try { - const dataApiResult = await DataApi.executeStatement(params).promise(); - const excludedDatabases = ['information_schema', 'performance_schema', 'mysql', 'sys']; - - databaseList.push(...dataApiResult.records.map((record) => record[0].stringValue).filter((name) => !excludedDatabases.includes(name))); - - spinner.succeed('Fetched Aurora Serverless cluster.'); - } catch (err) { - spinner.fail(err.message); - - if (err.code === 'BadRequestException' && /Access denied for user/.test(err.message)) { - const msg = - `Ensure that '${secretArn}' contains your database credentials. ` + - 'Please note that Aurora Serverless does not support IAM database authentication.'; - printer.error(msg); - } - } - - if (databaseList.length === 0) { - const errMessage = 'No database found in the selected cluster.'; - - printer.error(errMessage); - - await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - - exitOnNextTick(0); - } - - if (databaseList.length > 1) { - return await promptWalkthroughQuestion(inputs, 3, databaseList); - } - - printer.info(`${chalk.green('✔')} Only one Database was found: '${databaseList[0]}' was automatically selected.`); - - return databaseList[0]; -} - -/** - * - * @param {*} inputs - * @param {*} questionNumber - * @param {*} choicesList - */ -async function promptWalkthroughQuestion(inputs, questionNumber, choicesList) { - const question = { - type: inputs[questionNumber].type, - name: inputs[questionNumber].key, - message: inputs[questionNumber].question, - choices: choicesList, - }; - return await prompter.pick(question.message, choicesList); -} - -async function getAwsClient(context: $TSContext, action: string) { - const providerPlugins = context.amplify.getProviderPlugins(context); - const provider = require(providerPlugins[providerName]); - return await provider.getConfiguredAWSClient(context, 'aurora-serverless', action); -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts deleted file mode 100644 index f783839475..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts +++ /dev/null @@ -1,1172 +0,0 @@ -import * as path from 'path'; -import { Duration, Expiration } from 'aws-cdk-lib'; -import { - $TSContext, - exitOnNextTick, - FeatureFlags, - open, - pathManager, - ResourceAlreadyExistsError, - ResourceDoesNotExistError, - stateManager, - UnknownResourceTypeError, - getGraphQLTransformerAuthDocLink, - ApiCategoryFacade, -} from '@aws-amplify/amplify-cli-core'; -import { UpdateApiRequest } from 'amplify-headless-interface'; -import { printer, prompter } from '@aws-amplify/amplify-prompts'; -import chalk from 'chalk'; -import * as fs from 'fs-extra'; -import { collectDirectivesByTypeNames, readProjectConfiguration } from 'graphql-transformer-core'; -import inquirer, { CheckboxQuestion, ListChoiceOptions, ListQuestion } from 'inquirer'; -import _ from 'lodash'; -import { v4 as uuid } from 'uuid'; -import { category } from '../../../category-constants'; -import { rootAssetDir } from '../aws-constants'; -import { getAllDefaults } from '../default-values/appSync-defaults'; -import { dataStoreLearnMore } from '../sync-conflict-handler-assets/syncAssets'; -import { authConfigHasApiKey, checkIfAuthExists, getAppSyncAuthConfig } from '../utils/amplify-meta-utils'; -import { authConfigToAppSyncAuthType } from '../utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; -import { checkAppsyncApiResourceMigration } from '../utils/check-appsync-api-migration'; -import { defineGlobalSandboxMode } from '../utils/global-sandbox-mode'; -import { resolverConfigToConflictResolution } from '../utils/resolver-config-to-conflict-resolution-bi-di-mapper'; - -const serviceName = 'AppSync'; -const elasticContainerServiceName = 'ElasticContainer'; -const providerName = 'awscloudformation'; -const graphqlSchemaDir = path.join(rootAssetDir, 'graphql-schemas'); - -// keep in sync with ServiceName in amplify-category-function, but probably it will not change -const FunctionServiceNameLambdaFunction = 'Lambda'; - -const authProviderChoices = [ - { - name: 'API key', - value: 'API_KEY', - }, - { - name: 'Amazon Cognito User Pool', - value: 'AMAZON_COGNITO_USER_POOLS', - }, - { - name: 'IAM', - value: 'AWS_IAM', - }, - { - name: 'OpenID Connect', - value: 'OPENID_CONNECT', - }, -]; - -const conflictResolutionHanlderChoices = [ - { - name: 'Auto Merge', - value: 'AUTOMERGE', - }, - { - name: 'Optimistic Concurrency', - value: 'OPTIMISTIC_CONCURRENCY', - }, - { - name: 'Custom Lambda', - value: 'LAMBDA', - }, - { - name: 'Learn More', - value: 'Learn More', - }, -]; - -const blankSchemaFile = 'blank-schema.graphql'; -const schemaTemplatesV1 = [ - { - name: 'Single object with fields (e.g., “Todo” with ID, name, description)', - value: 'single-object-schema.graphql', - }, - { - name: 'One-to-many relationship (e.g., “Blogs” with “Posts” and “Comments”)', - value: 'many-relationship-schema.graphql', - }, - { - name: 'Objects with fine-grained access control (e.g., a project management app with owner-based authorization)', - value: 'single-object-auth-schema.graphql', - }, - { - name: 'Blank Schema', - value: blankSchemaFile, - }, -]; - -const schemaTemplatesV2 = [ - { - name: 'Single object with fields (e.g., “Todo” with ID, name, description)', - value: 'single-object-schema-v2.graphql', - }, - { - name: 'One-to-many relationship (e.g., “Blogs” with “Posts” and “Comments”)', - value: 'many-relationship-schema-v2.graphql', - }, - { - name: 'Objects with fine-grained access control (e.g., a project management app with owner-based authorization)', - value: 'single-object-auth-schema-v2.graphql', - }, - { - name: 'Blank Schema', - value: blankSchemaFile, - }, -]; - -export const openConsole = async (context: $TSContext) => { - const amplifyMeta = stateManager.getMeta(); - const categoryAmplifyMeta = amplifyMeta[category]; - const { Region } = amplifyMeta.providers[providerName]; - - const graphQLApis = Object.keys(categoryAmplifyMeta).filter((resourceName) => { - const resource = categoryAmplifyMeta[resourceName]; - - return ( - resource.output && - (resource.service === serviceName || (resource.service === elasticContainerServiceName && resource.apiType === 'GRAPHQL')) - ); - }); - - if (graphQLApis) { - let url; - let selectedApi = graphQLApis[0]; - - if (graphQLApis.length > 1) { - ({ selectedApi } = await inquirer.prompt({ - type: 'list', - name: 'selectedApi', - choices: graphQLApis, - message: 'Please select the API', - })); - } - - const selectedResource = categoryAmplifyMeta[selectedApi]; - - if (selectedResource.service === serviceName) { - const { - output: { GraphQLAPIIdOutput }, - } = selectedResource; - const appId = amplifyMeta.providers[providerName].AmplifyAppId; - if (!appId) { - throw new Error('Missing AmplifyAppId in amplify-meta.json'); - } - - url = `https://console.aws.amazon.com/appsync/home?region=${Region}#/${GraphQLAPIIdOutput}/v1/queries`; - - const providerPlugin = await import(context.amplify.getProviderPlugins(context)[providerName]); - const { isAdminApp, region } = await providerPlugin.isAmplifyAdminApp(appId); - if (isAdminApp) { - if (region !== Region) { - printer.warn(`Region mismatch: Amplify service returned '${region}', but found '${Region}' in amplify-meta.json.`); - } - const { envName } = context.amplify.getEnvInfo(); - const baseUrl: string = providerPlugin.adminBackendMap[region].amplifyAdminUrl; - url = `${baseUrl}/admin/${appId}/${envName}/datastore`; - } - } else { - // Elastic Container API - const { - output: { PipelineName, ServiceName, ClusterName }, - } = selectedResource; - const codePipeline = 'CodePipeline'; - const elasticContainer = 'ElasticContainer'; - - const { selectedConsole } = await inquirer.prompt({ - name: 'selectedConsole', - message: 'Which console you want to open', - type: 'list', - choices: [ - { - name: 'Elastic Container Service (Deployed container status)', - value: elasticContainer, - }, - { - name: 'CodePipeline (Container build status)', - value: codePipeline, - }, - ], - }); - - if (selectedConsole === elasticContainer) { - url = `https://console.aws.amazon.com/ecs/home?region=${Region}#/clusters/${ClusterName}/services/${ServiceName}/details`; - } else if (selectedConsole === codePipeline) { - url = `https://${Region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/${PipelineName}/view`; - } else { - printer.error('Option not available'); - return; - } - } - - await open(url, { wait: false }); - } else { - printer.error('AppSync API is not pushed in the cloud.'); - } -}; - -export const serviceApiInputWalkthrough = async (context: $TSContext, serviceMetadata) => { - let continuePrompt = false; - let authConfig; - let defaultAuthType; - let resolverConfig; - const { amplify } = context; - const { inputs } = serviceMetadata; - const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); - - let resourceAnswers = {}; - resourceAnswers[inputs[1].key] = allDefaultValues[inputs[1].key]; - resourceAnswers[inputs[0].key] = resourceAnswers[inputs[1].key]; - - // - // Default authConfig - API Key (expires in 7 days) - // - authConfig = { - defaultAuthentication: { - apiKeyConfig: { - apiKeyExpirationDays: 7, - }, - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }; - - // - // Repeat prompt until user selects Continue - // - while (!continuePrompt) { - const getAuthModeChoice = async () => { - if (authConfig.defaultAuthentication.authenticationType === 'API_KEY') { - return `${ - authProviderChoices.find((choice) => choice.value === authConfig.defaultAuthentication.authenticationType).name - } (default, expiration time: ${authConfig.defaultAuthentication.apiKeyConfig.apiKeyExpirationDays} days from now)`; - } - return `${authProviderChoices.find((choice) => choice.value === authConfig.defaultAuthentication.authenticationType).name} (default)`; - }; - - const getAdditionalAuthModeChoices = async () => { - let additionalAuthModesText = ''; - authConfig.additionalAuthenticationProviders.map(async (authMode) => { - additionalAuthModesText += `, ${authProviderChoices.find((choice) => choice.value === authMode.authenticationType).name}`; - }); - return additionalAuthModesText; - }; - - const basicInfoQuestionChoices = []; - - basicInfoQuestionChoices.push({ - name: chalk`{bold Name:} ${resourceAnswers[inputs[1].key]}`, - value: 'API_NAME', - }); - - basicInfoQuestionChoices.push({ - name: chalk`{bold Authorization modes:} ${await getAuthModeChoice()}${await getAdditionalAuthModeChoices()}`, - value: 'API_AUTH_MODE', - }); - - basicInfoQuestionChoices.push({ - name: chalk`{bold Conflict detection (required for DataStore):} ${resolverConfig?.project ? 'Enabled' : 'Disabled'}`, - value: 'CONFLICT_DETECTION', - }); - - if (resolverConfig?.project) { - basicInfoQuestionChoices.push({ - name: chalk`{bold Conflict resolution strategy:} ${ - conflictResolutionHanlderChoices.find((x) => x.value === resolverConfig.project.ConflictHandler).name - }`, - value: 'CONFLICT_STRATEGY', - }); - } - - basicInfoQuestionChoices.push({ - name: 'Continue', - value: 'CONTINUE', - }); - - const basicInfoQuestion = { - type: 'list', - name: 'basicApiSettings', - message: 'Here is the GraphQL API that we will create. Select a setting to edit or continue', - default: 'CONTINUE', - choices: basicInfoQuestionChoices, - }; - - let { basicApiSettings } = await inquirer.prompt([basicInfoQuestion]); - - switch (basicApiSettings) { - case 'API_NAME': { - const resourceQuestions = [ - { - type: inputs[1].type, - name: inputs[1].key, - message: inputs[1].question, - validate: amplify.inputValidation(inputs[1]), - default: () => { - const defaultValue = allDefaultValues[inputs[1].key]; - return defaultValue; - }, - }, - ]; - // API name question - resourceAnswers = await inquirer.prompt(resourceQuestions); - resourceAnswers[inputs[0].key] = resourceAnswers[inputs[1].key]; - allDefaultValues[inputs[1].key] = resourceAnswers[inputs[1].key]; - break; - } - case 'API_AUTH_MODE': - // Ask additonal questions - ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context)); - ({ authConfig } = await askAdditionalQuestions(context, authConfig, defaultAuthType)); - break; - case 'CONFLICT_DETECTION': - resolverConfig = await askResolverConflictQuestion(context, resolverConfig); - break; - case 'CONFLICT_STRATEGY': - resolverConfig = await askResolverConflictHandlerQuestion(context); - break; - case 'CONTINUE': - continuePrompt = true; - break; - } - } - - return { - answers: resourceAnswers, - output: { - authConfig, - }, - resolverConfig, - }; -}; - -const updateApiInputWalkthrough = async (context: $TSContext, project: Record, resolverConfig, modelTypes) => { - let authConfig; - let defaultAuthType; - const updateChoices = [ - { - name: 'Authorization modes', - value: 'AUTH_MODE', - }, - ]; - // check if DataStore is enabled for the entire API - if (project.config && !_.isEmpty(project.config.ResolverConfig)) { - updateChoices.push({ - name: 'Conflict resolution strategy', - value: 'CONFLICT_STRATEGY', - }); - updateChoices.push({ - name: 'Disable conflict detection', - value: 'DISABLE_CONFLICT', - }); - } else { - updateChoices.push({ - name: 'Enable conflict detection (required for DataStore)', - value: 'ENABLE_CONFLICT', - }); - } - - const updateOptionQuestion = { - type: 'list', - name: 'updateOption', - message: 'Select a setting to edit', - choices: updateChoices, - }; - - const { updateOption } = await inquirer.prompt([updateOptionQuestion]); - - if (updateOption === 'ENABLE_CONFLICT') { - resolverConfig = await askResolverConflictHandlerQuestion(context, modelTypes); - } else if (updateOption === 'DISABLE_CONFLICT') { - resolverConfig = {}; - } else if (updateOption === 'AUTH_MODE') { - ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context)); - authConfig = await askAdditionalAuthQuestions(context, authConfig, defaultAuthType); - } else if (updateOption === 'CONFLICT_STRATEGY') { - resolverConfig = await askResolverConflictHandlerQuestion(context, modelTypes); - } - - return { - authConfig, - resolverConfig, - }; -}; - -export const serviceWalkthrough = async (context: $TSContext, serviceMetadata: Record) => { - const resourceName = resourceAlreadyExists(); - const transformerVersion = await ApiCategoryFacade.getTransformerVersion(context); - await addLambdaAuthorizerChoice(context); - - if (resourceName) { - const errMessage = - 'You already have an AppSync API in your project. Use the "amplify update api" command to update your existing AppSync API.'; - printer.warn(errMessage); - await context.usageData.emitError(new ResourceAlreadyExistsError(errMessage)); - exitOnNextTick(0); - } - - const { amplify } = context; - const { inputs } = serviceMetadata; - - const basicInfoAnswers = await serviceApiInputWalkthrough(context, serviceMetadata); - let schemaContent = ''; - let askToEdit = true; - - // Schema template selection - const schemaTemplateOptions = transformerVersion === 2 ? schemaTemplatesV2 : schemaTemplatesV1; - const templateSelectionQuestion = { - type: inputs[4].type, - name: inputs[4].key, - message: inputs[4].question, - choices: schemaTemplateOptions.filter(templateSchemaFilter(basicInfoAnswers.output.authConfig)), - validate: amplify.inputValidation(inputs[4]), - }; - - const { templateSelection } = await inquirer.prompt(templateSelectionQuestion); - const schemaFilePath = path.join(graphqlSchemaDir, templateSelection); - schemaContent += transformerVersion === 2 ? defineGlobalSandboxMode(getGraphQLTransformerAuthDocLink(transformerVersion)) : ''; - schemaContent += fs.readFileSync(schemaFilePath, 'utf8'); - - return { - ...basicInfoAnswers, - noCfnFile: true, - schemaContent, - askToEdit, - }; -}; - -export const updateWalkthrough = async (context: $TSContext): Promise => { - const { allResources } = await context.amplify.getResourceStatus(); - let resourceDir; - let resourceName; - let resource; - let authConfig; - const resources = allResources.filter((resource) => resource.service === 'AppSync'); - await addLambdaAuthorizerChoice(context); - - // There can only be one appsync resource - if (resources.length > 0) { - resource = resources[0]; - if (resource.providerPlugin !== providerName) { - // TODO: Move message string to seperate file - throw new Error( - `The selected resource is not managed using AWS Cloudformation. Please use the AWS AppSync Console to make updates to your API - ${resource.resourceName}`, - ); - } - ({ resourceName } = resource); - resourceDir = pathManager.getResourceDirectoryPath(undefined, category, resourceName); - } else { - const errMessage = 'No AppSync resource to update. Use the "amplify add api" command to update your existing AppSync API.'; - printer.error(errMessage); - await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - exitOnNextTick(0); - } - - // migrate API project - await checkAppsyncApiResourceMigration(context, resourceName, true); - - // Get models - const project = await readProjectConfiguration(resourceDir); - let resolverConfig = project.config.ResolverConfig; - - await displayApiInformation(context, resource, project); - - // Check for common errors - const directiveMap = collectDirectivesByTypeNames(project.schema); - let modelTypes = []; - - if (directiveMap.types) { - Object.keys(directiveMap.types).forEach((type) => { - if (directiveMap.types[type].includes('model')) { - modelTypes.push(type); - } - }); - } - - ({ authConfig, resolverConfig } = await updateApiInputWalkthrough(context, project, resolverConfig, modelTypes)); - - return { - version: 1, - serviceModification: { - serviceName: 'AppSync', - defaultAuthType: authConfigToAppSyncAuthType(authConfig ? authConfig.defaultAuthentication : undefined), - additionalAuthTypes: - authConfig && authConfig.additionalAuthenticationProviders - ? authConfig.additionalAuthenticationProviders.map(authConfigToAppSyncAuthType) - : undefined, - conflictResolution: resolverConfigToConflictResolution(resolverConfig), - }, - }; -}; - -async function displayApiInformation(context: $TSContext, resource: Record, project: Record) { - let authModes: string[] = []; - authModes.push( - `- Default: ${await displayAuthMode(context, resource, resource.output.authConfig.defaultAuthentication.authenticationType)}`, - ); - await resource.output.authConfig.additionalAuthenticationProviders?.map(async (authMode) => { - authModes.push(`- ${await displayAuthMode(context, resource, authMode.authenticationType)}`); - }); - - printer.info(''); - - printer.info('General information'); - printer.info('- Name: '.concat(resource.resourceName)); - if (resource?.output?.GraphQLAPIEndpointOutput) { - printer.info(`- API endpoint: ${resource?.output?.GraphQLAPIEndpointOutput}`); - } - printer.info(''); - - printer.info('Authorization modes'); - authModes.forEach((authMode) => printer.info(authMode)); - printer.info(''); - - printer.info('Conflict detection (required for DataStore)'); - if (project.config && !_.isEmpty(project.config.ResolverConfig)) { - printer.info( - `- Conflict resolution strategy: ${ - conflictResolutionHanlderChoices.find((choice) => choice.value === project.config.ResolverConfig.project.ConflictHandler).name - }`, - ); - } else { - printer.info('- Disabled'); - } - - printer.info(''); -} - -async function displayAuthMode(context: $TSContext, resource: Record, authMode: string) { - if (authMode === 'API_KEY' && resource.output.GraphQLAPIKeyOutput) { - let { apiKeys } = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getGraphQLApiKeys', { - apiId: resource.output.GraphQLAPIIdOutput, - }); - let apiKeyExpires = apiKeys.find((key) => key.id == resource.output.GraphQLAPIKeyOutput)?.expires; - if (!apiKeyExpires) { - return authProviderChoices.find((choice) => choice.value === authMode).name; - } - let apiKeyExpiresDate = new Date(apiKeyExpires * 1000); - return `${authProviderChoices.find((choice) => choice.value === authMode).name} expiring ${apiKeyExpiresDate}: ${ - resource.output.GraphQLAPIKeyOutput - }`; - } - return authProviderChoices.find((choice) => choice.value === authMode).name; -} - -async function askAdditionalQuestions(context: $TSContext, authConfig, defaultAuthType, modelTypes?) { - authConfig = await askAdditionalAuthQuestions(context, authConfig, defaultAuthType); - return { authConfig }; -} - -async function askResolverConflictQuestion(context: $TSContext, resolverConfig, modelTypes?) { - let resolverConfigResponse: Record = {}; - - if (await context.prompt.confirm('Enable conflict detection?', !resolverConfig?.project)) { - resolverConfigResponse = await askResolverConflictHandlerQuestion(context, modelTypes); - } - - return resolverConfigResponse; -} - -async function askResolverConflictHandlerQuestion(context: $TSContext, modelTypes?) { - let resolverConfig: Record = {}; - const askConflictResolutionStrategy = async (msg) => { - let conflictResolutionStrategy; - - do { - const conflictResolutionQuestion: ListQuestion = { - type: 'list', - name: 'conflictResolutionStrategy', - message: msg, - default: 'AUTOMERGE', - choices: conflictResolutionHanlderChoices, - }; - if (conflictResolutionStrategy === 'Learn More') { - conflictResolutionQuestion.prefix = dataStoreLearnMore; - } - ({ conflictResolutionStrategy } = await inquirer.prompt([conflictResolutionQuestion])); - } while (conflictResolutionStrategy === 'Learn More'); - - let syncConfig: Record = { - ConflictHandler: conflictResolutionStrategy, - ConflictDetection: 'VERSION', - }; - - if (conflictResolutionStrategy === 'LAMBDA') { - const { newFunction, lambdaFunctionName } = await askSyncFunctionQuestion(); - syncConfig.LambdaConflictHandler = { - name: lambdaFunctionName, - new: newFunction, - }; - } - - return syncConfig; - }; - - resolverConfig.project = await askConflictResolutionStrategy('Select the default resolution strategy'); - - // Ask for per-model resolver override setting - - if (modelTypes && modelTypes.length > 0) { - if (await context.prompt.confirm('Do you want to override default per model settings?', false)) { - const modelTypeQuestion = { - type: 'checkbox', - name: 'selectedModelTypes', - message: 'Select the models from below:', - choices: modelTypes, - }; - - const { selectedModelTypes } = await inquirer.prompt([modelTypeQuestion]); - - if (selectedModelTypes.length > 0) { - resolverConfig.models = {}; - for (const modelType of selectedModelTypes) { - resolverConfig.models[modelType] = await askConflictResolutionStrategy(`Select the resolution strategy for ${modelType} model`); - } - } - } - } - - return resolverConfig; -} - -async function askSyncFunctionQuestion() { - const syncLambdaQuestion = { - type: 'list', - name: 'syncLambdaAnswer', - message: 'Select from the options below', - choices: [ - { - name: 'Create a new Lambda Function', - value: 'NEW', - }, - { - name: 'Existing Lambda Function', - value: 'EXISTING', - }, - ], - }; - - const { syncLambdaAnswer } = await inquirer.prompt([syncLambdaQuestion]); - - let lambdaFunctionName; - const newFunction = syncLambdaAnswer === 'NEW'; - - if (!newFunction) { - const syncLambdaNameQuestion = { - type: 'input', - name: 'lambdaFunctionName', - message: 'Enter lambda function name', - validate: (val) => !!val, - }; - ({ lambdaFunctionName } = await inquirer.prompt([syncLambdaNameQuestion])); - } - - return { newFunction, lambdaFunctionName }; -} - -async function addLambdaAuthorizerChoice(context: $TSContext) { - const transformerVersion = await ApiCategoryFacade.getTransformerVersion(context); - if (transformerVersion === 2 && !authProviderChoices.some((choice) => choice.value == 'AWS_LAMBDA')) { - authProviderChoices.push({ - name: 'Lambda', - value: 'AWS_LAMBDA', - }); - } -} - -async function askDefaultAuthQuestion(context: $TSContext) { - await addLambdaAuthorizerChoice(context); - const currentAuthConfig = getAppSyncAuthConfig(stateManager.getMeta()); - const currentDefaultAuth = - currentAuthConfig && currentAuthConfig.defaultAuthentication ? currentAuthConfig.defaultAuthentication.authenticationType : undefined; - - const defaultAuthTypeQuestion = { - type: 'list', - name: 'defaultAuthType', - message: 'Choose the default authorization type for the API', - choices: authProviderChoices, - default: currentDefaultAuth, - }; - - const { defaultAuthType } = await inquirer.prompt([defaultAuthTypeQuestion]); - - // Get default auth configured - const defaultAuth = await askAuthQuestions(defaultAuthType, context, false, currentAuthConfig?.defaultAuthentication); - - return { - authConfig: { - defaultAuthentication: defaultAuth, - }, - defaultAuthType, - }; -} - -export async function askAdditionalAuthQuestions(context: $TSContext, authConfig: Record, defaultAuthType) { - const currentAuthConfig = getAppSyncAuthConfig(stateManager.getMeta()); - authConfig.additionalAuthenticationProviders = []; - if (await context.prompt.confirm('Configure additional auth types?')) { - // Get additional auth configured - const remainingAuthProviderChoices = authProviderChoices.filter((p) => p.value !== defaultAuthType); - const currentAdditionalAuth = ( - (currentAuthConfig && currentAuthConfig.additionalAuthenticationProviders - ? currentAuthConfig.additionalAuthenticationProviders - : []) as any[] - ).map((authProvider) => authProvider.authenticationType); - - const additionalProvidersQuestion: CheckboxQuestion = { - type: 'checkbox', - name: 'authType', - message: 'Choose the additional authorization types you want to configure for the API', - choices: remainingAuthProviderChoices, - default: currentAdditionalAuth, - }; - - const additionalProvidersAnswer = await inquirer.prompt([additionalProvidersQuestion]); - - for (const authProvider of additionalProvidersAnswer.authType) { - const config = await askAuthQuestions( - authProvider, - context, - true, - currentAuthConfig?.additionalAuthenticationProviders?.find((authSetting) => authSetting.authenticationType == authProvider), - ); - - authConfig.additionalAuthenticationProviders.push(config); - } - } else { - authConfig.additionalAuthenticationProviders = (currentAuthConfig?.additionalAuthenticationProviders || []).filter( - (p) => p.authenticationType !== defaultAuthType, - ); - } - return authConfig; -} - -export async function askAuthQuestions(authType: string, context: $TSContext, printLeadText = false, authSettings) { - if (authType === 'AMAZON_COGNITO_USER_POOLS') { - if (printLeadText) { - printer.info('Cognito UserPool configuration'); - } - - const userPoolConfig = await askUserPoolQuestions(context); - - return userPoolConfig; - } - - if (authType === 'API_KEY') { - if (printLeadText) { - printer.info('API key configuration'); - } - - const apiKeyConfig = await askApiKeyQuestions(authSettings); - - return apiKeyConfig; - } - - if (authType === 'AWS_IAM') { - return { - authenticationType: 'AWS_IAM', - }; - } - - if (authType === 'OPENID_CONNECT') { - if (printLeadText) { - printer.info('OpenID Connect configuration'); - } - - const openIDConnectConfig = await askOpenIDConnectQuestions(authSettings); - - return openIDConnectConfig; - } - - if (authType === 'AWS_LAMBDA') { - if (printLeadText) { - context.print.info('Lambda Authorizer configuration'); - } - - const lambdaConfig = await askLambdaQuestion(context); - - return lambdaConfig; - } - - const errMessage = `Unknown authType: ${authType}`; - printer.error(errMessage); - await context.usageData.emitError(new UnknownResourceTypeError(errMessage)); - exitOnNextTick(1); -} - -async function askUserPoolQuestions(context: $TSContext) { - let authResourceName = checkIfAuthExists(); - if (!authResourceName) { - authResourceName = await context.amplify.invokePluginMethod(context, 'auth', undefined, 'add', [context, true]); - } else { - printer.info('Use a Cognito user pool configured as a part of this project.'); - } - - // Added resources are prefixed with auth - authResourceName = `auth${authResourceName}`; - - return { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - userPoolConfig: { - userPoolId: authResourceName, - }, - }; -} - -export async function askApiKeyQuestions(authSettings: Record = undefined) { - let defaultValues = { - apiKeyExpirationDays: 7, - description: '', - }; - Object.assign(defaultValues, authSettings?.apiKeyConfig); - - const apiKeyQuestions = [ - { - type: 'input', - name: 'description', - message: 'Enter a description for the API key:', - default: defaultValues.description, - }, - { - type: 'input', - name: 'apiKeyExpirationDays', - message: 'After how many days from now the API key should expire (1-365):', - default: defaultValues.apiKeyExpirationDays, - validate: validateDays, - // adding filter to ensure parsing input as int -> https://github.com/SBoudrias/Inquirer.js/issues/866 - filter: (value) => { - const val = parseInt(value, 10); - if (isNaN(val) || val <= 0 || val > 365) { - return value; - } - return val; - }, - }, - ]; - - const apiKeyConfig: Record = {}; - for (const apiKeyQuestion of apiKeyQuestions) { - apiKeyConfig[apiKeyQuestion.name] = await prompter.input(apiKeyQuestion.message, { initial: apiKeyQuestion.default as string }); - } - const apiKeyExpirationDaysNum = Number(apiKeyConfig.apiKeyExpirationDays); - apiKeyConfig.apiKeyExpirationDate = Expiration.after(Duration.days(apiKeyExpirationDaysNum)).date; - apiKeyConfig.apiKeyExpirationDays = apiKeyExpirationDaysNum; - - return { - authenticationType: 'API_KEY', - apiKeyConfig, - }; -} - -async function askOpenIDConnectQuestions(authSettings: Record) { - let defaultValues = { - authTTL: undefined, - clientId: undefined, - iatTTL: undefined, - issuerUrl: undefined, - name: undefined, - }; - Object.assign(defaultValues, authSettings?.openIDConnectConfig); - - const openIDConnectQuestions = [ - { - type: 'input', - name: 'name', - message: 'Enter a name for the OpenID Connect provider:', - default: defaultValues.name, - }, - { - type: 'input', - name: 'issuerUrl', - message: 'Enter the OpenID Connect provider domain (Issuer URL):', - validate: validateIssuerUrl, - default: defaultValues.issuerUrl, - }, - { - type: 'input', - name: 'clientId', - message: 'Enter the Client Id from your OpenID Client Connect application (optional):', - default: defaultValues.clientId, - }, - { - type: 'input', - name: 'iatTTL', - message: 'Enter the number of milliseconds a token is valid after being issued to a user:', - validate: validateTTL, - default: defaultValues.iatTTL, - }, - { - type: 'input', - name: 'authTTL', - message: 'Enter the number of milliseconds a token is valid after being authenticated:', - validate: validateTTL, - default: defaultValues.authTTL, - }, - ]; - - const openIDConnectConfig = await inquirer.prompt(openIDConnectQuestions); - - return { - authenticationType: 'OPENID_CONNECT', - openIDConnectConfig, - }; -} - -async function validateDays(input: string) { - const isValid = /^\d{0,3}$/.test(input); - const days = isValid ? parseInt(input, 10) : 0; - if (!isValid || days < 1 || days > 365) { - return 'Number of days must be between 1 and 365.'; - } - - return true; -} - -function validateIssuerUrl(input: string) { - const isValid = - /^(((?!http:\/\/(?!localhost))([a-zA-Z0-9.]{1,}):\/\/([a-zA-Z0-9-._~:?#@!$&'()*+,;=/]{1,})\/)|(?!http)(?!https)([a-zA-Z0-9.]{1,}):\/\/)$/.test( - input, - ); - - if (!isValid) { - return 'The value must be a valid URI with a trailing forward slash. HTTPS must be used instead of HTTP unless you are using localhost.'; - } - - return true; -} - -function validateTTL(input: string) { - const isValid = /^\d+$/.test(input); - - if (!isValid) { - return 'The value must be a number.'; - } - - return true; -} - -function resourceAlreadyExists() { - const meta = stateManager.getMeta(); - let resourceName; - - if (meta[category]) { - const categoryResources = meta[category]; - for (const resource of Object.keys(categoryResources)) { - if (categoryResources[resource].service === serviceName) { - resourceName = resource; - break; - } - } - } - - return resourceName; -} - -export const migrate = async (context: $TSContext) => { - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { - forceCompile: true, - migrate: true, - }); -}; - -export const getIAMPolicies = (resourceName: string, operations: string[]) => { - let policy: Record = {}; - const resources = []; - const actions = []; - if (!FeatureFlags.getBoolean('appSync.generateGraphQLPermissions')) { - operations.forEach((crudOption) => { - switch (crudOption) { - case 'create': - actions.push('appsync:Create*', 'appsync:StartSchemaCreation', 'appsync:GraphQL'); - resources.push(buildPolicyResource(resourceName, '/*')); - break; - case 'update': - actions.push('appsync:Update*'); - break; - case 'read': - actions.push('appsync:Get*', 'appsync:List*'); - break; - case 'delete': - actions.push('appsync:Delete*'); - break; - default: - printer.info(`${crudOption} not supported`); - } - }); - resources.push(buildPolicyResource(resourceName, null)); - } else { - actions.push('appsync:GraphQL'); - operations.forEach((operation) => resources.push(buildPolicyResource(resourceName, `/types/${operation}/*`))); - } - - policy = { - Effect: 'Allow', - Action: actions, - Resource: resources, - }; - - const attributes = ['GraphQLAPIIdOutput', 'GraphQLAPIEndpointOutput']; - if (authConfigHasApiKey(getAppSyncAuthConfig(stateManager.getMeta()))) { - attributes.push('GraphQLAPIKeyOutput'); - } - - return { policy, attributes }; -}; - -const buildPolicyResource = (resourceName: string, path: string | null) => { - return { - 'Fn::Join': [ - '', - [ - 'arn:aws:appsync:', - { Ref: 'AWS::Region' }, - ':', - { Ref: 'AWS::AccountId' }, - ':apis/', - { - Ref: `${category}${resourceName}GraphQLAPIIdOutput`, - }, - ...(path ? [path] : []), - ], - ], - }; -}; - -const templateSchemaFilter = (authConfig) => { - const authIncludesCognito = getAuthTypes(authConfig).includes('AMAZON_COGNITO_USER_POOLS'); - return (templateOption: ListChoiceOptions): boolean => - authIncludesCognito || - templateOption.name !== 'Objects with fine-grained access control (e.g., a project management app with owner-based authorization)'; -}; - -const getAuthTypes = (authConfig) => { - const additionalAuthTypes = (authConfig.additionalAuthenticationProviders || []) - .map((provider) => provider.authenticationType) - .filter((t) => !!t); - - const uniqueAuthTypes = new Set([...additionalAuthTypes, authConfig.defaultAuthentication.authenticationType]); - - return [...uniqueAuthTypes.keys()]; -}; - -async function askLambdaQuestion(context) { - const existingFunctions = functionsExist(context); - const choices = [ - { - name: 'Create a new Lambda function', - value: 'newFunction', - }, - ]; - if (existingFunctions) { - choices.push({ - name: 'Use a Lambda function already added in the current Amplify project', - value: 'projectFunction', - }); - } - - let defaultFunctionType = 'newFunction'; - const lambdaAnswer = await inquirer.prompt({ - name: 'functionType', - type: 'list', - message: 'Choose a Lambda authorization function', - choices, - default: defaultFunctionType, - }); - - const { lambdaFunction } = await askLambdaSource(context, lambdaAnswer.functionType); - const { ttlSeconds } = await inquirer.prompt({ - type: 'input', - name: 'ttlSeconds', - message: 'How long should the authorization response be cached in seconds?', - validate: validateTTL, - default: '300', - }); - - const lambdaAuthorizerConfig = { - lambdaFunction, - ttlSeconds, - }; - - return { - authenticationType: 'AWS_LAMBDA', - lambdaAuthorizerConfig, - }; -} - -function functionsExist(context: $TSContext): boolean { - const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; - if (!functionResources) { - return false; - } - - const lambdaFunctions = []; - Object.keys(functionResources).forEach((resourceName) => { - if (functionResources[resourceName].service === FunctionServiceNameLambdaFunction) { - lambdaFunctions.push(resourceName); - } - }); - - return lambdaFunctions.length !== 0; -} - -async function askLambdaSource(context: $TSContext, functionType: string) { - switch (functionType) { - case 'projectFunction': - return await askLambdaFromProject(context); - case 'newFunction': - return await newLambdaFunction(context); - default: - throw new Error(`Type ${functionType} not supported`); - } -} - -async function newLambdaFunction(context: $TSContext) { - const resourceName = await createLambdaAuthorizerFunction(context); - return { lambdaFunction: resourceName }; -} - -async function askLambdaFromProject(context: $TSContext) { - const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; - const lambdaFunctions = []; - Object.keys(functionResources).forEach((resourceName) => { - if (functionResources[resourceName].service === FunctionServiceNameLambdaFunction) { - lambdaFunctions.push(resourceName); - } - }); - - const answer = await inquirer.prompt({ - name: 'lambdaFunction', - type: 'list', - message: 'Choose one of the Lambda functions', - choices: lambdaFunctions, - default: lambdaFunctions[0], - }); - - await context.amplify.invokePluginMethod(context, 'function', undefined, 'addAppSyncInvokeMethodPermission', [answer.lambdaFunction]); - - return { lambdaFunction: answer.lambdaFunction }; -} - -async function createLambdaAuthorizerFunction(context: $TSContext) { - const [shortId] = uuid().split('-'); - const functionName = `graphQlLambdaAuthorizer${shortId}`; - const resourceName = await context.amplify.invokePluginMethod(context, 'function', undefined, 'add', [ - context, - 'awscloudformation', - FunctionServiceNameLambdaFunction, - { - functionName, - defaultRuntime: 'nodejs', - providerContext: { - provider: 'awscloudformation', - }, - template: 'lambda-auth', - skipAdvancedSection: true, - skipNextSteps: true, - }, - ]); - - context.print.success(`Successfully added ${resourceName} function locally`); - await context.amplify.invokePluginMethod(context, 'function', undefined, 'addAppSyncInvokeMethodPermission', [resourceName]); - return resourceName; -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/containers-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/containers-walkthrough.ts deleted file mode 100644 index f2c5873d1b..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/containers-walkthrough.ts +++ /dev/null @@ -1,358 +0,0 @@ -import { $TSContext, exitOnNextTick, ResourceDoesNotExistError } from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; -import inquirer from 'inquirer'; -import { category } from '../../../category-constants'; -import { DEPLOYMENT_MECHANISM } from '../base-api-stack'; -import { GitHubSourceActionInfo } from '../pipeline-with-awaiter'; -import { getAllDefaults } from '../default-values/containers-defaults'; - -const serviceName = 'ElasticContainer'; - -/** - * Designed to be backwards compatible with the old way of representing dependencies as - * { - * category: string - * resourceName: string - * attributes: string[] - * } - * and auto-generating environment variable names based on this info - * When attributeEnvMap is specified, it can specify a custom environment variable name for a dependency attribute - * If no mapping is found for an attribute in the map, then it falls back to the autogenerated value - */ -export interface ResourceDependency { - category: string; // resource category of the dependency - resourceName: string; // name of the dependency - attributes: string[]; // attributes that this function depends on (must be outputs of the dependencies CFN template) - attributeEnvMap?: { [name: string]: string }; // optional attributes to environment variable names map that will be exposed to the function -} - -export enum API_TYPE { - GRAPHQL = 'GRAPHQL', - REST = 'REST', -} - -export type ServiceConfiguration = { - resourceName: string; - imageSource: { type: IMAGE_SOURCE_TYPE; template?: string }; - gitHubPath: string; - authName: string; - gitHubToken: string; - deploymentMechanism: DEPLOYMENT_MECHANISM; - restrictAccess: boolean; - dependsOn?: ResourceDependency[]; // resources this function depends on - categoryPolicies?: any[]; // IAM policies that should be applied to this lambda - mutableParametersState?: any; // Contains the object that is written to function-parameters.json. Kindof a hold-over from older code - environmentMap?: Record; // Existing function environment variable map. Should refactor to use dependsOn directly, - gitHubInfo?: GitHubSourceActionInfo; -}; - -export async function serviceWalkthrough(context: $TSContext, apiType: API_TYPE): Promise> { - const allDefaultValues = getAllDefaults(); - - const resourceName = await askResourceName(context, allDefaultValues); - - const containerInfo = await askContainerSource(context, resourceName, apiType); - - return { resourceName, ...containerInfo }; -} - -async function askResourceName(context: $TSContext, allDefaultValues: Record) { - const { amplify } = context; - - const { resourceName } = await inquirer.prompt([ - { - name: 'resourceName', - type: 'input', - message: 'Provide a friendly name for your resource to be used as a label for this category in the project:', - default: allDefaultValues.resourceName, - validate: amplify.inputValidation({ - validation: { - operator: 'regex', - value: '^[a-z0-9]+$', - onErrorMsg: 'Resource name should be alphanumeric with no uppercase letters', - }, - required: true, - }), - }, - ]); - - return resourceName; -} - -async function askContainerSource(context: $TSContext, resourceName: string, apiType: API_TYPE): Promise> { - return newContainer(context, resourceName, apiType); -} - -export enum IMAGE_SOURCE_TYPE { - TEMPLATE = 'TEMPLATE', - CUSTOM = 'CUSTOM', -} - -async function newContainer(context: $TSContext, resourceName: string, apiType: API_TYPE): Promise> { - let imageSource: { type: IMAGE_SOURCE_TYPE; template?: string }; - let choices = []; - - if (apiType === API_TYPE.GRAPHQL) { - choices.push({ - name: 'ExpressJS - GraphQL template', - value: { type: IMAGE_SOURCE_TYPE.TEMPLATE, template: 'graphql-express' }, - }); - } - - if (apiType === API_TYPE.REST) { - choices.push({ - name: 'ExpressJS - REST template', - value: { type: IMAGE_SOURCE_TYPE.TEMPLATE, template: 'dockerfile-rest-express' }, - }); - - choices.push({ - name: 'Docker Compose - ExpressJS + Flask template', - value: { type: IMAGE_SOURCE_TYPE.TEMPLATE, template: 'dockercompose-rest-express' }, - }); - } - - choices = choices.concat([ - { - name: 'Custom (bring your own Dockerfile or docker-compose.yml)', - value: { type: IMAGE_SOURCE_TYPE.CUSTOM }, - }, - { - name: 'Learn More', - value: undefined, - }, - ]); - - do { - ({ imageSource } = await inquirer.prompt([ - { - name: 'imageSource', - type: 'list', - message: 'What image would you like to use', - choices, - default: 'express_hello_world', - }, - ])); - } while (imageSource === undefined); - - let deploymentMechanismQuestion; - - const deploymentMechanismChoices = [ - { - name: 'On every "amplify push" (Fully managed container source)', - value: DEPLOYMENT_MECHANISM.FULLY_MANAGED, - }, - ]; - - if (imageSource.type === IMAGE_SOURCE_TYPE.CUSTOM) { - deploymentMechanismChoices.push({ - name: 'On every Github commit (Independently managed container source)', - value: DEPLOYMENT_MECHANISM.INDENPENDENTLY_MANAGED, - }); - } - - deploymentMechanismChoices.push({ - name: 'Advanced: Self-managed (Learn more: docs.amplify.aws/cli/usage/containers)', - value: DEPLOYMENT_MECHANISM.SELF_MANAGED, - }); - - do { - deploymentMechanismQuestion = await inquirer.prompt([ - { - name: 'deploymentMechanism', - type: 'list', - message: 'When do you want to build & deploy the Fargate task', - choices: deploymentMechanismChoices, - }, - ]); - } while (deploymentMechanismQuestion.deploymentMechanism === 'Learn More'); - - let gitHubPath: string; - let gitHubToken: string; - - if (deploymentMechanismQuestion.deploymentMechanism === DEPLOYMENT_MECHANISM.INDENPENDENTLY_MANAGED) { - printer.info('We need a Github Personal Access Token to automatically build & deploy your Fargate task on every Github commit.'); - printer.info( - 'Learn more about Github Personal Access Token here: https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token', - ); - - const gitHubQuestions = await inquirer.prompt([ - { - name: 'github_access_token', - type: 'password', - message: 'GitHub Personal Access Token:', - }, - { - name: 'github_path', - type: 'input', - message: 'Path to your repo:', - }, - ]); - - gitHubPath = gitHubQuestions.github_path; - gitHubToken = gitHubQuestions.github_access_token; - } - - const meta = context.amplify.getProjectDetails().amplifyMeta; - const hasAccessableResources = ['storage', 'function'].some((categoryName) => { - return Object.keys(meta[categoryName] ?? {}).length > 0; - }); - let rolePermissions: any = {}; - if ( - hasAccessableResources && - (await context.amplify.confirmPrompt('Do you want to access other resources in this project from your api?')) - ) { - rolePermissions = await context.amplify.invokePluginMethod(context, 'function', undefined, 'askExecRolePermissionsQuestions', [ - context, - resourceName, - undefined, - undefined, - category, - serviceName, - ]); - } - - const { categoryPolicies, environmentMap, dependsOn, mutableParametersState } = rolePermissions; - - const restrictApiQuestion = await inquirer.prompt({ - name: 'rescrict_access', - type: 'confirm', - message: 'Do you want to restrict API access', - default: true, - }); - - return { - imageSource, - gitHubPath, - gitHubToken, - deploymentMechanism: deploymentMechanismQuestion.deploymentMechanism, - restrictAccess: restrictApiQuestion.rescrict_access, - categoryPolicies, - environmentMap, - dependsOn, - mutableParametersState, - }; -} - -export async function updateWalkthrough(context: $TSContext, apiType: API_TYPE) { - const { allResources } = await context.amplify.getResourceStatus(); - - const resources = allResources - .filter( - (resource) => - resource.category === category && resource.service === serviceName && !!resource.providerPlugin && resource.apiType === apiType, - ) - .map((resource) => resource.resourceName); - - // There can only be one appsync resource - if (resources.length === 0) { - const errMessage = `No ${apiType} API resource to update. Use "amplify add api" command to create a new ${apiType} API`; - printer.error(errMessage); - await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - exitOnNextTick(0); - return; - } - - const question = [ - { - name: 'resourceName', - message: 'Please select the API you would want to update', - type: 'list', - choices: resources, - }, - ]; - - const { resourceName } = await inquirer.prompt(question); - - const resourceSettings = allResources.find( - (resource) => - resource.resourceName === resourceName && - resource.category === category && - resource.service === serviceName && - !!resource.providerPlugin, - ); - - let { gitHubInfo: { path = undefined } = {} } = resourceSettings; - let gitHubToken; - - if (resourceSettings.deploymentMechanism === DEPLOYMENT_MECHANISM.INDENPENDENTLY_MANAGED) { - if (await confirm('Would you like to change your GitHub access token')) { - const gitHubQuestion = await inquirer.prompt({ - name: 'gitHubAccessToken', - type: 'password', - message: 'GitHub Personal Access Token:', - }); - gitHubToken = gitHubQuestion.gitHubAccessToken; - } - - if (await confirm('Would you like to change your GitHub Path to your repo')) { - const gitHubQuestion = await inquirer.prompt({ - name: 'gitHubPath', - type: 'input', - message: 'Path to your repo:', - default: path, - }); - path = gitHubQuestion.gitHubPath; - } - } - - const { environmentMap = {}, mutableParametersState = {} } = resourceSettings; - - const meta = context.amplify.getProjectDetails().amplifyMeta; - const hasAccessableResources = ['storage', 'function'].some((categoryName) => { - return Object.keys(meta[categoryName] ?? {}).length > 0; - }); - let rolePermissions: any = {}; - if ( - hasAccessableResources && - (await context.amplify.confirmPrompt('Do you want to access other resources in this project from your api?')) - ) { - rolePermissions = await context.amplify.invokePluginMethod(context, 'function', undefined, 'askExecRolePermissionsQuestions', [ - context, - resourceName, - mutableParametersState.permissions, - environmentMap, - category, - serviceName, - ]); - } - - const { - categoryPolicies = [], - environmentMap: newEnvironmentMap, - dependsOn: newDependsOn = [], - mutableParametersState: newMutableParametersState, - } = rolePermissions; - - const { restrict_access: restrictAccess } = await inquirer.prompt({ - name: 'restrict_access', - type: 'confirm', - message: 'Do you want to restrict API access', - default: resourceSettings.restrictAccess, - }); - - return { - ...resourceSettings, - restrictAccess, - environmentMap: newEnvironmentMap, - mutableParametersState: newMutableParametersState, - dependsOn: newDependsOn, - categoryPolicies, - gitHubPath: path, - gitHubToken, - }; -} - -async function confirm(question: string) { - const { confirm } = await inquirer.prompt({ - type: 'confirm', - default: false, - message: question, - name: 'confirm', - }); - - return confirm; -} - -export async function getPermissionPolicies(context, service, resourceName, crudOptions) { - throw new Error('IAM access not available for this resource'); -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/import-appsync-api-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/import-appsync-api-walkthrough.ts deleted file mode 100644 index e5fb852221..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/import-appsync-api-walkthrough.ts +++ /dev/null @@ -1,114 +0,0 @@ -import * as path from 'path'; -import * as fs from 'fs-extra'; -import { ApiCategoryFacade, $TSContext } from '@aws-amplify/amplify-cli-core'; -import { printer, prompter } from '@aws-amplify/amplify-prompts'; -import { - ImportAppSyncAPIInputs, - ImportedDataSourceType, - ImportedRDSType, - ImportedDataSourceConfig, - SQL_SCHEMA_FILE_NAME, -} from '@aws-amplify/graphql-transformer-core'; -import { storeConnectionSecrets, getSecretsKey } from '../utils/rds-resources/database-resources'; -import { constructDefaultGlobalAmplifyInput } from '@aws-amplify/graphql-schema-generator'; -import { getAPIResourceDir, getAppSyncAPINames } from '../utils/amplify-meta-utils'; -import { writeSchemaFile } from '../utils/graphql-schema-utils'; -import { serviceMetadataFor } from '../utils/dynamic-imports'; -import { serviceWalkthroughResultToAddApiRequest } from '../utils/service-walkthrough-result-to-add-api-request'; -import { getCfnApiArtifactHandler } from '../cfn-api-artifact-handler'; -import { serviceApiInputWalkthrough } from './appSync-walkthrough'; -import { databaseConfigurationInputWalkthrough } from './appSync-rds-db-config'; - -const service = 'AppSync'; - -/** - * Walkthrough for importing an AppSync API from an existing SQL database - * @param context the Amplify CLI context - * @returns inputs to create an AppSync API - */ -export const importAppSyncAPIWalkthrough = async (context: $TSContext): Promise => { - let apiName: string; - const existingAPIs = getAppSyncAPINames(); - if (existingAPIs?.length > 0) { - apiName = existingAPIs[0]; - } else { - const serviceMetadata = await serviceMetadataFor(service); - const walkthroughResult = await serviceApiInputWalkthrough(context, serviceMetadata); - const importAPIRequest = serviceWalkthroughResultToAddApiRequest(walkthroughResult); - apiName = await getCfnApiArtifactHandler(context).createArtifacts(importAPIRequest); - } - - const apiResourceDir = getAPIResourceDir(apiName); - const pathToSchemaFile = path.join(apiResourceDir, SQL_SCHEMA_FILE_NAME); - const secretsKey = await getSecretsKey(); - - if (fs.pathExistsSync(pathToSchemaFile)) { - printer.error('Imported Database schema already exists. Use "amplify api generate-schema" to fetch the latest updates to schema.'); - return { - apiName: apiName, - }; - } - - const engine = await promptDatabaseEngine(); - const databaseConfig: ImportedDataSourceConfig = await databaseConfigurationInputWalkthrough(engine); - - await writeDefaultGraphQLSchema(context, pathToSchemaFile, databaseConfig); - await storeConnectionSecrets(context, databaseConfig, apiName, secretsKey); - - return { - apiName, - dataSourceConfig: databaseConfig, - }; -}; - -const promptDatabaseEngine = async (): Promise => { - const engine = await prompter.pick<'one', string>('Select the database type:', [ - { - name: 'MySQL', - value: ImportedRDSType.MYSQL as string, - }, - { - name: 'PostgreSQL', - value: ImportedRDSType.POSTGRESQL as string, - }, - ]); - - return engine as ImportedRDSType; -}; - -/** - * Writes a default GraphQL schema from the global input template for the specified database engine - * @param context the Amplify CLI context - * @param pathToSchemaFile the output path for the default schema file - * @param databaseConfig the database configuration - */ -export const writeDefaultGraphQLSchema = async ( - context: $TSContext, - pathToSchemaFile: string, - databaseConfig: ImportedDataSourceConfig, -): Promise => { - const dataSourceType = databaseConfig?.engine; - if (Object.values(ImportedRDSType).includes(dataSourceType)) { - const includeAuthRule = false; - const globalAmplifyInputTemplate = await constructDefaultGlobalAmplifyInput(databaseConfig.engine, includeAuthRule); - writeSchemaFile(pathToSchemaFile, globalAmplifyInputTemplate); - } else { - throw new Error(`Data source type ${dataSourceType} is not supported.`); - } -}; - -/** - * Returns a human-friendly string for the specified database engine - * @param engine the database engine - * @returns a human-friendly string for the specified database engine - */ -export const formatEngineName = (engine: ImportedDataSourceType): string => { - switch (engine) { - case ImportedRDSType.MYSQL: - return 'MySQL'; - case ImportedRDSType.POSTGRESQL: - return 'PostgreSQL'; - default: - throw new Error(`Unsupported database engine: ${engine}`); - } -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.ts deleted file mode 100644 index bbde2f3300..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.ts +++ /dev/null @@ -1,16 +0,0 @@ -import chalk from 'chalk'; - -const learnMore = `When more than one system is updating an item in your GraphQL backend at a single time, Amplify DataStore can use different strategies with AWS AppSync to resolve these conflicts based on your use case. -This can be on the entire API (recommended) or for advanced use cases you can change these for each one of your GraphQL types. - -Automerge is the default mechanism where GraphQL type information can be used to merge objects using the scalar type context as long as two fields in a type are not in conflict. -When this happens the data is merged and AppSync will update the object version so that all clients are updated. -This also functions on lists of scalars where the updates are concatenated. - -Optimistic Concurrency Control accepts the latest committed write to the database. -Other writers are rejected and must handle merges through other means, such as a client-side callback. - -Finally you can also also configure a Lambda Function to resolve conflicts depending on your custom business need, such as letting specific users in a system have priority on making updates to data. -`; - -export const dataStoreLearnMore = chalk.green(learnMore); diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/amplify-meta-utils.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/amplify-meta-utils.ts deleted file mode 100644 index 43b2464b7e..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/amplify-meta-utils.ts +++ /dev/null @@ -1,88 +0,0 @@ -import * as path from 'path'; -import { $TSMeta, AmplifyCategories, AmplifySupportedService, stateManager, pathManager } from '@aws-amplify/amplify-cli-core'; -import _ from 'lodash'; - -export const authConfigHasApiKey = (authConfig?: any) => { - if (!authConfig) { - return false; - } - return ( - Array.of(authConfig.defaultAuthentication) - .concat(authConfig.additionalAuthenticationProviders) - .filter((auth) => !!auth) // filter out undefined elements which can happen if there are no addtl auth providers - .map((auth) => auth.authenticationType) - .findIndex((authType) => authType === 'API_KEY') > -1 - ); -}; - -export const checkIfAuthExists = () => { - const amplifyMeta = stateManager.getMeta(); - let authResourceName; - const authServiceName = AmplifySupportedService.COGNITO; - const authCategoryName = AmplifyCategories.AUTH; - - if (amplifyMeta[authCategoryName] && Object.keys(amplifyMeta[authCategoryName]).length > 0) { - const categoryResources = amplifyMeta[authCategoryName]; - Object.keys(categoryResources).forEach((resource) => { - if (categoryResources[resource].service === authServiceName) { - authResourceName = resource; - } - }); - } - - return authResourceName; -}; - -export const getAppSyncAPINames = () => { - return Object.entries(stateManager.getMeta()?.api || {}) - .filter(([_, apiResource]) => (apiResource as any).service === 'AppSync') - .map(([name]) => name); -}; - -export const ensureNoAppSyncAPIExists = () => { - const apiNames = getAppSyncAPINames(); - // This restriction of having a single AppSync API might change in future. - if (apiNames?.length > 0) { - throw new Error( - `You already have an AppSync API named ${apiNames[0]} in your project. Use the "amplify update api" command to update your existing AppSync API.`, - ); - } -}; - -export const getAppSyncAPIName = () => { - const apiNames = getAppSyncAPINames(); - // This restriction of having a single AppSync API might change in future. - if (apiNames?.length === 0) { - throw new Error(`You do not have AppSync API added. Use "amplify add api" or "amplify import api" to add one to your project.`); - } - return apiNames[0]; -}; - -export const getAPIResourceDir = (apiName: string) => { - return path.join(pathManager.getBackendDirPath(), AmplifyCategories.API, apiName); -}; - -// some utility functions to extract the AppSync API name and config from amplify-meta - -export const getAppSyncAuthConfig = (projectMeta: $TSMeta) => { - const entry = getAppSyncAmplifyMetaEntry(projectMeta); - if (entry) { - const value = entry[1] as any; - return value && value.output ? value.output.authConfig : {}; - } -}; - -export const getAppSyncResourceName = (projectMeta: $TSMeta): string | undefined => { - const entry = getAppSyncAmplifyMetaEntry(projectMeta); - if (entry) { - return entry[0]; - } -}; - -// project meta is the contents of amplify-meta.json -// typically retreived using context.amplify.getProjectMeta() -const getAppSyncAmplifyMetaEntry = (projectMeta: $TSMeta) => { - return Object.entries(projectMeta[AmplifyCategories.API] || {}).find( - ([, value]) => (value as Record).service === AmplifySupportedService.APPSYNC, - ); -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper.ts deleted file mode 100644 index 709cedf034..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { - AppSyncAuthType, - AppSyncAPIKeyAuthType, - AppSyncCognitoUserPoolsAuthType, - AppSyncOpenIDConnectAuthType, - AppSyncLambdaAuthType, -} from 'amplify-headless-interface'; -import _ from 'lodash'; - -/** - * Converts the authConfig object that is returned by the AppSync walkthrough into the AppSyncAuthType defined by the AddApiRequest - * - * Used when transforming the walkthrough result into an AddApiRequest - */ -export const authConfigToAppSyncAuthType = (authConfig: any = {}): AppSyncAuthType => { - return _.get(authConfigToAppSyncAuthTypeMap, authConfig.authenticationType, () => undefined)(authConfig); -}; - -/** - * Converts an AppSyncAuthType object into the authConfig object that gets written to amplify-meta - * - * This conversion is necessary to ensure we are storing the authConfig in the same way as older projects - * @param authType - */ -export const appSyncAuthTypeToAuthConfig = (authType?: AppSyncAuthType) => { - if (!authType) return undefined; - return _.get(appSyncAuthTypeToAuthConfigMap, authType.mode, () => undefined)(authType); -}; - -const authConfigToAppSyncAuthTypeMap: Record AppSyncAuthType> = { - API_KEY: (authConfig) => ({ - mode: 'API_KEY', - expirationTime: authConfig.apiKeyConfig.apiKeyExpirationDays, - apiKeyExpirationDate: authConfig.apiKeyConfig?.apiKeyExpirationDate, - keyDescription: authConfig.apiKeyConfig.description, - }), - AWS_IAM: () => ({ - mode: 'AWS_IAM', - }), - AMAZON_COGNITO_USER_POOLS: (authConfig) => ({ - mode: 'AMAZON_COGNITO_USER_POOLS', - cognitoUserPoolId: authConfig.userPoolConfig.userPoolId, - }), - OPENID_CONNECT: (authConfig) => ({ - mode: 'OPENID_CONNECT', - openIDProviderName: authConfig.openIDConnectConfig.name, - openIDIssuerURL: authConfig.openIDConnectConfig.issuerUrl, - openIDClientID: authConfig.openIDConnectConfig.clientId, - openIDAuthTTL: authConfig.openIDConnectConfig.authTTL, - openIDIatTTL: authConfig.openIDConnectConfig.iatTTL, - }), - AWS_LAMBDA: (authConfig) => ({ - mode: 'AWS_LAMBDA', - lambdaFunction: authConfig.lambdaAuthorizerConfig.lambdaFunction, - ttlSeconds: authConfig.lambdaAuthorizerConfig.ttlSeconds, - }), -}; - -const appSyncAuthTypeToAuthConfigMap: Record any> = { - API_KEY: (authType: AppSyncAPIKeyAuthType) => ({ - authenticationType: 'API_KEY', - apiKeyConfig: { - apiKeyExpirationDays: authType.expirationTime, - apiKeyExpirationDate: authType?.apiKeyExpirationDate, - description: authType.keyDescription, - }, - }), - AWS_IAM: () => ({ - authenticationType: 'AWS_IAM', - }), - AMAZON_COGNITO_USER_POOLS: (authType: AppSyncCognitoUserPoolsAuthType) => ({ - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - userPoolConfig: { - userPoolId: authType.cognitoUserPoolId, - }, - }), - OPENID_CONNECT: (authType: AppSyncOpenIDConnectAuthType) => ({ - authenticationType: 'OPENID_CONNECT', - openIDConnectConfig: { - name: authType.openIDProviderName, - issuerUrl: authType.openIDIssuerURL, - clientId: authType.openIDClientID, - authTTL: authType.openIDAuthTTL, - iatTTL: authType.openIDIatTTL, - }, - }), - AWS_LAMBDA: (authType: AppSyncLambdaAuthType) => ({ - authenticationType: 'AWS_LAMBDA', - lambdaAuthorizerConfig: { - lambdaFunction: authType.lambdaFunction, - ttlSeconds: authType.ttlSeconds, - }, - }), -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-appsync-api-migration.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-appsync-api-migration.ts deleted file mode 100644 index a4dd7e39ea..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-appsync-api-migration.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { $TSContext, AmplifyCategories, getMigrateResourceMessageForOverride } from '@aws-amplify/amplify-cli-core'; -import { printer, prompter } from '@aws-amplify/amplify-prompts'; -import { AppsyncApiInputState } from '../api-input-manager/appsync-api-input-state'; -import { migrateResourceToSupportOverride } from './migrate-api-override-resource'; - -export const checkAppsyncApiResourceMigration = async (context: $TSContext, apiName: string, isUpdate: boolean): Promise => { - const cliState = new AppsyncApiInputState(context, apiName); - if (!cliState.cliInputFileExists()) { - printer.debug('cli-inputs.json doesnt exist'); - const headlessMigrate = context.input.options?.yes || context.input.options?.forcePush || context.input.options?.headless; - if (headlessMigrate || (await prompter.yesOrNo(getMigrateResourceMessageForOverride(AmplifyCategories.API, apiName, isUpdate), true))) { - // generate cli-inputs for migration from parameters.json - await migrateResourceToSupportOverride(apiName); - return true; - } - return false; - } - return true; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/containers-artifacts.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/containers-artifacts.ts deleted file mode 100644 index 905b653336..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/containers-artifacts.ts +++ /dev/null @@ -1,362 +0,0 @@ -import * as path from 'path'; -import { Octokit } from '@octokit/rest'; -import * as fs from 'fs-extra'; -import inquirer from 'inquirer'; -import { v4 as uuid } from 'uuid'; -import { $TSContext, JSONUtilities, pathManager, readCFNTemplate } from '@aws-amplify/amplify-cli-core'; -import * as cdk from 'aws-cdk-lib'; -import { provider as cloudformationProviderName } from '../../../provider-utils/awscloudformation/aws-constants'; -import { getContainers } from '../../../provider-utils/awscloudformation/docker-compose'; -import Container from '../docker-compose/ecs-objects/container'; -import { EcsStack } from '../ecs-apigw-stack'; -import { API_TYPE, ResourceDependency } from '../../../provider-utils/awscloudformation/service-walkthroughs/containers-walkthrough'; -import { getGitHubOwnerRepoFromPath } from '../../../provider-utils/awscloudformation/utils/github'; -import { DEPLOYMENT_MECHANISM } from '../base-api-stack'; -import { category } from '../../../category-constants'; -import { setExistingSecretArns } from './containers/set-existing-secret-arns'; - -export const cfnFileName = (resourceName: string) => `${resourceName}-cloudformation-template.json`; - -export type ApiResource = { - category: string; - resourceName: string; - gitHubInfo?: { - path: string; - tokenSecretArn: string; - }; - deploymentMechanism: DEPLOYMENT_MECHANISM; - authName: string; - restrictAccess: boolean; - dependsOn: ResourceDependency[]; - environmentMap: Record; - categoryPolicies: any[]; - mutableParametersState: any; - output?: Record; - apiType?: API_TYPE; - exposedContainer?: { name: string; port: number }; -}; - -type ExposedContainer = { - name: string; - port: number; -}; - -type ContainerArtifactsMetadata = { - exposedContainer: ExposedContainer; - pipelineInfo: { consoleUrl: string }; -}; - -export async function generateContainersArtifacts( - context: $TSContext, - resource: ApiResource, - askForExposedContainer: boolean = false, -): Promise { - const { - providers: { [cloudformationProviderName]: provider }, - } = context.amplify.getProjectMeta(); - - const { StackName: envName } = provider; - - const { - category: categoryName, - resourceName, - gitHubInfo, - deploymentMechanism, - categoryPolicies = [], - dependsOn, - environmentMap, - restrictAccess, - apiType, - } = resource; - - const backendDir = context.amplify.pathManager.getBackendDirPath(); - const resourceDir = path.normalize(path.join(backendDir, categoryName, resourceName)); - const srcPath = path.join(resourceDir, 'src'); - - const { containersPorts, containers, isInitialDeploy, desiredCount, exposedContainer, secretsArns } = await processDockerConfig( - context, - resource, - srcPath, - askForExposedContainer, - ); - const repositories = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'describeEcrRepositories'); - - const existingEcrRepositories: Set = new Set( - repositories - .map(({ repositoryName }) => repositoryName) - .filter((repositoryName) => repositoryName.startsWith(`${envName}-${categoryName}-${resourceName}-`)), - ); - - const stack = new EcsStack(undefined, 'ContainersStack', { - categoryName, - apiName: resourceName, - taskPorts: containersPorts, - dependsOn, - policies: categoryPolicies, - taskEnvironmentVariables: environmentMap, - gitHubSourceActionInfo: gitHubInfo, - deploymentMechanism, - containers, - isInitialDeploy, - desiredCount, - restrictAccess, - currentStackName: envName, - apiType, - exposedContainer, - secretsArns, - existingEcrRepositories, - }); - - const cfn = stack.toCloudFormation(); - - JSONUtilities.writeJson(path.normalize(path.join(resourceDir, cfnFileName(resourceName))), cfn); - - return { - exposedContainer, - pipelineInfo: { consoleUrl: stack.getPipelineConsoleUrl(provider.Region) }, - }; -} - -export async function processDockerConfig( - context: $TSContext, - resource: ApiResource, - srcPath: string, - askForExposedContainer: boolean = false, -) { - const { - providers: { [cloudformationProviderName]: provider }, - } = context.amplify.getProjectMeta(); - - const { StackName: envName } = provider; - - const { resourceName, gitHubInfo, deploymentMechanism, output, exposedContainer: exposedContainerFromMeta } = resource; - - const dockerComposeFileNameYaml = 'docker-compose.yaml'; - const dockerComposeFileNameYml = 'docker-compose.yml'; - const dockerfileFileName = 'Dockerfile'; - - const containerDefinitionFileNames = [dockerComposeFileNameYaml, dockerComposeFileNameYml, dockerfileFileName]; - - const containerDefinitionFiles: Record = {}; - - for await (const fileName of containerDefinitionFileNames) { - switch (deploymentMechanism) { - case DEPLOYMENT_MECHANISM.FULLY_MANAGED: - case DEPLOYMENT_MECHANISM.SELF_MANAGED: { - const filePath = path.normalize(path.join(srcPath, fileName)); - - if (fs.existsSync(filePath)) { - containerDefinitionFiles[fileName] = fs.readFileSync(filePath).toString(); - } - break; - } - case DEPLOYMENT_MECHANISM.INDENPENDENTLY_MANAGED: { - const { path: repoUri, tokenSecretArn } = gitHubInfo; - - const { SecretString: gitHubToken } = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'retrieveSecret', { - secretArn: tokenSecretArn, - }); - - const octokit = new Octokit({ auth: gitHubToken }); - - const { owner, repo, branch, path: pathInRepo } = getGitHubOwnerRepoFromPath(repoUri); - - try { - const { - data: { content, encoding }, - } = (await octokit.repos.getContent({ - owner, - repo, - ...(branch ? { ref: branch } : undefined), // only include branch if not undefined - path: path.join(pathInRepo, fileName), - })) as { data: { content?: string; encoding?: string } }; - - containerDefinitionFiles[fileName] = Buffer.from(content, encoding).toString('utf8'); - } catch (error) { - const { status } = error; - - // It is ok if the file doesn't exist, we skip it - if (status !== 404) { - throw error; - } - } - break; - } - default: { - const exhaustiveCheck: never = deploymentMechanism; - throw new Error(`Unhandled type [${exhaustiveCheck}]`); - } - } - } - - if (Object.keys(containerDefinitionFiles).length === 0) { - throw new Error('No definition available (docker-compose.yaml / docker-compose.yml / Dockerfile)'); - } - - if (containerDefinitionFiles[dockerComposeFileNameYaml] && containerDefinitionFiles[dockerComposeFileNameYml]) { - throw new Error('There should be only one docker-compose.yaml / docker-compose.yml)'); - } - - const composeContents = containerDefinitionFiles[dockerComposeFileNameYaml] || containerDefinitionFiles[dockerComposeFileNameYml]; - const { [dockerfileFileName]: dockerfileContents } = containerDefinitionFiles; - - const { buildspec, containers, service, secrets } = getContainers(composeContents, dockerfileContents); - - const containersPorts = containers.reduce( - (acc, container) => acc.concat(container.portMappings.map(({ containerPort }) => containerPort)), - [], - ); - - const newContainersName = Array.from(new Set(containers.map(({ name }) => name))); - - let isInitialDeploy = Object.keys(output ?? {}).length === 0; - const currentContainersSet = new Set(output?.ContainerNames?.split(',')); - // Service require all containers to exists - isInitialDeploy = isInitialDeploy || newContainersName.some((newContainer) => !currentContainersSet.has(newContainer)); - - let exposedContainer: { name: string; port: number }; - - const containersExposed = containers.filter((container) => container.portMappings.length > 0); - - if (containersPorts.length === 0) { - throw new Error('Service requires at least one exposed port'); - } else if (containersPorts.length > 1) { - exposedContainer = await checkContainerExposed(containersExposed, exposedContainerFromMeta, askForExposedContainer); - } else { - exposedContainer = { - name: containersExposed[0].name, - port: containersExposed[0].portMappings[0].containerPort, - }; - } - - fs.ensureDirSync(srcPath); - fs.writeFileSync(path.join(srcPath, 'buildspec.yml'), buildspec); - - const secretsArns: Map = new Map(); - - if ((await shouldUpdateSecrets(context, secrets)) || isInitialDeploy) { - // Normalizes paths - // Validate secrets file paths, existence and prefixes - const errors = Object.entries(secrets).reduce((acc, [secretName, secretFilePath]) => { - const baseDir = path.isAbsolute(secretFilePath) ? '' : srcPath; - const normalizedFilePath = path.normalize(path.join(baseDir, secretFilePath)); - - secrets[secretName] = normalizedFilePath; - - let canRead = true; - - try { - const fd = fs.openSync(normalizedFilePath, 'r'); - - fs.closeSync(fd); - } catch (err) { - canRead = false; - } - - if (!canRead) { - acc.push(`Secret file "${secretFilePath}" can't be read.`); - return acc; - } - - const basename = path.basename(normalizedFilePath); - const hasCorrectPrefix = basename.startsWith('.secret-'); - - if (!hasCorrectPrefix) { - acc.push(`Secret file "${secretFilePath}" doesn't start with the ".secret-" prefix.`); - return acc; - } - - const isInsideSrc = normalizedFilePath.startsWith(path.join(srcPath, path.sep)); - if (isInsideSrc) { - acc.push(`Secret file "${secretFilePath}" should not be inside the "src" folder. The "src" folder will be uploaded to S3.`); - return acc; - } - - return acc; - }, []); - - if (errors.length > 0) { - throw new Error(['Error(s) in secret file(s):'].concat(errors).join('\n')); - } - - for await (const entries of Object.entries(secrets)) { - const [secretName, secretFilePath] = entries; - - const contents = fs.readFileSync(secretFilePath).toString(); - - const ssmSecretName = `${envName}-${resourceName}-${secretName}`; - - const { ARN: secretArn } = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'upsertSecretValue', { - secret: contents, - description: `Secret for ${resourceName}`, - name: ssmSecretName, - version: uuid(), - }); - - const [prefix] = secretArn.toString().split(ssmSecretName); - const secretArnRef = cdk.Fn.join('', [prefix, cdk.Fn.ref('rootStackName'), '-', resourceName, '-', secretName]); - - secretsArns.set(secretName, secretArnRef); - } - } else { - const { cfnTemplate } = readCFNTemplate(path.join(pathManager.getBackendDirPath(), category, resourceName, cfnFileName(resourceName))); - setExistingSecretArns(secretsArns, cfnTemplate); - } - - const desiredCount = service?.replicas ?? 1; // TODO: 1 should be from meta (HA setting) - - return { - containersPorts, - containers, - isInitialDeploy, - desiredCount, - exposedContainer, - secretsArns, - }; -} - -async function shouldUpdateSecrets(context: $TSContext, secrets: Record): Promise { - const hasSecrets = Object.keys(secrets).length > 0; - - if (!hasSecrets || context.exeInfo.inputParams.yes) { - return false; - } - - const { update_secrets } = await inquirer.prompt({ - name: 'update_secrets', - type: 'confirm', - message: 'Secret configuration detected. Do you wish to store new values in the cloud?', - default: false, - }); - - return update_secrets; -} - -async function checkContainerExposed( - containersExposed: Container[], - exposedContainerFromMeta: { name: string; port: number } = { name: '', port: 0 }, - askForExposedContainer: boolean = false, -): Promise<{ name: string; port: number }> { - const containerExposed = containersExposed.find((container) => container.name === exposedContainerFromMeta.name); - - if (!askForExposedContainer && containerExposed?.portMappings.find((port) => port.containerPort === exposedContainerFromMeta.port)) { - return { ...exposedContainerFromMeta }; - } else { - const choices: { name: string; value: Container }[] = containersExposed.map((container) => ({ - name: container.name, - value: container, - })); - - const { containerToExpose } = await inquirer.prompt({ - message: 'Select which container is the entrypoint', - name: 'containerToExpose', - type: 'list', - choices, - }); - - return { - name: containerToExpose.name, - port: containerToExpose.portMappings[0].containerPort, - }; - } -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/containers/set-existing-secret-arns.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/containers/set-existing-secret-arns.ts deleted file mode 100644 index 91e1cd393e..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/containers/set-existing-secret-arns.ts +++ /dev/null @@ -1,56 +0,0 @@ -import _ from 'lodash'; -import * as cdk from 'aws-cdk-lib'; - -/** - * Check if the template contains existing secret configuration and if so, add it to the secretsMap - * The secrets configuration is stored in the template in the following format - * { - * "Resources": { - "TaskDefinition": { - "Type": "AWS::ECS::TaskDefinition", - "Properties": { - "ContainerDefinitions": [ - { - "Secrets": [ - { - "Name": "SECRETNAME", - "ValueFrom": "" - } - } - } - ] - } - } - } - */ -export const setExistingSecretArns = (secretsMap: Map, cfnObj: any) => { - if (_.isEmpty(cfnObj)) { - return; - } - const taskDef = Object.values(cfnObj?.Resources) // get all the resources - .find((value: any) => value?.Type === 'AWS::ECS::TaskDefinition') as any; // find the task definition - const containerDefs = taskDef?.Properties?.ContainerDefinitions as any[]; // pull out just the container definitions - if (!Array.isArray(containerDefs)) { - return; - } - containerDefs - .map((def) => def?.Secrets) // get the secrets array - .filter((secrets) => !_.isEmpty(secrets)) // filter out defs that don't contain secrets - .flat(1) // merge nested secrets array into one array - .filter((secretDef) => !!secretDef?.Name) // make sure the name is defined - .filter((secretDef) => !!secretDef.ValueFrom) // make sure the arn is defined - .forEach((secretDef) => { - if (typeof secretDef.ValueFrom === 'object' && secretDef.ValueFrom['Fn::Join']) { - const [delimiter, values] = secretDef.ValueFrom['Fn::Join']; - secretsMap.set( - secretDef.Name, - cdk.Fn.join( - delimiter, - values.map((val) => (val.Ref ? cdk.Fn.ref(val.Ref) : val)), - ), - ); - } else { - secretsMap.set(secretDef.Name, secretDef.ValueFrom); - } - }); // add it to the secretsMap map -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/database-url.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/database-url.ts deleted file mode 100644 index 7b07a3e2e6..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/database-url.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { URL } from 'url'; -import { ImportedRDSType, RDSDataSourceConfig } from '@aws-amplify/graphql-transformer-core'; -import { AmplifyError } from '@aws-amplify/amplify-cli-core'; - -export const parseDatabaseUrl = (databaseUrl: string): Partial => { - const allowedProtocols = ['mysql', 'mysql2']; - try { - const parsedDatabaseUrl = new URL(databaseUrl); - const { username, password, hostname: host } = parsedDatabaseUrl; - const database = parsedDatabaseUrl?.pathname?.slice(1); - const port = parseInt(parsedDatabaseUrl?.port, 10); - const engine = parsedDatabaseUrl?.protocol?.slice(0, -1) as ImportedRDSType; - - const isValidEngine = allowedProtocols.includes(engine); - if (!isValidEngine) { - throw new AmplifyError('InputValidationError', { - message: `Invalid engine ${engine}.`, - }); - } - - const config = { - engine, - username, - password, - database, - host, - port, - }; - return config; - } catch (err) { - if (err.code !== 'ERR_INVALID_URL') { - throw err; - } - } - return {}; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/dynamic-imports.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/dynamic-imports.ts deleted file mode 100644 index 5f571e35eb..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/dynamic-imports.ts +++ /dev/null @@ -1,10 +0,0 @@ -import * as path from 'path'; - -export const serviceMetadataFor = async (service: string) => - (await import(path.join('..', '..', 'supported-services'))).supportedServices[service]; - -export const datasourceMetadataFor = async (datasource: string) => - (await import(path.join('..', '..', 'supported-datasources'))).supportedDataSources[datasource]; - -export const getServiceWalkthrough = async (walkthroughFilename: string) => - (await import(path.join('..', 'service-walkthroughs', walkthroughFilename))).serviceWalkthrough; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/edit-schema-flow.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/edit-schema-flow.ts deleted file mode 100644 index 83daf66145..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/edit-schema-flow.ts +++ /dev/null @@ -1,14 +0,0 @@ -import * as path from 'path'; -import { $TSContext, pathManager } from '@aws-amplify/amplify-cli-core'; -import { prompter } from '@aws-amplify/amplify-prompts'; -import { category } from '../../../category-constants'; -import { gqlSchemaFilename } from '../aws-constants'; - -export const editSchemaFlow = async (context: $TSContext, apiName: string) => { - if (!(await prompter.yesOrNo('Do you want to edit the schema now?', true))) { - return; - } - - const schemaPath = path.join(pathManager.getResourceDirectoryPath(undefined, category, apiName), gqlSchemaFilename); - await context.amplify.openEditor(context, schemaPath, false); -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/get-appsync-auth-config.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/get-appsync-auth-config.ts deleted file mode 100644 index a9afc7255c..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/get-appsync-auth-config.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { AppsyncApiInputState } from '../api-input-manager/appsync-api-input-state'; -import { appSyncAuthTypeToAuthConfig } from './auth-config-to-app-sync-auth-type-bi-di-mapper'; - -/** - * - * @param resourceName - * @returns authConfig - */ -export const getAuthConfig = async (context: $TSContext, resourceName: string) => { - const cliState = new AppsyncApiInputState(context, resourceName); - if (cliState.cliInputFileExists()) { - const appsyncInputs = cliState.getCLIInputPayload().serviceConfiguration; - return { - defaultAuthentication: appSyncAuthTypeToAuthConfig(appsyncInputs.defaultAuthType), - additionalAuthenticationProviders: (appsyncInputs.additionalAuthTypes || []).map(appSyncAuthTypeToAuthConfig), - }; - } -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/get-appsync-resolver-config.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/get-appsync-resolver-config.ts deleted file mode 100644 index cd813db288..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/get-appsync-resolver-config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { AppsyncApiInputState } from '../api-input-manager/appsync-api-input-state'; -import { conflictResolutionToResolverConfig } from './resolver-config-to-conflict-resolution-bi-di-mapper'; - -/** - * - * @param resourceName - * @returns resolverConfig - */ -export const getResolverConfig = async (context: $TSContext, resourceName: string) => { - const cliState = new AppsyncApiInputState(context, resourceName); - if (cliState.cliInputFileExists()) { - const appsyncInputs = cliState.getCLIInputPayload().serviceConfiguration; - return conflictResolutionToResolverConfig(appsyncInputs.conflictResolution); - } -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/getAppSyncApiName.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/getAppSyncApiName.ts deleted file mode 100644 index 6c627fb682..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/getAppSyncApiName.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { $TSContext, AmplifySupportedService, AmplifyError } from '@aws-amplify/amplify-cli-core'; - -export const getAppSyncApiResourceName = async (context: $TSContext): Promise => { - const { allResources } = await context.amplify.getResourceStatus(); - const apiResource = allResources.filter((resource: { service: string }) => resource.service === AmplifySupportedService.APPSYNC); - let apiResourceName; - - if (apiResource.length > 0) { - const resource = apiResource[0]; - apiResourceName = resource.resourceName; - } else { - throw new AmplifyError('NotImplementedError', { - message: `${AmplifySupportedService.APPSYNC} API does not exist`, - resolution: 'To add an api, use amplify add api', - }); - } - return apiResourceName; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/github.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/github.ts deleted file mode 100644 index 6d73ee22a3..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/github.ts +++ /dev/null @@ -1,14 +0,0 @@ -export function getGitHubOwnerRepoFromPath(path: string) { - if (!path.startsWith('https://github.com/')) { - throw Error(`Invalid Repo Path ${path}`); - } - - const [, , , owner, repo, , branch, ...pathParts] = path.split('/'); - - return { - owner, - repo, - branch, - path: pathParts.join('/'), - }; -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/global-sandbox-mode.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/global-sandbox-mode.ts deleted file mode 100644 index b9cd1c9884..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/global-sandbox-mode.ts +++ /dev/null @@ -1,6 +0,0 @@ -export function defineGlobalSandboxMode(link: string): string { - return `# This "input" configures a global authorization rule to enable public access to -# all models in this schema. Learn more about authorization rules here: ${link} -input AMPLIFY { globalAuthRule: AuthRule = { allow: public } } # FOR TESTING ONLY!\n -`; -} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/graphql-schema-utils.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/graphql-schema-utils.ts deleted file mode 100644 index 9a93d58f53..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/graphql-schema-utils.ts +++ /dev/null @@ -1,120 +0,0 @@ -import * as os from 'os'; -import { ImportedRDSType, ImportedDataSourceConfig } from '@aws-amplify/graphql-transformer-core'; -import * as fs from 'fs-extra'; -import { - MySQLDataSourceAdapter, - Schema, - Engine, - DataSourceAdapter, - DataSourceConfig, - getHostVpc, - provisionSchemaInspectorLambda, - PostgresDataSourceAdapter, - renderSchema, -} from '@aws-amplify/graphql-schema-generator'; -import { readRDSSchema } from './rds-input-utils'; -import { $TSContext, AmplifyError, stateManager, ApiCategoryFacade } from '@aws-amplify/amplify-cli-core'; -import { prompter } from '@aws-amplify/amplify-prompts'; -import { getVpcMetadataLambdaName } from './rds-resources/database-resources'; -import { DocumentNode, parse } from 'graphql'; - -export const writeSchemaFile = (pathToSchemaFile: string, schemaString: string) => { - fs.ensureFileSync(pathToSchemaFile); - fs.writeFileSync(pathToSchemaFile, schemaString); -}; - -export const generateRDSSchema = async ( - context: $TSContext, - databaseConfig: ImportedDataSourceConfig, - pathToSchemaFile: string, -): Promise => { - const { amplify } = context; - const { envName } = amplify.getEnvInfo(); - const schema = await buildSchemaFromConnection(envName, databaseConfig); - const existingSchema = await readRDSSchema(pathToSchemaFile); - const existingSchemaDocument = parseSchema(existingSchema, pathToSchemaFile); - - const includeAuthRule = false; - return renderSchema(schema, databaseConfig, includeAuthRule, existingSchemaDocument); -}; - -const retryWithVpcLambda = async (envName: string, databaseConfig, adapter: DataSourceAdapter): Promise => { - const meta = stateManager.getMeta(); - const { AmplifyAppId, Region } = meta.providers.awscloudformation; - const vpc = await getHostVpc(databaseConfig.host, Region); - - if (vpc) { - const shouldTryVpc = await prompter.confirmContinue( - `Unable to connect to the database from this machine. Would you like to try from VPC '${vpc.vpcId}'? (This will take several minutes):`, - ); - - if (shouldTryVpc) { - const schemaInspectorLambda = getVpcMetadataLambdaName(AmplifyAppId, envName); - await provisionSchemaInspectorLambda(schemaInspectorLambda, vpc, Region); - adapter.useVpc(schemaInspectorLambda, Region); - await adapter.initialize(); - return true; - } - } - - return false; -}; - -const parseSchema = (schemaContent: string | undefined, pathToSchemaFile: string): DocumentNode | undefined => { - if (!schemaContent) { - return; - } - - try { - const document = parse(schemaContent); - if (!document) { - return; - } - return document; - } catch (err) { - throw new Error(`The schema file at ${pathToSchemaFile} is not a valid GraphQL document. ${err?.message}`); - } -}; - -const buildSchemaFromConnection = async (envName: string, databaseConfig: ImportedDataSourceConfig): Promise => { - // Establish the connection - let adapter: DataSourceAdapter; - let schema: Schema; - const UNABLE_TO_CONNECT_MESSAGE = - 'Failed to connect to the specified RDS Data Source. Check the connection details in the schema and re-try. Use "amplify api update-secrets" to update the user credentials.'; - - switch (databaseConfig.engine) { - case ImportedRDSType.MYSQL: - adapter = new MySQLDataSourceAdapter(databaseConfig as DataSourceConfig); - schema = new Schema(new Engine('MySQL')); - break; - case ImportedRDSType.POSTGRESQL: - adapter = new PostgresDataSourceAdapter(databaseConfig as DataSourceConfig); - schema = new Schema(new Engine('Postgres')); - break; - default: - throw new AmplifyError('UserInputError', { message: 'Only MySQL and Postgres Data Sources are supported.' }); - } - - try { - await adapter.initialize(); - } catch (error) { - // If connection is unsuccessful, try connecting from VPC - if (error.code === 'ETIMEDOUT' || error.name === 'KnexTimeoutError') { - const canConnectFromVpc = await retryWithVpcLambda(envName, databaseConfig, adapter); - if (!canConnectFromVpc) { - throw new AmplifyError('UserInputError', { - message: UNABLE_TO_CONNECT_MESSAGE, - }); - } - } else { - throw error; - } - } - - const models = adapter.getModels(); - adapter.cleanup(); - models.forEach((m) => schema.addModel(m)); - - return schema; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/migrate-api-override-resource.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/migrate-api-override-resource.ts deleted file mode 100644 index ef0f65807a..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/migrate-api-override-resource.ts +++ /dev/null @@ -1,110 +0,0 @@ -import * as path from 'path'; -import { AmplifyCategories, JSONUtilities, pathManager, ResourceDoesNotExistError, stateManager } from '@aws-amplify/amplify-cli-core'; -import { printer } from '@aws-amplify/amplify-prompts'; -import * as fs from 'fs-extra'; -import { ResolverConfig } from 'graphql-transformer-core'; -import _ from 'lodash'; -import { v4 as uuid } from 'uuid'; -import { AppSyncCLIInputs } from '../service-walkthrough-types/appsync-user-input-types'; -import { authConfigToAppSyncAuthType } from './auth-config-to-app-sync-auth-type-bi-di-mapper'; -import { resolverConfigToConflictResolution } from './resolver-config-to-conflict-resolution-bi-di-mapper'; - -type ApiMetaData = { - resourceName: string; - authConfig: any; - resolverConfig: ResolverConfig; -}; -export const migrateResourceToSupportOverride = async (resourceName: string) => { - printer.debug('Starting Migration Process'); - /** - * backup resource folder - * get parameters.json - * generate and save cliInputs - * return cliInputs - * */ - const projectPath = pathManager.findProjectRoot(); - if (!projectPath) { - // New project, hence not able to find the amplify dir - throw new Error('Project not initialized'); - } - const apiresourceDirPath = pathManager.getResourceDirectoryPath(undefined, AmplifyCategories.API, resourceName); - const backupApiResourceFolder = backup(apiresourceDirPath, projectPath, resourceName); - - try { - let resolverConfig = {}; - const transformConfig = - JSONUtilities.readJson(path.join(apiresourceDirPath, 'transform.conf.json'), { throwIfNotExist: false }) ?? {}; - if (!_.isEmpty(transformConfig) && !_.isEmpty(transformConfig!.ResolverConfig)) { - resolverConfig = transformConfig!.ResolverConfig; - } - const authConfig = stateManager.getMeta()[AmplifyCategories.API][resourceName].output.authConfig; - if (_.isEmpty(authConfig)) { - throw new ResourceDoesNotExistError( - `auth configuration not present for ${resourceName}. Try amplify pull to sync your folder structure`, - ); - } - const parameters: ApiMetaData = { - authConfig, - resolverConfig, - resourceName, - }; - // convert parameters.json to cli-inputs.json - const cliInputs = generateCliInputs(parameters); - const cliInputsPath = path.join(apiresourceDirPath, 'cli-inputs.json'); - JSONUtilities.writeJson(cliInputsPath, cliInputs); - printer.debug('Migration is Successful'); - } catch (e) { - printer.error('There was an error migrating your project.'); - rollback(apiresourceDirPath, backupApiResourceFolder); - printer.debug('migration operations are rolled back.'); - throw e; - } finally { - cleanUp(backupApiResourceFolder); - } -}; - -function backup(authresourcePath: string, projectPath: string, resourceName: string) { - if (fs.existsSync(authresourcePath)) { - const backupauthResourceDirName = `${resourceName}-BACKUP-${uuid().split('-')[0]}`; - const backupauthResourceDirPath = path.join(projectPath, backupauthResourceDirName); - - if (fs.existsSync(backupauthResourceDirPath)) { - const error = new Error(`Backup folder at ${backupauthResourceDirPath} already exists, remove the folder and retry the operation.`); - - error.name = 'BackupFolderAlreadyExist'; - error.stack = undefined; - - throw error; - } - - fs.copySync(authresourcePath, backupauthResourceDirPath); - return backupauthResourceDirPath; - } -} - -function rollback(authresourcePath: string, backupauthResourceDirPath: string) { - if (fs.existsSync(authresourcePath) && fs.existsSync(backupauthResourceDirPath)) { - fs.removeSync(authresourcePath); - fs.moveSync(backupauthResourceDirPath, authresourcePath); - } -} - -function cleanUp(authresourcePath: string | undefined) { - if (!!authresourcePath && fs.existsSync(authresourcePath)) fs.removeSync(authresourcePath); -} - -const generateCliInputs = (parameters: ApiMetaData): AppSyncCLIInputs => { - return { - version: 1, - serviceConfiguration: { - serviceName: 'AppSync', - defaultAuthType: authConfigToAppSyncAuthType(parameters.authConfig ? parameters.authConfig.defaultAuthentication : undefined), - additionalAuthTypes: - !_.isEmpty(parameters.authConfig) && !_.isEmpty(parameters.authConfig.additionalAuthenticationProviders) - ? parameters.authConfig.additionalAuthenticationProviders.map(authConfigToAppSyncAuthType) - : undefined, - conflictResolution: resolverConfigToConflictResolution(parameters.resolverConfig), - apiName: parameters.resourceName, - }, - }; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/print-api-key-warnings.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/print-api-key-warnings.ts deleted file mode 100644 index dc4f8cd020..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/print-api-key-warnings.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { printer } from '@aws-amplify/amplify-prompts'; - -// If adding or removing the API_KEY auth type, print a warning that resources that depend on the API must re-add the API as a dependency to have the API key parameter added / removed. -export const printApiKeyWarnings = (oldConfigHadApiKey: boolean, newConfigHasApiKey: boolean) => { - if (oldConfigHadApiKey && !newConfigHasApiKey) { - printer.warn('The API_KEY auth type has been removed from the API.'); - printer.warn( - 'If other resources depend on this API, run "amplify update " and reselect this API to remove the dependency on the API key.', - ); - printer.warn('This must be done before running "amplify push" to prevent a push failure'); - } - - if (!oldConfigHadApiKey && newConfigHasApiKey) { - printer.warn('The API_KEY auth type has been added to the API.'); - printer.warn( - 'If other resources depend on this API and need access to the API key, run "amplify update " and reselect this API as a dependency to add the API key dependency.', - ); - } -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-input-utils.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-input-utils.ts deleted file mode 100644 index b11a1a91f5..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-input-utils.ts +++ /dev/null @@ -1,28 +0,0 @@ -import * as fs from 'fs-extra'; -import _ from 'lodash'; -import { DocumentNode, StringValueNode } from 'graphql'; -import { readRDSGlobalAmplifyInput } from '@aws-amplify/graphql-schema-generator'; -import { ImportedRDSType } from '@aws-amplify/graphql-transformer-core'; - -export const readRDSSchema = (pathToSchemaFile: string): string | undefined => { - if (!fs.existsSync(pathToSchemaFile)) { - return; - } - const schemaContent = fs.readFileSync(pathToSchemaFile, 'utf-8'); - if (_.isEmpty(schemaContent)) { - return; - } - return schemaContent; -}; - -export const getEngineInput = (schemaDocument: DocumentNode): ImportedRDSType => { - const inputNode = readRDSGlobalAmplifyInput(schemaDocument); - if (inputNode) { - const engine = (inputNode.fields.find((field) => field.name.value === 'engine')?.defaultValue as StringValueNode)?.value; - if (engine && !Object.values(ImportedRDSType).includes(engine as ImportedRDSType)) { - throw new Error(`engine input ${engine} is not supported.`); - } - return engine as ImportedRDSType; - } - return ImportedRDSType.MYSQL; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-resources/database-resources.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-resources/database-resources.ts deleted file mode 100644 index 5d69d8abb0..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-resources/database-resources.ts +++ /dev/null @@ -1,345 +0,0 @@ -import { $TSContext, stateManager } from '@aws-amplify/amplify-cli-core'; -import _ from 'lodash'; -import { - getParameterStoreSecretPath, - RDSConnectionSecrets, - ImportedRDSType, - ImportedDataSourceConfig, -} from '@aws-amplify/graphql-transformer-core'; -import { MySQLDataSourceAdapter, DataSourceAdapter, DataSourceConfig } from '@aws-amplify/graphql-schema-generator'; -import { printer } from '@aws-amplify/amplify-prompts'; -import { DeleteFunctionCommand, LambdaClient } from '@aws-sdk/client-lambda'; -import { DeleteRoleCommand, IAMClient } from '@aws-sdk/client-iam'; -import { SqlModelDataSourceSsmDbConnectionConfig } from '@aws-amplify/graphql-transformer-interfaces'; -import { getAppSyncAPIName } from '../amplify-meta-utils'; -import { databaseConfigurationInputWalkthrough } from '../../service-walkthroughs/appSync-rds-db-config'; -import { SSMClient } from './ssmClient'; - -const secretNames = ['database', 'host', 'port', 'username', 'password']; -const secretNamesToDbConnectionConfigFields: Record = { - database: 'databaseNameSsmPath', - host: 'hostnameSsmPath', - port: 'portSsmPath', - username: 'usernameSsmPath', - password: 'passwordSsmPath', -}; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const isConnectionSecrets = (obj: any): obj is RDSConnectionSecrets => { - if (typeof obj !== 'object' || obj === null) { - return false; - } - - return secretNames.every((secretName) => secretName in obj); -}; - -/** - * Derive name of schema inspector lambda - * @param appId the Amplify App ID - * @param envName the Amplify environment name - * @returns the name of the schema inspector lambda - */ -export const getVpcMetadataLambdaName = (appId: string, envName: string): string => { - if (appId && envName) { - return `${appId}-rds-schema-inspector-${envName}`; - } - throw new Error('AppId and environment name are required to generate the schema inspector lambda.'); -}; - -/** - * Get database connection information from SSM - * @param context the Amplify CLI context - * @param secretsKey the "key" part of the SSM path of the parameter to retrieve - * @param apiName the AppSync API name - * @param envName the Amplify environment name - * @returns a promise that resolves to the database connection information, or undefined if no connection information is stored - */ -export const getExistingConnectionSecrets = async ( - context: $TSContext, - secretsKey: string, - apiName: string, - envName?: string, -): Promise => { - try { - const environmentName = envName || stateManager.getCurrentEnvName(); - const appId = stateManager.getAppID(); - - const ssmClient = await SSMClient.getInstance(context); - const secrets = await ssmClient.getSecrets( - secretNames.map((secret) => getParameterStoreSecretPath(secret, secretsKey, apiName, environmentName, appId)), - ); - - if (_.isEmpty(secrets)) { - return undefined; - } - - const existingSecrets = secretNames - .map((secretName) => { - const secretPath = getParameterStoreSecretPath(secretName, secretsKey, apiName, environmentName, appId); - const matchingSecret = secrets?.find((secret) => secret?.secretName === secretPath && !_.isEmpty(secret?.secretValue)); - const result = {}; - if (matchingSecret) { - result[secretName] = matchingSecret.secretValue; - } - return result; - }) - .reduce((result, current) => { - if (!_.isEmpty(current)) { - return Object.assign(result, current); - } else { - return current; - } - }, {}); - - if (isConnectionSecrets(existingSecrets)) { - return existingSecrets; - } else { - return undefined; - } - } catch (error) { - return undefined; - } -}; - -/** - * Derives expected path names for database connection config parameters stored during the Gen1 CLI import flow. - */ -export const getExistingConnectionDbConnectionConfig = (apiName: string, secretsKey: string): SqlModelDataSourceSsmDbConnectionConfig => { - const environmentName = stateManager.getCurrentEnvName(); - const appId = stateManager.getAppID(); - const dbConnectionConfig: any = {}; - secretNames.forEach((name) => { - const path = getParameterStoreSecretPath(name, secretsKey, apiName, environmentName, appId); - dbConnectionConfig[secretNamesToDbConnectionConfigFields[name]] = path; - }); - return dbConnectionConfig; -}; - -/** - * Get SSM paths for database connection information - * @param context the Amplify CLI context - * @param apiName the AppSync API name - * @param secretsKey the "key" part of the SSM path of the parameter to retrieve - * @param envName the Amplify environment name - * @returns a promise that resolves to the database connection information, or undefined if no connection information is stored - */ -export const getExistingConnectionSecretNames = async ( - context: $TSContext, - apiName: string, - secretsKey: string, - envName?: string, -): Promise => { - try { - const environmentName = envName || stateManager.getCurrentEnvName(); - const appId = stateManager.getAppID(); - const ssmClient = await SSMClient.getInstance(context); - const secrets = await ssmClient.getSecrets( - secretNames.map((secret) => getParameterStoreSecretPath(secret, secretsKey, apiName, environmentName, appId)), - ); - - if (_.isEmpty(secrets)) { - return undefined; - } - - const existingSecrets = secretNames - .map((secretName) => { - const secretPath = getParameterStoreSecretPath(secretName, secretsKey, apiName, environmentName, appId); - const matchingSecret = secrets?.find((secret) => secret?.secretName === secretPath && !_.isEmpty(secret?.secretValue)); - const result = {}; - if (matchingSecret) { - result[secretName] = secretPath; - } - return result; - }) - .reduce((result, current) => { - if (!_.isEmpty(current)) { - return Object.assign(result, current); - } else { - return current; - } - }, {}); - - if (isConnectionSecrets(existingSecrets)) { - return existingSecrets; - } else { - return undefined; - } - } catch (error) { - return undefined; - } -}; - -/** - * Store database connection information into SSM - * @param context the Amplify CLI context - * @param secrets the connection information to store - * @param apiName the AppSync API name - * @param secretsKey the prefix of the SSM path of the parameter to store - */ -export const storeConnectionSecrets = async ( - context: $TSContext, - secrets: RDSConnectionSecrets, - apiName: string, - secretsKey: string, -): Promise => { - const environmentName = stateManager.getCurrentEnvName(); - const appId = stateManager.getAppID(); - - const ssmClient = await SSMClient.getInstance(context); - secretNames.map(async (secret) => { - const parameterPath = getParameterStoreSecretPath(secret, secretsKey, apiName, environmentName, appId); - await ssmClient.setSecret(parameterPath, secrets[secret]?.toString()); - }); -}; - -/** - * Delete database connection information from SSM - * @param context the Amplify CLI context - * @param secretsKey the prefix of the SSM path of the parameter to store - * @param apiName the AppSync API name - * @param envName the Amplify environment name - */ -export const deleteConnectionSecrets = async ( - context: $TSContext, - secretsKey: string, - apiName: string, - envName?: string, -): Promise => { - const environmentName = stateManager.getCurrentEnvName(); - const meta = stateManager.getMeta(); - const { AmplifyAppId } = meta.providers.awscloudformation; - if (!AmplifyAppId) { - printer.debug(`No AppId found when deleting parameters for environment ${envName}`); - return; - } - const ssmClient = await SSMClient.getInstance(context); - const secretParameterPaths = secretNames.map((secret) => { - return getParameterStoreSecretPath(secret, secretsKey, apiName, environmentName, AmplifyAppId); - }); - await ssmClient.deleteSecrets(secretParameterPaths); -}; - -// TODO: This is not used. Leaving it here for now. Generate schema step already checks for connection. -/** - * Try to establish a connection using the provided connection information - * @param config the database connection information - */ -export const testDatabaseConnection = async (config: RDSConnectionSecrets): Promise => { - // Establish the connection - let adapter: DataSourceAdapter; - let canConnect = false; - - switch (config.engine) { - case ImportedRDSType.MYSQL: - adapter = new MySQLDataSourceAdapter(config as DataSourceConfig); - break; - default: - printer.error('Only MySQL Data Source is supported.'); - } - - try { - canConnect = await adapter.test(); - } finally { - adapter.cleanup(); - } - - return canConnect; -}; - -// this will be an extension point when we support multiple database imports. -/** - * Returns the prefix for the database configuration SSM paths - * @returns the prefix for the database configuration SSM paths - */ -export const getSecretsKey = (): string => 'schema'; - -/** - * Retrieves the database name from SSM - * @param context the Amplify CLI context - * @param apiName the AppSync API name - * @param secretsKey the prefix of the SSM path of the parameter to store - * @returns a Promise that resolves to the database name, or undefined if the name isn't at the expected SSM path - */ -export const getDatabaseName = async (context: $TSContext, apiName: string, secretsKey: string): Promise => { - const environmentName = stateManager.getCurrentEnvName(); - const appId = stateManager.getAppID(); - const ssmClient = await SSMClient.getInstance(context); - - const secrets = await ssmClient.getSecrets([getParameterStoreSecretPath('database', secretsKey, apiName, environmentName, appId)]); - - if (_.isEmpty(secrets)) { - return undefined; - } - - return secrets[0].secretValue; -}; - -/** - * Deletes the IAM role for the schema inspector lambda - * @param lambdaName the function name of the schema inspector lambda - */ -export const deleteSchemaInspectorLambdaRole = async (lambdaName: string): Promise => { - const roleName = `${lambdaName}-execution-role`; - const client = new IAMClient({}); - const command = new DeleteRoleCommand({ RoleName: roleName }); - await client.send(command); -}; - -/** - * Deletes the schema inspector lambda and associated IAM role - * @param context the Amplify CLI context - */ -export const removeVpcSchemaInspectorLambda = async (context: $TSContext): Promise => { - try { - // Delete the lambda function - const meta = stateManager.getMeta(); - const { AmplifyAppId, Region } = meta.providers.awscloudformation; - const { amplify } = context; - const { envName } = amplify.getEnvInfo(); - const lambdaName = getVpcMetadataLambdaName(AmplifyAppId, envName); - - const client = new LambdaClient({ region: Region }); - const command = new DeleteFunctionCommand({ FunctionName: lambdaName }); - await client.send(command); - - // Delete the role and policy - await deleteSchemaInspectorLambdaRole(lambdaName); - } catch (error) { - printer.debug(`Error deleting the schema inspector lambda: ${error}`); - // 1. Ignore if the AppId is not found error. - // 2. Schema introspection will exist only on databases imported from VPC. Ignore the error on environment deletion. - } -}; - -/** - * Retrieve database connection information from SSM - * @param context the Amplify CLI context - * @param secretsKey the prefix of the SSM path of the parameter to store - * @param engine the database engine type to retrieve connection info for - */ -export const getConnectionSecrets = async ( - context: $TSContext, - secretsKey: string, - engine: ImportedRDSType, -): Promise<{ secrets: RDSConnectionSecrets & { engine: ImportedRDSType }; storeSecrets: boolean }> => { - const apiName = getAppSyncAPIName(); - const existingSecrets = await getExistingConnectionSecrets(context, secretsKey, apiName); - if (existingSecrets) { - return { - secrets: { - engine, - ...existingSecrets, - }, - storeSecrets: false, - }; - } - - const databaseConfig: ImportedDataSourceConfig = await databaseConfigurationInputWalkthrough(engine); - return { - secrets: { - engine, - ...databaseConfig, - }, - storeSecrets: true, - }; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-resources/multi-env-database-secrets.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-resources/multi-env-database-secrets.ts deleted file mode 100644 index e402b790c7..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-resources/multi-env-database-secrets.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { storeConnectionSecrets, getExistingConnectionSecrets } from '../../utils/rds-resources/database-resources'; -import { printer } from '@aws-amplify/amplify-prompts'; - -type EnvironmentInfo = { - isNewEnv: boolean; - sourceEnv: string; - yesFlagSet: boolean; - envName: string; -}; - -export const configureMultiEnvDBSecrets = async (context: $TSContext, secretsKey: string, apiName: string, envInfo: EnvironmentInfo) => { - // For existing environments, the secrets are already set in parameter store - if (!envInfo.isNewEnv) { - return; - } - - // For new environments, the secrets are copied over from the source environment. - const secrets = await getExistingConnectionSecrets(context, secretsKey, apiName, envInfo.sourceEnv); - if (!secrets) { - printer.warn( - `Could not copy over the user secrets for imported database. Run "amplify api update-secrets" to set them for the current environment.`, - ); - return; - } - - await storeConnectionSecrets(context, secrets, apiName, secretsKey); - return; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-resources/ssmClient.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-resources/ssmClient.ts deleted file mode 100644 index ebed196a38..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-resources/ssmClient.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import aws from 'aws-sdk'; - -export type Secret = { - secretName: string; - secretValue: string; -}; - -/** - * SSM client provider for AWS SDK calls - */ -export class SSMClient { - private static instance: SSMClient; - - static getInstance = async (context: $TSContext): Promise => { - if (!SSMClient?.instance) { - SSMClient.instance = new SSMClient(await getSSMClient(context)); - } - return SSMClient.instance; - }; - - private constructor(private readonly ssmClient: aws.SSM) {} - - /** - * Returns a list of secret name value pairs - */ - getSecrets = async (secretNames: string[]): Promise => { - if (!secretNames || secretNames?.length === 0) { - return []; - } - const result = await this.ssmClient - .getParameters({ - Names: secretNames, - WithDecryption: true, - }) - .promise(); - - return result?.Parameters?.map(({ Name, Value }) => ({ secretName: Name, secretValue: Value })); - }; - - /** - * Returns all secret names under a path. Does NOT decrypt any secrets - */ - getSecretNamesByPath = async (secretPath: string): Promise => { - let nextToken: string | undefined; - const secretNames: string[] = []; - do { - const result = await this.ssmClient - .getParametersByPath({ - Path: secretPath, - MaxResults: 10, - ParameterFilters: [ - { - Key: 'Type', - Option: 'Equals', - Values: ['SecureString'], - }, - ], - NextToken: nextToken, - }) - .promise(); - secretNames.push(...result?.Parameters?.map((param) => param?.Name)); - nextToken = result?.NextToken; - } while (nextToken); - return secretNames; - }; - - /** - * Sets the given secretName to the secretValue. If secretName is already present, it is overwritten. - */ - setSecret = async (secretName: string, secretValue: string): Promise => { - await this.ssmClient - .putParameter({ - Name: secretName, - Value: secretValue, - Type: 'SecureString', - Overwrite: true, - }) - .promise(); - }; - - /** - * Deletes secretName. If it already doesn't exist, this is treated as success. All other errors will throw. - */ - deleteSecret = async (secretName: string): Promise => { - try { - await this.ssmClient.deleteParameter({ Name: secretName }).promise(); - } catch (err) { - if (err?.code !== 'ParameterNotFound') { - // if the value didn't exist in the first place, consider it deleted - throw err; - } - } - }; - - /** - * Deletes all secrets in secretNames.If secret doesn't exist, this is treated as success. All other errors will throw. - */ - deleteSecrets = async (secretNames: string[]): Promise => { - try { - await this.ssmClient.deleteParameters({ Names: secretNames }).promise(); - } catch (err) { - // if the value didn't exist in the first place, consider it deleted - if (err?.code !== 'ParameterNotFound') { - throw err; - } - } - }; -} - -// The Provider plugin holds all the configured service clients. Fetch from there. -const getSSMClient = async (context: $TSContext): Promise => { - const { client } = (await context.amplify.invokePluginMethod(context, 'awscloudformation', undefined, 'getConfiguredSSMClient', [ - context, - ])) as any; - return client as aws.SSM; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-resources/utils.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-resources/utils.ts deleted file mode 100644 index 7a84a14fb8..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rds-resources/utils.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { parse, FieldDefinitionNode, ObjectTypeDefinitionNode, visit } from 'graphql'; -import _ from 'lodash'; -import { isSqlStrategy } from '@aws-amplify/graphql-transformer-core'; -import { - DataSourceStrategiesProvider, - ModelDataSourceStrategy, - SqlDirectiveDataSourceStrategy, -} from '@aws-amplify/graphql-transformer-interfaces'; - -export const checkForUnsupportedDirectives = (schema: string, context: DataSourceStrategiesProvider): void => { - const unsupportedRDSDirectives = ['searchable', 'predictions', 'function', 'manyToMany', 'http', 'mapsTo']; - if (_.isEmpty(schema) || _.isEmpty(context.dataSourceStrategies)) { - return; - } - - const rdsModels = Object.entries(context.dataSourceStrategies) - .filter(([key, value]) => isSqlStrategy(value)) - .map(([key, value]) => key); - - if (_.isEmpty(rdsModels)) { - return; - } - - const document = parse(schema); - const schemaVisitor = { - FieldDefinition: { - enter(node: FieldDefinitionNode, key, parent, path, ancestors): any { - const parentName = getParentName(ancestors); - if (!(parentName === 'Query') && !rdsModels?.includes(parentName)) { - return; - } - node?.directives?.map((directive) => { - if (unsupportedRDSDirectives.includes(directive?.name?.value)) { - throw unsupportedDirectiveError(directive?.name?.value, node?.name?.value, parentName, unsupportedRDSDirectives); - } - }); - }, - }, - ObjectTypeDefinition: { - enter(node: ObjectTypeDefinitionNode): any { - const typeName = node?.name?.value; - if (!(typeName === 'Query') && !rdsModels?.includes(typeName)) { - return; - } - node?.directives?.map((directive) => { - if (unsupportedRDSDirectives.includes(directive?.name?.value)) { - throw unsupportedDirectiveError(directive?.name?.value, undefined, node?.name?.value, unsupportedRDSDirectives); - } - }); - }, - }, - }; - - visit(document, schemaVisitor); -}; - -export const containsSqlModelOrDirective = ( - dataSourceStrategies: Record, - sqlDirectiveDataSourceStrategies?: SqlDirectiveDataSourceStrategy[], -): boolean => { - if (sqlDirectiveDataSourceStrategies && sqlDirectiveDataSourceStrategies?.length > 0) { - return true; - } - return Object.values(dataSourceStrategies).some((strategy) => isSqlStrategy(strategy)); -}; - -const unsupportedDirectiveError = ( - directiveName: string, - fieldName: string | undefined, - typeName: string, - unsupportedDirectives: string[], -): Error => { - return new Error( - `@${directiveName} directive on type "${typeName}" ${ - fieldName ? `and field "${fieldName}"` : '' - } is not supported on a SQL datasource. Following directives are not supported on a SQL datasource: ${unsupportedDirectives.join( - ', ', - )}`, - ); -}; - -const getParentName = (ancestors: any[]): string | undefined => { - if (ancestors && ancestors?.length > 0) { - return (ancestors[ancestors.length - 1] as ObjectTypeDefinitionNode)?.name?.value; - } - return undefined; -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/resolver-config-to-conflict-resolution-bi-di-mapper.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/resolver-config-to-conflict-resolution-bi-di-mapper.ts deleted file mode 100644 index fdcec14512..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/resolver-config-to-conflict-resolution-bi-di-mapper.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { ConflictResolution, PerModelResolutionstrategy, ResolutionStrategy, LambdaResolutionStrategy } from 'amplify-headless-interface'; -import { ResolverConfig, SyncConfig, ConflictHandlerType, SyncConfigLAMBDA } from 'graphql-transformer-core'; -import _ from 'lodash'; - -export const conflictResolutionToResolverConfig = (conflictResolution: ConflictResolution = {}): ResolverConfig => { - const result: ResolverConfig = {}; - if (_.isEmpty(conflictResolution)) return undefined; - if (conflictResolution.defaultResolutionStrategy) { - result.project = resolutionStrategyToSyncConfig(conflictResolution.defaultResolutionStrategy); - } - if (conflictResolution.perModelResolutionStrategy) { - result.models = modelSyncConfigTransformer(conflictResolution.perModelResolutionStrategy); - } - return result; -}; - -export const resolverConfigToConflictResolution = (resolverConfig: ResolverConfig = {}): ConflictResolution => { - const result: ConflictResolution = {}; - if (resolverConfig.project) { - result.defaultResolutionStrategy = syncConfigToResolutionStrategy(resolverConfig.project); - } - if (resolverConfig.models) { - result.perModelResolutionStrategy = modelResolutionStrategyTransformer(resolverConfig.models); - } - return result; -}; - -const modelSyncConfigTransformer = (perModelResolutionStrategy: PerModelResolutionstrategy[]): { [key: string]: SyncConfig } => { - const result: { [key: string]: SyncConfig } = {}; - perModelResolutionStrategy.forEach( - (strategy) => (result[strategy.entityName] = resolutionStrategyToSyncConfig(strategy.resolutionStrategy)), - ); - return result; -}; - -const modelResolutionStrategyTransformer = (modelSyncConfig: { [key: string]: SyncConfig }): PerModelResolutionstrategy[] => { - const result: PerModelResolutionstrategy[] = []; - Object.entries(modelSyncConfig) - .map( - ([key, value]): PerModelResolutionstrategy => ({ - resolutionStrategy: syncConfigToResolutionStrategy(value), - entityName: key, - }), - ) - .forEach((modelStrategy) => result.push(modelStrategy)); - return result; -}; - -const resolutionStrategyToSyncConfig = (resolutionStrategy: ResolutionStrategy, newFunctionMap?: Record): SyncConfig => { - const defaultMapper = () => undefined; - return _.get(resolutionStrategyToSyncConfigMap, resolutionStrategy.type, defaultMapper)(resolutionStrategy); -}; - -const resolutionStrategyToSyncConfigMap: Record SyncConfig> = { - AUTOMERGE: () => ({ - ConflictHandler: ConflictHandlerType.AUTOMERGE, - ConflictDetection: 'VERSION', - }), - OPTIMISTIC_CONCURRENCY: () => ({ - ConflictHandler: ConflictHandlerType.OPTIMISTIC, - ConflictDetection: 'VERSION', - }), - LAMBDA: (resolutionStrategy: LambdaResolutionStrategy) => { - switch (resolutionStrategy.resolver.type) { - case 'EXISTING': { - const { name, region, arn } = resolutionStrategy.resolver; - return { - ConflictHandler: ConflictHandlerType.LAMBDA, - ConflictDetection: 'VERSION', - LambdaConflictHandler: { name, region, lambdaArn: arn }, - }; - } - case 'NEW': - throw new Error( - 'Tried to convert LambdaResolutionStrategy "NEW" to SyncConfig. New resources must be generated prior to this conversion and then replaced with a LambdaResolutionStrategy of type "EXISTING"', - ); - } - }, -}; - -const syncConfigToResolutionStrategy = (syncConfig: SyncConfig): ResolutionStrategy => { - const defaultMapper = (): ResolutionStrategy => ({ type: 'NONE' }); - return _.get(syncConfigToResolutionStrategyMap, syncConfig.ConflictHandler, defaultMapper)(syncConfig); -}; - -const syncConfigToResolutionStrategyMap: Record ResolutionStrategy> = { - AUTOMERGE: () => ({ - type: 'AUTOMERGE', - }), - OPTIMISTIC_CONCURRENCY: () => ({ - type: 'OPTIMISTIC_CONCURRENCY', - }), - LAMBDA: (syncConfig: SyncConfigLAMBDA) => ({ - type: 'LAMBDA', - resolver: (syncConfig.LambdaConflictHandler as any).new - ? { - // this is a hack to pass the "new" flag into the ResolutionStrategy - type: 'NEW', - } - : { - type: 'EXISTING', - name: syncConfig.LambdaConflictHandler.name, - region: syncConfig.LambdaConflictHandler.region, - arn: syncConfig.LambdaConflictHandler.lambdaArn, - }, - }), -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rest-api-path-utils.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rest-api-path-utils.ts deleted file mode 100644 index b0ef42fde3..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rest-api-path-utils.ts +++ /dev/null @@ -1,89 +0,0 @@ -// validatePathName checks that the provided path name is of a valid path structure. -// Examples of valid path structures: /book, /book/{isbn}, /book/{isbn}/page/{pageNum} -export const validatePathName = (name: string) => { - // Allow the path / - if (name === '/') { - return true; - } - - if (name.length === 0) { - return 'The path must not be empty'; - } - - if (name.charAt(name.length - 1) === '/') { - return 'The path must not end with /'; - } - - if (name.charAt(0) !== '/') { - return 'The path must begin with / e.g. /items'; - } - - // Matches parameterized paths such as /book/{isbn}/page/{pageNum} - // This regex also catches the above conditions, but those are left in to provide clearer error messages. - if (!/^(?:\/(?:[a-zA-Z0-9\-]+|{[a-zA-Z0-9\-]+}))+$/.test(name)) { - return 'Each path part must use characters a-z A-Z 0-9 - and must not be empty.\nOptionally, a path part can be surrounded by { } to denote a path parameter.'; - } - - return true; -}; - -// checkForPathOverlap checks to see if the provided path name eclipses or overlaps any other paths in the provided list of paths. -// -// checkForPathOverlap returns false if the provided path name does not overlap with any of the other provided paths. -// checkForPathOverlap returns an object with the following structure if the provided path name does overlap with any of the provided paths: -// { -// higherOrderPath: string, -// lowerOrderPath: string, -// } -// -// checkForPathOverlap assumes that all provided paths have previously been run through validatePathName(). -export const checkForPathOverlap = (name: string, paths: string[]) => { - // Split name into an array of its components. - const split = name.split('/').filter((sub) => sub !== ''); // Because name starts with a /, this filters out the first empty element - - // Sort paths so that the prefix paths of name are checked with shorter paths first. - paths.sort(); - - // Check if any prefix of this path matches an existing path. - // - // Convert parameters to: '{}'. When evaluating whether paths overlap, we're only concerned about the placement of parameters in those - // paths --- not what the parameters are named. - // - // Ex: paths /book/{isbn} and /book/{publication-year} overlap. We aren't concerned with the fact that the parameters in those two routes - // are named "isbn" and "publication-year"; we're concerned about the fact that the subpaths after /book in both paths are parameters. - let subpath = ''; - let overlappingPath = ''; - const subMatch = split.some((sub) => { - // If the current subpath is a parameter, convert it to: '{}'. - sub = sub.replace(/{[a-zA-Z0-9\-]+}/g, '{}'); - subpath = `${subpath}/${sub}`; - // Explicitly check for the path / since it overlaps with any other valid path. - // If the path isn't /, replace all of its parameters with '{}' when checking for overlap in find(). - overlappingPath = paths.find((name) => name === '/' || name.replace(/{[a-zA-Z0-9\-]+}/g, '{}') === subpath); - return overlappingPath !== undefined; - }); - if (subMatch) { - // To determine which of the overlapping paths is the higher order path, count the number of occurrences of '/' in both paths. - const nameSlashCount = name.split('/').length - 1; - const overlappingPathSlashCount = overlappingPath.split('/').length - 1; - if (nameSlashCount < overlappingPathSlashCount) { - return { - higherOrderPath: name, - lowerOrderPath: overlappingPath, - }; - } - return { - higherOrderPath: overlappingPath, - lowerOrderPath: name, - }; - } - - // This path doesn't overlap with any of the other provided paths. - return false; -}; - -// Convert a CloudFormation parameterized path to an ExpressJS parameterized path -// /library/{libraryId}/book/{isbn} => /library/:libraryId/book/:isbn -export const formatCFNPathParamsForExpressJs = (path: string) => { - return path.replace(/{([a-zA-Z0-9\-]+)}/g, ':$1'); -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/service-walkthrough-result-to-add-api-request.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/service-walkthrough-result-to-add-api-request.ts deleted file mode 100644 index 5a8fb460a3..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/service-walkthrough-result-to-add-api-request.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { AddApiRequest } from 'amplify-headless-interface'; -import _ from 'lodash'; -import { resolverConfigToConflictResolution } from './resolver-config-to-conflict-resolution-bi-di-mapper'; -import { authConfigToAppSyncAuthType } from './auth-config-to-app-sync-auth-type-bi-di-mapper'; - -// Temporary conversion function between the existing output of the appSync service walkthrough and the new AddApiRequest interface -// Long-term, the service walkthrough should be refactored to directly return an object conforming to the interface -export const serviceWalkthroughResultToAddApiRequest = (result): AddApiRequest => ({ - version: 1, - serviceConfiguration: { - serviceName: 'AppSync', - apiName: result.answers.apiName, - transformSchema: result.schemaContent, - defaultAuthType: authConfigToAppSyncAuthType(result.output.authConfig.defaultAuthentication), - additionalAuthTypes: (result.output.authConfig.additionalAuthenticationProviders || []).map(authConfigToAppSyncAuthType), - conflictResolution: resolverConfigToConflictResolution(result.resolverConfig), - }, -}); diff --git a/packages/amplify-category-api/src/provider-utils/supported-datasources.ts b/packages/amplify-category-api/src/provider-utils/supported-datasources.ts deleted file mode 100644 index 97d679ad4e..0000000000 --- a/packages/amplify-category-api/src/provider-utils/supported-datasources.ts +++ /dev/null @@ -1,56 +0,0 @@ -export const supportedDataSources = { - 'Aurora Serverless': { - inputs: [ - { - key: 'region', - type: 'list', - question: 'Provide the region in which your cluster is located:', - required: true, - }, - { - key: 'rdsClusterIdentifier', - type: 'list', - question: 'Select the Aurora Serverless cluster that will be used as the data source for your API:', - required: true, - }, - { - key: 'rdsSecretStoreArn', - type: 'list', - question: 'Select the secret used to access your Aurora Serverless cluster:', - required: true, - }, - { - key: 'databaseName', - type: 'list', - question: 'Select the database to use as the datasource:', - required: true, - }, - ], - alias: 'Aurora Serverless', - serviceWalkthroughFilename: 'appSync-rds-walkthrough.js', - cfnFilename: 'appSync-rds-cloudformation-template-default.yml.ejs', - provider: 'awscloudformation', - availableRegions: [ - 'us-east-1', - 'us-east-2', - 'us-west-1', - 'us-west-2', - 'ap-east-1', - 'ap-south-1', - 'ap-southeast-1', - 'ap-southeast-2', - 'ap-northeast-1', - 'ap-northeast-2', - 'ap-northeast-3', - 'ca-central-1', - 'eu-central-1', - 'eu-north-1', - 'eu-south-1', - 'eu-west-1', - 'eu-west-2', - 'eu-west-3', - 'me-south-1', - 'sa-east-1', - ], - }, -}; diff --git a/packages/amplify-category-api/src/provider-utils/supported-services.ts b/packages/amplify-category-api/src/provider-utils/supported-services.ts deleted file mode 100644 index 21de2e9c38..0000000000 --- a/packages/amplify-category-api/src/provider-utils/supported-services.ts +++ /dev/null @@ -1,153 +0,0 @@ -export const supportedServices = { - AppSync: { - inputs: [ - { - key: 'resourceName', - type: 'input', - question: 'Provide a friendly name for your resource to be used as label for this category in the project:', - validation: { - operator: 'regex', - value: '^[a-zA-Z0-9]+$', - onErrorMsg: 'Resource name should be alphanumeric', - }, - required: true, - }, - { - key: 'apiName', - type: 'input', - question: 'Provide API name:', - validation: { - operator: 'regex', - value: '^[a-zA-Z0-9]{1,80}$', - onErrorMsg: 'You can use the following characters: a-z A-Z 0-9 with maximum length of 80', - }, - required: true, - }, - { - key: 'apiCreationChoice', - type: 'confirm', - question: 'Do you have an annotated GraphQL schema?', - required: true, - }, - { - key: 'schemaFilePath', - type: 'input', - question: 'Provide your schema file path:', - required: true, - }, - { - key: 'templateSelection', - type: 'list', - question: 'Choose a schema template:', - options: [ - { - name: 'Single object with fields (e.g., “Todo” with ID, name, description)', - value: 'single-object-schema.graphql', - }, - { - name: 'One-to-many relationship (e.g., “Blogs” with “Posts” and “Comments”)', - value: 'many-relationship-schema.graphql', - }, - { - name: 'Objects with fine-grained access control (e.g., a project management app with owner-based authorization)', - value: 'single-object-auth-schema.graphql', - }, - { - name: 'Blank Schema', - value: 'blank-schema.graphql', - }, - ], - required: true, - }, - { - key: 'editSchemaChoice', - type: 'confirm', - question: 'Do you want to edit the schema now?', - required: true, - }, - { - key: 'editorSelection', - type: 'list', - question: 'Choose the editor you want to open the schema in:', - options: [ - { - name: 'Sublime Text', - value: 'sublime', - }, - { - name: 'Atom Editor', - value: 'atom', - }, - { - name: 'Visual Studio Code', - value: 'code', - }, - { - name: 'IDEA 14 CE', - value: 'idea14ce', - }, - { - name: 'Vim (via Terminal, macOS only)', - value: 'vim', - }, - { - name: 'Emacs (via Terminal, macOS only)', - value: 'emacs', - }, - { - name: 'None - Use my env variables to open my default editor', - value: 'none', - }, - ], - required: true, - }, - { - key: 'dynamoDbType', - type: 'list', - question: 'Choose a DynamoDB data source option', - options: [ - { - name: 'Use the DynamoDB table configured in the current Amplify project', - value: 'currentProject', - }, - { - name: 'Create a new DynamoDB table', - value: 'newResource', - }, - { - name: 'Use a DynamoDB table already deployed on AWS', - value: 'cloudResource', - }, - ], - }, - ], - alias: 'GraphQL', - serviceWalkthroughFilename: 'appSync-walkthrough.js', - cfnFilename: 'appSync-cloudformation-template-default.yml.ejs', - provider: 'awscloudformation', - }, - 'API Gateway': { - inputs: [ - { - key: 'apiName', - question: 'Provide a friendly name for your API:', - required: true, - }, - { - key: 'pathName', - question: 'HTTP path name?', - type: 'input', - required: 'true', - }, - { - key: 'lambdaFunction', - question: 'Select the Lambda function', - required: true, - type: 'input', - }, - ], - alias: 'REST', - serviceWalkthroughFilename: 'apigw-walkthrough.js', - provider: 'awscloudformation', - }, -}; diff --git a/packages/amplify-category-api/src/provider-utils/vpc-utils.ts b/packages/amplify-category-api/src/provider-utils/vpc-utils.ts deleted file mode 100644 index fbbb70c3a7..0000000000 --- a/packages/amplify-category-api/src/provider-utils/vpc-utils.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { SubnetAvailabilityZone } from '@aws-amplify/graphql-transformer-interfaces'; -import { EC2Client, DescribeSubnetsCommand } from '@aws-sdk/client-ec2'; - -export const getAvailabilityZoneOfSubnets = async (subnetIds: string[], region: string): Promise => { - const ec2 = new EC2Client({ region }); - const command = new DescribeSubnetsCommand({ - SubnetIds: subnetIds, - }); - const subnets = await ec2.send(command); - return subnets.Subnets?.map((subnet) => ({ - subnetId: subnet.SubnetId, - availabilityZone: subnet.AvailabilityZone, - })); -}; diff --git a/packages/amplify-category-api/tsconfig.json b/packages/amplify-category-api/tsconfig.json deleted file mode 100644 index 4689ad577b..0000000000 --- a/packages/amplify-category-api/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "lib", - "rootDir": "src", - "strict": false, - "allowJs": false - }, - "exclude": [ - "coverage", - "lib", - "scripts", - "resources/awscloudformation/lambdas", - "resources/awscloudformation/container-templates", - "resources/awscloudformation/graphql-lambda-authorizer", - "resources/awscloudformation/overrides-resource", - "scripts", - "src/__tests__" - ] -} diff --git a/packages/amplify-dynamodb-simulator/.npmignore b/packages/amplify-dynamodb-simulator/.npmignore deleted file mode 100644 index 77a94494aa..0000000000 --- a/packages/amplify-dynamodb-simulator/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -__test__ -.pid diff --git a/packages/amplify-dynamodb-simulator/.pid/.gitkeep b/packages/amplify-dynamodb-simulator/.pid/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/amplify-dynamodb-simulator/CHANGELOG.md b/packages/amplify-dynamodb-simulator/CHANGELOG.md deleted file mode 100644 index 76c32817d6..0000000000 --- a/packages/amplify-dynamodb-simulator/CHANGELOG.md +++ /dev/null @@ -1,576 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [2.4.17](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-dynamodb-simulator@2.4.16...amplify-category-api-dynamodb-simulator@2.4.17) (2024-07-15) - -**Note:** Version bump only for package amplify-category-api-dynamodb-simulator - -## [2.4.16](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-dynamodb-simulator@2.4.15...amplify-category-api-dynamodb-simulator@2.4.16) (2024-02-28) - -**Note:** Version bump only for package amplify-category-api-dynamodb-simulator - -## [2.4.15](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-dynamodb-simulator@2.4.14...amplify-category-api-dynamodb-simulator@2.4.15) (2023-10-21) - -**Note:** Version bump only for package amplify-category-api-dynamodb-simulator - -## [2.4.14](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-dynamodb-simulator@2.4.13...amplify-category-api-dynamodb-simulator@2.4.14) (2023-08-28) - -**Note:** Version bump only for package amplify-category-api-dynamodb-simulator - -## [2.4.13](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-dynamodb-simulator@2.4.12...amplify-category-api-dynamodb-simulator@2.4.13) (2023-08-09) - -**Note:** Version bump only for package amplify-category-api-dynamodb-simulator - -## [2.4.12](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-dynamodb-simulator@2.4.11...amplify-category-api-dynamodb-simulator@2.4.12) (2023-07-21) - -**Note:** Version bump only for package amplify-category-api-dynamodb-simulator - -## [2.4.11](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-dynamodb-simulator@2.4.10...amplify-category-api-dynamodb-simulator@2.4.11) (2023-07-17) - -**Note:** Version bump only for package amplify-category-api-dynamodb-simulator - -## [2.4.10](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-dynamodb-simulator@2.4.9...amplify-category-api-dynamodb-simulator@2.4.10) (2023-05-17) - -**Note:** Version bump only for package amplify-category-api-dynamodb-simulator - -## [2.4.9](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-dynamodb-simulator@2.4.8...amplify-category-api-dynamodb-simulator@2.4.9) (2023-04-25) - -**Note:** Version bump only for package amplify-category-api-dynamodb-simulator - -## [2.4.8](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-dynamodb-simulator@2.4.7...amplify-category-api-dynamodb-simulator@2.4.8) (2023-03-30) - -**Note:** Version bump only for package amplify-category-api-dynamodb-simulator - -## [2.4.7](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-dynamodb-simulator@2.4.6...amplify-category-api-dynamodb-simulator@2.4.7) (2023-03-15) - -**Note:** Version bump only for package amplify-category-api-dynamodb-simulator - -## [2.4.6](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-dynamodb-simulator@2.4.5...amplify-category-api-dynamodb-simulator@2.4.6) (2023-03-01) - -**Note:** Version bump only for package amplify-category-api-dynamodb-simulator - -## [2.4.5](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-dynamodb-simulator@2.4.4...amplify-category-api-dynamodb-simulator@2.4.5) (2023-02-27) - -### Bug Fixes - -- **test:** update cli dependencies to use the cli rc packages ([#1294](https://github.com/aws-amplify/amplify-category-api/issues/1294)) ([7b13884](https://github.com/aws-amplify/amplify-category-api/commit/7b138841bf2c26fa16465ef263af0de7ce5a4122)) - -## [2.4.4](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-dynamodb-simulator@2.4.3...amplify-category-api-dynamodb-simulator@2.4.4) (2023-01-12) - -**Note:** Version bump only for package amplify-category-api-dynamodb-simulator - -## [2.4.3](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-dynamodb-simulator@2.4.2...amplify-category-api-dynamodb-simulator@2.4.3) (2022-09-14) - -**Note:** Version bump only for package amplify-category-api-dynamodb-simulator - -## [2.4.2](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-dynamodb-simulator@2.4.1...amplify-category-api-dynamodb-simulator@2.4.2) (2022-07-20) - -**Note:** Version bump only for package amplify-category-api-dynamodb-simulator - -## [2.4.1](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-dynamodb-simulator@2.4.0...amplify-category-api-dynamodb-simulator@2.4.1) (2022-06-13) - -**Note:** Version bump only for package amplify-category-api-dynamodb-simulator - -# 2.4.0 (2022-06-10) - -### Bug Fixes - -- **amplify-dynamodb-simulator:** detect errors logged to stderr ([#6769](https://github.com/aws-amplify/amplify-category-api/issues/6769)) ([72b7c0a](https://github.com/aws-amplify/amplify-category-api/commit/72b7c0aa4a78e3e1b40b3a3c3c6d5f87bca79005)) -- **amplify-dynamodb-simulator:** update simulator to work in docker ([#2061](https://github.com/aws-amplify/amplify-category-api/issues/2061)) ([90a423c](https://github.com/aws-amplify/amplify-category-api/commit/90a423cc1ecaff3dc8ebb9b5e526e1256d36d835)), closes [#2037](https://github.com/aws-amplify/amplify-category-api/issues/2037) -- removed unsupported portfinder ([#10269](https://github.com/aws-amplify/amplify-category-api/issues/10269)) ([33d8a8f](https://github.com/aws-amplify/amplify-category-api/commit/33d8a8ffeebbb9f05f9dbcd8afc6b0629bcf3819)) -- use correct version of amplify-cli-core ([#5661](https://github.com/aws-amplify/amplify-category-api/issues/5661)) ([c8c2e1a](https://github.com/aws-amplify/amplify-category-api/commit/c8c2e1a9242e2096484f194b9e1944bf34840c51)) - -### Features - -- add support for SMS Sandbox ([#7436](https://github.com/aws-amplify/amplify-category-api/issues/7436)) ([cdcb626](https://github.com/aws-amplify/amplify-category-api/commit/cdcb6260c11bbedef5b056fdcd730612d8bb3230)) -- **amplify-category-api:** rename private packages to scope them down ([e131d06](https://github.com/aws-amplify/amplify-category-api/commit/e131d06463745d448a699e0e75eedd040c167d9d)) -- **amplify-category-api:** update descriptions to properly publish ([f685bbe](https://github.com/aws-amplify/amplify-category-api/commit/f685bbe52fd2d364e34c0ecb45c8a903555de3fe)) -- **amplify-category-api:** update dynamodb simulator version ([95f7c86](https://github.com/aws-amplify/amplify-category-api/commit/95f7c86d647d2bf10b6cbfa066c41bce9d2635fc)) -- **amplify-category-function:** refactor to support runtime and template plugins ([#3517](https://github.com/aws-amplify/amplify-category-api/issues/3517)) ([607ae21](https://github.com/aws-amplify/amplify-category-api/commit/607ae21287941805f44ea8a9b78dd12d16d71f85)) -- **amplify-util-mock:** add mock config for JAVA_OPTS ([#3503](https://github.com/aws-amplify/amplify-category-api/issues/3503)) ([24d8085](https://github.com/aws-amplify/amplify-category-api/commit/24d8085325d435284b9c49a43592e61891fd72bc)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-category-api/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-category-api/commit/0fd0dd5102177766c454c8715fa5acac32385048)) -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-category-api/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-category-api/commit/372e5346ee1f27a2e9bee25fbbdcb19417f5230f)) -- pre-deploy pull, new login mechanism and pkg cli updates ([#5941](https://github.com/aws-amplify/amplify-category-api/issues/5941)) ([7274251](https://github.com/aws-amplify/amplify-category-api/commit/7274251faadc1035acce5f44699b172e10e2e67d)) -- update post-install to copy executable assets to .amplify ([#5595](https://github.com/aws-amplify/amplify-category-api/issues/5595)) ([53a23a0](https://github.com/aws-amplify/amplify-category-api/commit/53a23a07cbb9e09566c1f0f577ba2b7488bc2eae)) - -## [2.2.32](https://github.com/aws-amplify/amplify-category-api/compare/amplify-dynamodb-simulator@2.2.31...amplify-dynamodb-simulator@2.2.32) (2022-06-10) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.31](https://github.com/aws-amplify/amplify-category-api/compare/amplify-dynamodb-simulator@2.2.28...amplify-dynamodb-simulator@2.2.31) (2022-06-07) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.30](https://github.com/aws-amplify/amplify-category-api/compare/amplify-dynamodb-simulator@2.2.28...amplify-dynamodb-simulator@2.2.30) (2022-05-31) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.29](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.28...amplify-dynamodb-simulator@2.2.29) (2022-05-02) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.28](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.27...amplify-dynamodb-simulator@2.2.28) (2022-04-29) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.27](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.26...amplify-dynamodb-simulator@2.2.27) (2022-04-27) - -### Bug Fixes - -- removed unsupported portfinder ([#10269](https://github.com/aws-amplify/amplify-cli/issues/10269)) ([33d8a8f](https://github.com/aws-amplify/amplify-cli/commit/33d8a8ffeebbb9f05f9dbcd8afc6b0629bcf3819)) - -## [2.2.26](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.25...amplify-dynamodb-simulator@2.2.26) (2022-04-11) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.25](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.24...amplify-dynamodb-simulator@2.2.25) (2022-04-07) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.24](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.23...amplify-dynamodb-simulator@2.2.24) (2022-03-23) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.23](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.22...amplify-dynamodb-simulator@2.2.23) (2022-03-14) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.22](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.21...amplify-dynamodb-simulator@2.2.22) (2022-03-07) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.21](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.20...amplify-dynamodb-simulator@2.2.21) (2022-02-25) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.20](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.19...amplify-dynamodb-simulator@2.2.20) (2022-02-15) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.19](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.15...amplify-dynamodb-simulator@2.2.19) (2022-02-10) - -## 7.6.19 (2022-02-08) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.15](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.14...amplify-dynamodb-simulator@2.2.15) (2022-02-03) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.14](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.13...amplify-dynamodb-simulator@2.2.14) (2022-01-27) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.13](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.12...amplify-dynamodb-simulator@2.2.13) (2022-01-23) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.12](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.10...amplify-dynamodb-simulator@2.2.12) (2022-01-10) - -## 7.6.7 (2022-01-10) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.10](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.9...amplify-dynamodb-simulator@2.2.10) (2021-12-21) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.9](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.8...amplify-dynamodb-simulator@2.2.9) (2021-12-17) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.8](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.7...amplify-dynamodb-simulator@2.2.8) (2021-12-02) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.6...amplify-dynamodb-simulator@2.2.7) (2021-12-01) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.5...amplify-dynamodb-simulator@2.2.6) (2021-11-26) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.4...amplify-dynamodb-simulator@2.2.5) (2021-11-23) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.3...amplify-dynamodb-simulator@2.2.4) (2021-11-21) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.2...amplify-dynamodb-simulator@2.2.3) (2021-11-20) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@2.2.1...amplify-dynamodb-simulator@2.2.2) (2021-11-17) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [2.2.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.16...amplify-dynamodb-simulator@2.2.1) (2021-11-15) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -# [2.0.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.16...amplify-dynamodb-simulator@2.0.0) (2021-11-13) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.19.16](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.15...amplify-dynamodb-simulator@1.19.16) (2021-11-11) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.19.15](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.14...amplify-dynamodb-simulator@1.19.15) (2021-10-10) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.19.14](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.13...amplify-dynamodb-simulator@1.19.14) (2021-10-06) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.19.13](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.12...amplify-dynamodb-simulator@1.19.13) (2021-09-27) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.19.12](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.11...amplify-dynamodb-simulator@1.19.12) (2021-09-18) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.19.11](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.10...amplify-dynamodb-simulator@1.19.11) (2021-09-14) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.19.10](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.9...amplify-dynamodb-simulator@1.19.10) (2021-09-09) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.19.9](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.8...amplify-dynamodb-simulator@1.19.9) (2021-09-02) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.19.8](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.7...amplify-dynamodb-simulator@1.19.8) (2021-08-24) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.19.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.6...amplify-dynamodb-simulator@1.19.7) (2021-08-06) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.19.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.5...amplify-dynamodb-simulator@1.19.6) (2021-07-30) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.19.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.4...amplify-dynamodb-simulator@1.19.5) (2021-07-27) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.19.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.3...amplify-dynamodb-simulator@1.19.4) (2021-07-16) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.19.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.2...amplify-dynamodb-simulator@1.19.3) (2021-06-30) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.19.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.1...amplify-dynamodb-simulator@1.19.2) (2021-06-24) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.19.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.19.0...amplify-dynamodb-simulator@1.19.1) (2021-06-15) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -# [1.19.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.18.9...amplify-dynamodb-simulator@1.19.0) (2021-06-02) - -# 4.52.0 (2021-06-01) - -### Features - -- add support for SMS Sandbox ([#7436](https://github.com/aws-amplify/amplify-cli/issues/7436)) ([cdcb626](https://github.com/aws-amplify/amplify-cli/commit/cdcb6260c11bbedef5b056fdcd730612d8bb3230)) - -## [1.18.9](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.18.8...amplify-dynamodb-simulator@1.18.9) (2021-05-26) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.18.8](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.18.7...amplify-dynamodb-simulator@1.18.8) (2021-05-18) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.18.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.18.6...amplify-dynamodb-simulator@1.18.7) (2021-05-14) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.18.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.18.4...amplify-dynamodb-simulator@1.18.6) (2021-05-03) - -## 4.50.1 (2021-05-03) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.18.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.18.4...amplify-dynamodb-simulator@1.18.5) (2021-05-03) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.18.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.18.3...amplify-dynamodb-simulator@1.18.4) (2021-04-27) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.18.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.18.2...amplify-dynamodb-simulator@1.18.3) (2021-04-19) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.18.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.18.1...amplify-dynamodb-simulator@1.18.2) (2021-04-14) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.18.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.17.13...amplify-dynamodb-simulator@1.18.1) (2021-04-09) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.17.13](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.17.12...amplify-dynamodb-simulator@1.17.13) (2021-03-11) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.17.12](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.17.11...amplify-dynamodb-simulator@1.17.12) (2021-03-05) - -### Bug Fixes - -- **amplify-dynamodb-simulator:** detect errors logged to stderr ([#6769](https://github.com/aws-amplify/amplify-cli/issues/6769)) ([72b7c0a](https://github.com/aws-amplify/amplify-cli/commit/72b7c0aa4a78e3e1b40b3a3c3c6d5f87bca79005)) - -## [1.17.11](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.17.10...amplify-dynamodb-simulator@1.17.11) (2021-02-26) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.17.10](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.17.9...amplify-dynamodb-simulator@1.17.10) (2021-02-24) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.17.9](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.17.8...amplify-dynamodb-simulator@1.17.9) (2021-02-17) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.17.8](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.17.7...amplify-dynamodb-simulator@1.17.8) (2021-02-11) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.17.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.17.6...amplify-dynamodb-simulator@1.17.7) (2021-02-10) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.17.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.17.5...amplify-dynamodb-simulator@1.17.6) (2021-01-08) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.17.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.17.4...amplify-dynamodb-simulator@1.17.5) (2020-12-31) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.17.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.17.3...amplify-dynamodb-simulator@1.17.4) (2020-12-21) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.17.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.17.2...amplify-dynamodb-simulator@1.17.3) (2020-12-16) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.17.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.17.1...amplify-dynamodb-simulator@1.17.2) (2020-12-11) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.17.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.17.0...amplify-dynamodb-simulator@1.17.1) (2020-12-07) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -# [1.17.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.16.2...amplify-dynamodb-simulator@1.17.0) (2020-11-30) - -### Features - -- pre-deploy pull, new login mechanism and pkg cli updates ([#5941](https://github.com/aws-amplify/amplify-cli/issues/5941)) ([7274251](https://github.com/aws-amplify/amplify-cli/commit/7274251faadc1035acce5f44699b172e10e2e67d)) - -## [1.16.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.16.1...amplify-dynamodb-simulator@1.16.2) (2020-11-27) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.16.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.15.2...amplify-dynamodb-simulator@1.16.1) (2020-11-22) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -# 1.16.0 (2020-11-22) - -### Bug Fixes - -- use correct version of amplify-cli-core ([#5661](https://github.com/aws-amplify/amplify-cli/issues/5661)) ([c8c2e1a](https://github.com/aws-amplify/amplify-cli/commit/c8c2e1a9242e2096484f194b9e1944bf34840c51)) -- **amplify-dynamodb-simulator:** update simulator to work in docker ([#2061](https://github.com/aws-amplify/amplify-cli/issues/2061)) ([90a423c](https://github.com/aws-amplify/amplify-cli/commit/90a423cc1ecaff3dc8ebb9b5e526e1256d36d835)), closes [#2037](https://github.com/aws-amplify/amplify-cli/issues/2037) - -### Features - -- update post-install to copy executable assets to .amplify ([#5595](https://github.com/aws-amplify/amplify-cli/issues/5595)) ([53a23a0](https://github.com/aws-amplify/amplify-cli/commit/53a23a07cbb9e09566c1f0f577ba2b7488bc2eae)) -- **amplify-category-function:** refactor to support runtime and template plugins ([#3517](https://github.com/aws-amplify/amplify-cli/issues/3517)) ([607ae21](https://github.com/aws-amplify/amplify-cli/commit/607ae21287941805f44ea8a9b78dd12d16d71f85)) -- **amplify-util-mock:** add mock config for JAVA_OPTS ([#3503](https://github.com/aws-amplify/amplify-cli/issues/3503)) ([24d8085](https://github.com/aws-amplify/amplify-cli/commit/24d8085325d435284b9c49a43592e61891fd72bc)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e5346ee1f27a2e9bee25fbbdcb19417f5230f)) - -## [1.15.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.15.2...amplify-dynamodb-simulator@1.15.5) (2020-11-20) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.15.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.15.2...amplify-dynamodb-simulator@1.15.4) (2020-11-20) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.15.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.15.2...amplify-dynamodb-simulator@1.15.3) (2020-11-19) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.15.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.15.1...amplify-dynamodb-simulator@1.15.2) (2020-11-08) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.15.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.15.0...amplify-dynamodb-simulator@1.15.1) (2020-10-27) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -# [1.15.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.14.3...amplify-dynamodb-simulator@1.15.0) (2020-10-22) - -### Bug Fixes - -- use correct version of amplify-cli-core ([#5661](https://github.com/aws-amplify/amplify-cli/issues/5661)) ([c8c2e1a](https://github.com/aws-amplify/amplify-cli/commit/c8c2e1a9242e2096484f194b9e1944bf34840c51)) - -### Features - -- update post-install to copy executable assets to .amplify ([#5595](https://github.com/aws-amplify/amplify-cli/issues/5595)) ([53a23a0](https://github.com/aws-amplify/amplify-cli/commit/53a23a07cbb9e09566c1f0f577ba2b7488bc2eae)) - -## [1.14.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.14.2...amplify-dynamodb-simulator@1.14.3) (2020-10-07) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.14.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.14.0...amplify-dynamodb-simulator@1.14.2) (2020-07-29) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.14.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.14.0...amplify-dynamodb-simulator@1.14.1) (2020-07-23) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -# [1.14.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.13.3...amplify-dynamodb-simulator@1.14.0) (2020-03-22) - -### Features - -- **amplify-category-function:** refactor to support runtime and template plugins ([#3517](https://github.com/aws-amplify/amplify-cli/issues/3517)) ([607ae21](https://github.com/aws-amplify/amplify-cli/commit/607ae21287941805f44ea8a9b78dd12d16d71f85)) -- **amplify-util-mock:** add mock config for JAVA_OPTS ([#3503](https://github.com/aws-amplify/amplify-cli/issues/3503)) ([24d8085](https://github.com/aws-amplify/amplify-cli/commit/24d8085325d435284b9c49a43592e61891fd72bc)) - -## [1.13.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.13.2...amplify-dynamodb-simulator@1.13.3) (2020-02-13) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.13.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.13.1...amplify-dynamodb-simulator@1.13.2) (2020-02-07) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -## [1.13.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@1.13.0...amplify-dynamodb-simulator@1.13.1) (2020-01-24) - -**Note:** Version bump only for package amplify-dynamodb-simulator - -# [1.13.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@0.23.0...amplify-dynamodb-simulator@1.13.0) (2020-01-23) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [1.12.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@0.23.0...amplify-dynamodb-simulator@1.12.0) (2020-01-09) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [1.11.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@0.23.0...amplify-dynamodb-simulator@1.11.0) (2019-12-31) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [1.10.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@0.23.0...amplify-dynamodb-simulator@1.10.0) (2019-12-28) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [1.9.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@0.23.0...amplify-dynamodb-simulator@1.9.0) (2019-12-26) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [1.8.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@0.23.0...amplify-dynamodb-simulator@1.8.0) (2019-12-25) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [1.7.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@0.23.0...amplify-dynamodb-simulator@1.7.0) (2019-12-20) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [1.6.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@0.23.0...amplify-dynamodb-simulator@1.6.0) (2019-12-10) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [1.4.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@0.23.0...amplify-dynamodb-simulator@1.4.0) (2019-12-03) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [1.3.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@0.23.0...amplify-dynamodb-simulator@1.3.0) (2019-12-01) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [1.2.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@0.23.0...amplify-dynamodb-simulator@1.2.0) (2019-11-27) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [1.1.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-dynamodb-simulator@0.23.0...amplify-dynamodb-simulator@1.1.0) (2019-11-27) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# 0.5.0 (2019-08-30) - -### Bug Fixes - -- **amplify-dynamodb-simulator:** update simulator to work in docker ([#2061](https://github.com/aws-amplify/amplify-cli/issues/2061)) ([90a423c](https://github.com/aws-amplify/amplify-cli/commit/90a423c)), closes [#2037](https://github.com/aws-amplify/amplify-cli/issues/2037) - -### Features - -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e534)) - -# 0.4.0 (2019-08-28) - -### Bug Fixes - -- **amplify-dynamodb-simulator:** update simulator to work in docker ([#2061](https://github.com/aws-amplify/amplify-cli/issues/2061)) ([90a423c](https://github.com/aws-amplify/amplify-cli/commit/90a423c)), closes [#2037](https://github.com/aws-amplify/amplify-cli/issues/2037) - -### Features - -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e534)) - -# 0.3.0 (2019-08-13) - -### Features - -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e534)) - -# 0.2.0 (2019-08-07) - -### Features - -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e534)) diff --git a/packages/amplify-dynamodb-simulator/README.md b/packages/amplify-dynamodb-simulator/README.md deleted file mode 100644 index 28e436e48b..0000000000 --- a/packages/amplify-dynamodb-simulator/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# Amplify DynamoDB Simulator - -This package contains wrapper logic to download and use the dynamodb emulator. - -This package automatically (on install) downloads the latest dynamodb emulator. - -Much of the logic in this package is around retrying to start the server. This can be an issue when using jest and there is contention when binding a port. - -## Usage - -```js -const emulator = require('amplify-dynamodb-simulator'); - -async function main() { - // start the emulator - const emu = await emulator.launch({ - /* options */ - }); - // by default we launch the emulator on some open port in the ephemeral range in the 'inMemory' mode. - - // get the dynamodb client (aws-sdk) - const dynamodb = emulator.getClient(emu); -} -``` - -### Options: - -#### `port` - -Port to bind the emulator to. If omitted will bind to the first available port in the ephemeral range. - -default: `null` - -#### `sharedDb` - -If to use a single database file to use in the emulator. Should typically be left on. - -default: `true` - -#### `dbPath` - -Where to launch the database. Will automatically create this directory if missing. - -deafult: `null` - -#### `startTimeout` - -Maximum amount of time to wait for the dynamodb emulator to start listening on it's chosen port. - -default: `5000` diff --git a/packages/amplify-dynamodb-simulator/__test__/index.test.js b/packages/amplify-dynamodb-simulator/__test__/index.test.js deleted file mode 100644 index 46667c2342..0000000000 --- a/packages/amplify-dynamodb-simulator/__test__/index.test.js +++ /dev/null @@ -1,103 +0,0 @@ -const fs = require('fs-extra'); -const ddbSimulator = require('..'); - -jest.mock('@aws-amplify/amplify-cli-core', () => ({ - pathManager: { - getAmplifyPackageLibDirPath: jest.fn().mockReturnValue('./'), - }, -})); - -describe('emulator operations', () => { - const dbPath = `${__dirname}/dynamodb-data/${process.pid}`; - // taken from dynamodb examples. - const dbParams = { - AttributeDefinitions: [ - { - AttributeName: 'Artist', - AttributeType: 'S', - }, - { - AttributeName: 'SongTitle', - AttributeType: 'S', - }, - ], - KeySchema: [ - { - AttributeName: 'Artist', - KeyType: 'HASH', - }, - { - AttributeName: 'SongTitle', - KeyType: 'RANGE', - }, - ], - ProvisionedThroughput: { - ReadCapacityUnits: 5, - WriteCapacityUnits: 5, - }, - }; - - const ensureNoDbPath = () => { - if (fs.existsSync(dbPath)) { - try { - fs.removeSync(dbPath); - } catch (err) { - console.log(err); - } - } - }; - - let emulators; - beforeEach(async () => { - ensureNoDbPath(); - emulators = []; - jest.setTimeout(40 * 1000); - }); - - afterEach(async () => { - await Promise.all(emulators.map((emu) => emu.terminate())); - ensureNoDbPath(); - }); - - it('should support in memory operations', async () => { - const emu = await ddbSimulator.launch(); - emulators.push(emu); - const dynamo = ddbSimulator.getClient(emu); - - const tables = await dynamo.listTables().promise(); - expect(tables).toEqual({ TableNames: [] }); - }); - - it('should preserve state between restarts with dbPath', async () => { - const emuOne = await ddbSimulator.launch({ dbPath }); - emulators.push(emuOne); - const dynamoOne = ddbSimulator.getClient(emuOne); - await dynamoOne - .createTable({ - TableName: 'foo', - ...dbParams, - }) - .promise(); - await emuOne.terminate(); - emulators = []; - const emuTwo = await ddbSimulator.launch({ dbPath }); - emulators.push(emuTwo); - const dynamoTwo = await ddbSimulator.getClient(emuTwo); - const t = await dynamoTwo.listTables().promise(); - expect(t).toEqual({ - TableNames: ['foo'], - }); - }); - - it('should start on specific port', async () => { - const port = await require('get-port')(); - const emu = await ddbSimulator.launch({ port }); - emulators.push(emu); - expect(emu.port).toBe(port); - }); - - it('reports on invalid dbPath values', async () => { - expect.assertions(1); - await expect(ddbSimulator.launch({ dbPath: 'dynamodb-data' })).rejects.toThrow('invalid directory for database creation'); - }); -}); diff --git a/packages/amplify-dynamodb-simulator/index.js b/packages/amplify-dynamodb-simulator/index.js deleted file mode 100644 index 8ebd56a3e4..0000000000 --- a/packages/amplify-dynamodb-simulator/index.js +++ /dev/null @@ -1,248 +0,0 @@ -const path = require('path'); -const { fromEvent } = require('promise-toolbox'); -const fs = require('fs-extra'); -const waitPort = require('wait-port'); -const detectPort = require('detect-port'); -const log = require('logdown')('dynamodb-emulator'); -const execa = require('execa'); -const { pathManager } = require('@aws-amplify/amplify-cli-core'); - -// random port I chose in the ephemeral range -const basePort = 62224; - -const defaultOptions = { - inMemory: true, - sharedDb: false, - dbPath: null, - startTimeout: 20 * 1000, -}; - -const packageName = 'amplify-dynamodb-simulator'; -const relativeEmulatorPath = 'emulator'; - -const emulatorPath = path.join(pathManager.getAmplifyPackageLibDirPath(packageName), relativeEmulatorPath); -const retryInterval = 20; -const maxRetries = 5; - -class Emulator { - constructor(proc, opts) { - this.proc = proc; - this.opts = opts; - return this; - } - - get pid() { - return this.proc.pid; - } - - get port() { - return this.opts.port; - } - - get url() { - return `http://localhost:${this.port}/`; - } - - terminate() { - // already exited - if (this.proc.exitCode != null) { - return this.proc.exitCode; - } - this.proc.kill(); - return fromEvent(this.proc, 'exit'); - } -} - -const wait = (ms) => { - let timeoutHandle; - const promise = new Promise((accept) => { - timeoutHandle = setTimeout(accept, ms); - }); - - return { - promise, - cancel: () => { - clearTimeout(timeoutHandle); - }, - }; -}; - -async function which(bin) { - return new Promise((accept, reject) => { - require('which')(bin, (err, value) => { - if (err) return reject(err); - return accept(value); - }); - }); -} - -function buildArgs(options) { - const args = []; - - if (options.javaOpts) { - args.push(...options.javaOpts.split(' ')); - } - - args.push(...['-Djava.library.path=./DynamoDBLocal_lib', '-jar', 'DynamoDBLocal.jar', '-port', options.port]); - if (options.dbPath) { - args.push('-dbPath'); - args.push(options.dbPath); - } - - // dbPath overrides in memory - if (options.inMemory && !options.dbPath) { - args.push('-inMemory'); - } - if (options.sharedDb) { - args.push('-sharedDb'); - } - return args; -} - -async function launch(givenOptions = {}, retry = 0, startTime = Date.now()) { - log.info('launching', { retry, givenOptions }); - // launch will retry but ensure it will not retry indefinitely. - if (retry >= maxRetries) { - throw new Error('max retries hit for starting dynamodb emulator'); - } - - if (givenOptions.inMemory && givenOptions.dbPath) { - throw new Error('inMemory and dbPath are mutually exclusive options'); - } - let { port } = givenOptions; - if (!port) { - port = await detectPort(basePort); - log.info('found open port', { port }); - } else { - const freePort = await detectPort(port); - if (freePort !== port) { - throw new Error(`Port ${port} is not free. Please use a different port`); - } - } - const opts = { ...defaultOptions, ...givenOptions, port }; - - if (opts.dbPath) { - fs.ensureDirSync(opts.dbPath); - } - - const java = await which('java'); - const args = buildArgs(opts); - log.info('Spawning Emulator:', { args, cwd: emulatorPath }); - - const proc = execa(java, args, { - cwd: emulatorPath, - }); - - function startingTimeout() { - log.error('Failed to start within timeout'); - // ensure process is halted. - proc.kill(); - const err = new Error('start has timed out!'); - err.code = 'timeout'; - throw err; - } - - // define this now so we can use it later to remove a listener. - let prematureExit; - let waiter; - // This is a fairly complex set of logic to retry starting - // the emulator if it fails to start. We need this logic due - // to possible race conditions between when we find an open - // port and bind to it. This situation is particularly common - // in jest where each test file is running in it's own process - // each competing for the open port. - try { - waiter = wait(opts.startTimeout); - await Promise.race([ - new Promise((accept, reject) => { - let stdout = ''; - let stderr = ''; - - function readStderrBuffer(buffer) { - stderr += buffer.toString(); - - // Check stderr for any known errors. - if (/^Invalid directory for database creation.$/.test(stderr)) { - proc.stdout.removeListener('data', readStdoutBuffer); - proc.stderr.removeListener('data', readStderrBuffer); - const err = new Error('invalid directory for database creation'); - err.code = 'bad_config'; - reject(err); - } - } - - function readStdoutBuffer(buffer) { - stdout += buffer.toString(); - - if (stdout.indexOf(opts.port) !== -1) { - proc.stdout.removeListener('data', readStdoutBuffer); - proc.stderr.removeListener('data', readStderrBuffer); - log.info('Emulator has started but need to verify socket'); - accept( - waitPort({ - host: 'localhost', - port, - output: 'silent', - }), - ); - } - } - proc.stderr.on('data', readStderrBuffer); - proc.stdout.on('data', readStdoutBuffer); - }), - waiter.promise.then(startingTimeout), - new Promise((accept, reject) => { - prematureExit = () => { - log.error('Dynamo DB Simulator has prematurely exited... need to retry'); - const err = new Error('premature exit'); - err.code = 'premature'; - proc.removeListener('exit', prematureExit); - reject(err); - }; - proc.on('exit', prematureExit); - }), - ]); - - log.info('Successfully launched emulator on', { - port, - time: Date.now() - startTime, - }); - } catch (err) { - // retry starting the emulator after a small "back off" time - // if we have a premature exit or the port is bound in a different process. - if (err.code === 'premature' || err.code === 'port_taken') { - if (givenOptions.port) { - throw new Error(`${givenOptions.port} is bound and unavailable`); - } - log.info('Queue retry in', retryInterval); - return wait(retryInterval).promise.then(() => launch(givenOptions, retry + 1, startTime)); - } - throw err; - } finally { - waiter && waiter.cancel(); - if (typeof prematureExit === 'function') { - proc.removeListener('exit', prematureExit); - } - } - - return new Emulator(proc, opts); -} - -function getClient(emu, options = {}) { - const { DynamoDB } = require('aws-sdk'); - return new DynamoDB({ - endpoint: emu.url, - region: 'us-fake-1', - accessKeyId: 'fake', - secretAccessKey: 'fake', - ...options, - }); -} - -const getPackageAssetPaths = async () => [relativeEmulatorPath]; - -module.exports = { - launch, - getClient, - getPackageAssetPaths, -}; diff --git a/packages/amplify-dynamodb-simulator/package.json b/packages/amplify-dynamodb-simulator/package.json deleted file mode 100644 index 42453ad4cf..0000000000 --- a/packages/amplify-dynamodb-simulator/package.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "amplify-category-api-dynamodb-simulator", - "version": "2.4.17", - "description": "DynamoDB emulator NodeJS wrapper", - "private": "true", - "repository": { - "type": "git", - "url": "https://github.com/aws-amplify/amplify-category-api.git", - "directory": "packages/amplify-dynamodb-simulator" - }, - "author": "Amazon Web Services", - "license": "Apache-2.0", - "main": "index.js", - "keywords": [ - "graphql", - "appsync", - "aws" - ], - "scripts": { - "build": "node ./scripts/update-ddb-simulator.js", - "clean": "rimraf emulator", - "test": "jest" - }, - "dependencies": { - "aws-sdk": "^2.1113.0", - "detect-port": "^1.3.0", - "execa": "^5.1.1", - "fs-extra": "^8.1.0", - "logdown": "^3.3.0", - "promise-toolbox": "^0.20.0", - "wait-port": "^0.2.7", - "which": "^2.0.2" - }, - "peerDependencies": { - "@aws-amplify/amplify-cli-core": "^4.3.9" - }, - "devDependencies": { - "get-port": "^5.1.1", - "gunzip-maybe": "^1.4.2", - "hash.js": "^1.1.7", - "node-fetch": "^2.6.7", - "rimraf": "^3.0.2", - "tar": "^6.1.11" - }, - "jest": { - "testEnvironment": "node", - "collectCoverage": true, - "collectCoverageFrom": [ - "src/**/*.ts" - ], - "coveragePathIgnorePatterns": [ - "/__tests__/" - ] - } -} diff --git a/packages/amplify-dynamodb-simulator/scripts/update-ddb-simulator.js b/packages/amplify-dynamodb-simulator/scripts/update-ddb-simulator.js deleted file mode 100644 index 7efbe2eb5d..0000000000 --- a/packages/amplify-dynamodb-simulator/scripts/update-ddb-simulator.js +++ /dev/null @@ -1,44 +0,0 @@ -const { join } = require('path'); -const { pipeline, Readable } = require('stream'); -const { promisify } = require('util'); -const { ensureDir, readFile, writeFile } = require('fs-extra'); -const gunzip = require('gunzip-maybe'); -const hash = require('hash.js'); -const nodefetch = require('node-fetch'); -const tar = require('tar'); - -const main = async () => { - const ddbSimulatorUrl = 'https://s3.us-west-2.amazonaws.com/dynamodb-local/dynamodb_local_latest.tar.gz'; - const sha256Url = `${ddbSimulatorUrl}.sha256`; - - const emulatorDirPath = join(__dirname, '..', 'emulator'); - const sha256FilePath = join(emulatorDirPath, 'sha256'); - - const latestSha256 = (await nodefetch(sha256Url).then((res) => res.text())).split(' ')[0]; - await ensureDir(emulatorDirPath); - - let previousSha256; - try { - previousSha256 = (await readFile(sha256FilePath)).toString(); - } catch { - previousSha256 = undefined; - } - - if (previousSha256 !== latestSha256) { - const ddbSimulatorGunZippedTarball = await nodefetch(ddbSimulatorUrl).then((res) => res.buffer()); - const computedSha256 = hash.sha256().update(ddbSimulatorGunZippedTarball).digest('hex'); - if (latestSha256 !== computedSha256) { - throw Error(`SHA256 DID NOT MATCH CHECKSUM. EXPECTED: ${latestSha256} RECEIVED: ${computedSha256}`); - } - - // Create a Readable stream from the in-memory tar.gz, unzip it, and extract it to /emulator - await promisify(pipeline)(Readable.from(ddbSimulatorGunZippedTarball), gunzip(), tar.extract({ C: 'emulator' })); - - return writeFile(sha256FilePath, latestSha256); - } -}; - -main().catch((err) => { - console.log(err); - process.exit(1); -}); diff --git a/packages/amplify-graphql-transformer-migrator/.npmignore b/packages/amplify-graphql-transformer-migrator/.npmignore deleted file mode 100644 index 3ee5d55b0b..0000000000 --- a/packages/amplify-graphql-transformer-migrator/.npmignore +++ /dev/null @@ -1,5 +0,0 @@ -**/__mocks__/** -**/__tests__/** -src -tsconfig.json -tsconfig.tsbuildinfo diff --git a/packages/amplify-graphql-transformer-migrator/API.md b/packages/amplify-graphql-transformer-migrator/API.md deleted file mode 100644 index 0a71581fd1..0000000000 --- a/packages/amplify-graphql-transformer-migrator/API.md +++ /dev/null @@ -1,23 +0,0 @@ -## API Report File for "@aws-amplify/graphql-transformer-migrator" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -// @public (undocumented) -export function attemptV2TransformerMigration(resourceDir: string, apiName: string, featureFlags: { - transformerVersion: number; - improvePluralization: boolean; -}, envName?: string): Promise; - -// @public (undocumented) -export function revertV2Migration(resourceDir: string, envName: string): Promise; - -// Warning: (ae-forgotten-export) The symbol "SchemaDocument" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export function runMigration(schemas: SchemaDocument[], authMode: string): Promise; - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/amplify-graphql-transformer-migrator/CHANGELOG.md b/packages/amplify-graphql-transformer-migrator/CHANGELOG.md deleted file mode 100644 index 5c2091164c..0000000000 --- a/packages/amplify-graphql-transformer-migrator/CHANGELOG.md +++ /dev/null @@ -1,509 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [2.2.27](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.26...@aws-amplify/graphql-transformer-migrator@2.2.27) (2024-07-15) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.26](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.25...@aws-amplify/graphql-transformer-migrator@2.2.26) (2024-07-02) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.25](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.24...@aws-amplify/graphql-transformer-migrator@2.2.25) (2024-07-01) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.24](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.23...@aws-amplify/graphql-transformer-migrator@2.2.24) (2024-06-25) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.23](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.22...@aws-amplify/graphql-transformer-migrator@2.2.23) (2024-05-10) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.22](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.21...@aws-amplify/graphql-transformer-migrator@2.2.22) (2024-04-26) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.21](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.20...@aws-amplify/graphql-transformer-migrator@2.2.21) (2024-04-11) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.20](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.19...@aws-amplify/graphql-transformer-migrator@2.2.20) (2024-03-28) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.19](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.18...@aws-amplify/graphql-transformer-migrator@2.2.19) (2024-02-28) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.18](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.17...@aws-amplify/graphql-transformer-migrator@2.2.18) (2024-02-05) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.17](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.16...@aws-amplify/graphql-transformer-migrator@2.2.17) (2024-01-30) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.16](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.15...@aws-amplify/graphql-transformer-migrator@2.2.16) (2024-01-22) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.15](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.14...@aws-amplify/graphql-transformer-migrator@2.2.15) (2023-12-18) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.14](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.13...@aws-amplify/graphql-transformer-migrator@2.2.14) (2023-12-14) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.13](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.12...@aws-amplify/graphql-transformer-migrator@2.2.13) (2023-12-06) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.12](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.11...@aws-amplify/graphql-transformer-migrator@2.2.12) (2023-11-22) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.11](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.10...@aws-amplify/graphql-transformer-migrator@2.2.11) (2023-11-18) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.10](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.9...@aws-amplify/graphql-transformer-migrator@2.2.10) (2023-11-16) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.9](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.8...@aws-amplify/graphql-transformer-migrator@2.2.9) (2023-11-15) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.8](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.7...@aws-amplify/graphql-transformer-migrator@2.2.8) (2023-11-02) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.7](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.6...@aws-amplify/graphql-transformer-migrator@2.2.7) (2023-10-21) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.6](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.5...@aws-amplify/graphql-transformer-migrator@2.2.6) (2023-10-12) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.5](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.4...@aws-amplify/graphql-transformer-migrator@2.2.5) (2023-10-05) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.4](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.3...@aws-amplify/graphql-transformer-migrator@2.2.4) (2023-10-02) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.2...@aws-amplify/graphql-transformer-migrator@2.2.3) (2023-09-20) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.1...@aws-amplify/graphql-transformer-migrator@2.2.2) (2023-08-30) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.2.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.2.0...@aws-amplify/graphql-transformer-migrator@2.2.1) (2023-08-28) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -# [2.2.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.13...@aws-amplify/graphql-transformer-migrator@2.2.0) (2023-08-09) - -### Features - -- bump major version of transformer packages ([2458c84](https://github.com/aws-amplify/amplify-category-api/commit/2458c8426da5772aa669d37e11f99ee9c6c5ac2e)) - -## [2.1.13](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.12...@aws-amplify/graphql-transformer-migrator@2.1.13) (2023-07-21) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.1.12](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.11...@aws-amplify/graphql-transformer-migrator@2.1.12) (2023-07-17) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.1.11](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.10...@aws-amplify/graphql-transformer-migrator@2.1.11) (2023-07-07) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.1.10](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.9...@aws-amplify/graphql-transformer-migrator@2.1.10) (2023-07-07) - -### Bug Fixes - -- trigger republish of dependencies that failed in https://app.circleci.com/pipelines/github/aws-amplify/amplify-category-api/7981/workflows/e7366f04-6f0a-4ee4-9cc2-1772089e8005/jobs/163571 ([f2c7151](https://github.com/aws-amplify/amplify-category-api/commit/f2c7151005e4a9fd29d91ac1af1f3e482a06a5cc)) - -## [2.1.9](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.8...@aws-amplify/graphql-transformer-migrator@2.1.9) (2023-07-07) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.1.8](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.7...@aws-amplify/graphql-transformer-migrator@2.1.8) (2023-06-29) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.1.7](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.6...@aws-amplify/graphql-transformer-migrator@2.1.7) (2023-06-20) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.1.6](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.5...@aws-amplify/graphql-transformer-migrator@2.1.6) (2023-06-05) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.1.5](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.4...@aws-amplify/graphql-transformer-migrator@2.1.5) (2023-05-23) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.1.4](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.3...@aws-amplify/graphql-transformer-migrator@2.1.4) (2023-05-17) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.1.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.2...@aws-amplify/graphql-transformer-migrator@2.1.3) (2023-04-25) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.1.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.1...@aws-amplify/graphql-transformer-migrator@2.1.2) (2023-03-30) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [2.1.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.0...@aws-amplify/graphql-transformer-migrator@2.1.1) (2023-03-15) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -# [2.1.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.17...@aws-amplify/graphql-transformer-migrator@2.1.0) (2023-03-01) - -### Features - -- migrate auth, maps-to, relational, default value transformer to CDK v2 ([#875](https://github.com/aws-amplify/amplify-category-api/issues/875)) ([5c714a9](https://github.com/aws-amplify/amplify-category-api/commit/5c714a9a8436be343477574cb5523c23c96c9338)) - -# [2.1.0-beta.6](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.16...@aws-amplify/graphql-transformer-migrator@2.1.0-beta.6) (2023-02-21) - -### Features - -- migrate auth, maps-to, relational, default value transformer to CDK v2 ([#875](https://github.com/aws-amplify/amplify-category-api/issues/875)) ([5c714a9](https://github.com/aws-amplify/amplify-category-api/commit/5c714a9a8436be343477574cb5523c23c96c9338)) - -# [2.1.0-beta.5](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.16...@aws-amplify/graphql-transformer-migrator@2.1.0-beta.5) (2023-02-15) - -### Features - -- migrate auth, maps-to, relational, default value transformer to CDK v2 ([#875](https://github.com/aws-amplify/amplify-category-api/issues/875)) ([5c714a9](https://github.com/aws-amplify/amplify-category-api/commit/5c714a9a8436be343477574cb5523c23c96c9338)) - -# [2.1.0-beta.4](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.15...@aws-amplify/graphql-transformer-migrator@2.1.0-beta.4) (2023-02-03) - -### Features - -- migrate auth, maps-to, relational, default value transformer to CDK v2 ([#875](https://github.com/aws-amplify/amplify-category-api/issues/875)) ([5c714a9](https://github.com/aws-amplify/amplify-category-api/commit/5c714a9a8436be343477574cb5523c23c96c9338)) - -# [2.1.0-beta.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.12...@aws-amplify/graphql-transformer-migrator@2.1.0-beta.3) (2022-12-27) - -### Features - -- migrate auth, maps-to, relational, default value transformer to CDK v2 ([#875](https://github.com/aws-amplify/amplify-category-api/issues/875)) ([5c714a9](https://github.com/aws-amplify/amplify-category-api/commit/5c714a9a8436be343477574cb5523c23c96c9338)) - -# [2.1.0-beta.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.0-beta.0...@aws-amplify/graphql-transformer-migrator@2.1.0-beta.2) (2022-12-12) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -# [2.1.0-beta.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.0-beta.0...@aws-amplify/graphql-transformer-migrator@2.1.0-beta.1) (2022-11-30) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -# [2.1.0-beta.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.0-cdkv2.3...@aws-amplify/graphql-transformer-migrator@2.1.0-beta.0) (2022-11-18) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -# [2.1.0-cdkv2.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.10...@aws-amplify/graphql-transformer-migrator@2.1.0-cdkv2.3) (2022-11-15) - -### Features - -- migrate auth, maps-to, relational, default value transformer to CDK v2 ([#875](https://github.com/aws-amplify/amplify-category-api/issues/875)) ([5c714a9](https://github.com/aws-amplify/amplify-category-api/commit/5c714a9a8436be343477574cb5523c23c96c9338)) - -# [2.1.0-cdkv2.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.0-cdkv2.1...@aws-amplify/graphql-transformer-migrator@2.1.0-cdkv2.2) (2022-11-03) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -# [2.1.0-cdkv2.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@2.1.0-cdkv2.0...@aws-amplify/graphql-transformer-migrator@2.1.0-cdkv2.1) (2022-10-24) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -# [2.1.0-cdkv2.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.7...@aws-amplify/graphql-transformer-migrator@2.1.0-cdkv2.0) (2022-10-24) - -### Features - -- migrate auth, maps-to, relational, default value transformer to CDK v2 ([#875](https://github.com/aws-amplify/amplify-category-api/issues/875)) ([5c714a9](https://github.com/aws-amplify/amplify-category-api/commit/5c714a9a8436be343477574cb5523c23c96c9338)) - -## [1.4.17](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.16...@aws-amplify/graphql-transformer-migrator@1.4.17) (2023-02-27) - -### Bug Fixes - -- **test:** update cli dependencies to use the cli rc packages ([#1294](https://github.com/aws-amplify/amplify-category-api/issues/1294)) ([7b13884](https://github.com/aws-amplify/amplify-category-api/commit/7b138841bf2c26fa16465ef263af0de7ce5a4122)) - -## [1.4.16](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.15...@aws-amplify/graphql-transformer-migrator@1.4.16) (2023-02-10) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.4.15](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.14...@aws-amplify/graphql-transformer-migrator@1.4.15) (2023-01-26) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.4.14](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.13...@aws-amplify/graphql-transformer-migrator@1.4.14) (2023-01-12) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.4.13](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.12...@aws-amplify/graphql-transformer-migrator@1.4.13) (2023-01-12) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.4.12](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.11...@aws-amplify/graphql-transformer-migrator@1.4.12) (2022-12-09) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.4.11](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.10...@aws-amplify/graphql-transformer-migrator@1.4.11) (2022-12-03) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.4.10](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.9...@aws-amplify/graphql-transformer-migrator@1.4.10) (2022-11-08) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.4.9](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.8...@aws-amplify/graphql-transformer-migrator@1.4.9) (2022-10-26) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.4.8](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.7...@aws-amplify/graphql-transformer-migrator@1.4.8) (2022-10-24) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.4.7](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.6...@aws-amplify/graphql-transformer-migrator@1.4.7) (2022-09-14) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.4.6](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.5...@aws-amplify/graphql-transformer-migrator@1.4.6) (2022-08-23) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.4.5](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.4...@aws-amplify/graphql-transformer-migrator@1.4.5) (2022-08-16) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.4.4](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.2...@aws-amplify/graphql-transformer-migrator@1.4.4) (2022-07-20) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.4.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.2...@aws-amplify/graphql-transformer-migrator@1.4.3) (2022-07-14) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.4.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.1...@aws-amplify/graphql-transformer-migrator@1.4.2) (2022-07-01) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.4.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.4.0...@aws-amplify/graphql-transformer-migrator@1.4.1) (2022-06-23) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -# [1.4.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.3.0...@aws-amplify/graphql-transformer-migrator@1.4.0) (2022-06-13) - -### Features - -- **graphql-auth-transformer:** [@auth](https://github.com/auth) allow more granular access rights for read ([#23](https://github.com/aws-amplify/amplify-category-api/issues/23)) ([041fb80](https://github.com/aws-amplify/amplify-category-api/commit/041fb808e380d04f2c4913cef1037c3d87e98d22)) - -# [1.3.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.2.40...@aws-amplify/graphql-transformer-migrator@1.3.0) (2022-06-10) - -### Features - -- **amplify-category-api:** update descriptions to properly publish ([f685bbe](https://github.com/aws-amplify/amplify-category-api/commit/f685bbe52fd2d364e34c0ecb45c8a903555de3fe)) - -## [1.2.40](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.2.39...@aws-amplify/graphql-transformer-migrator@1.2.40) (2022-06-10) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.39](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.2.36...@aws-amplify/graphql-transformer-migrator@1.2.39) (2022-06-07) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.38](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-transformer-migrator@1.2.36...@aws-amplify/graphql-transformer-migrator@1.2.38) (2022-05-31) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.37](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.36...@aws-amplify/graphql-transformer-migrator@1.2.37) (2022-05-02) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.36](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.35...@aws-amplify/graphql-transformer-migrator@1.2.36) (2022-04-29) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.35](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.34...@aws-amplify/graphql-transformer-migrator@1.2.35) (2022-04-27) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.34](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.33...@aws-amplify/graphql-transformer-migrator@1.2.34) (2022-04-18) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.33](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.32...@aws-amplify/graphql-transformer-migrator@1.2.33) (2022-04-11) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.32](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.31...@aws-amplify/graphql-transformer-migrator@1.2.32) (2022-04-07) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.31](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.30...@aws-amplify/graphql-transformer-migrator@1.2.31) (2022-03-23) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.30](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.29...@aws-amplify/graphql-transformer-migrator@1.2.30) (2022-03-14) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.29](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.28...@aws-amplify/graphql-transformer-migrator@1.2.29) (2022-03-07) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.28](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.27...@aws-amplify/graphql-transformer-migrator@1.2.28) (2022-02-25) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.27](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.26...@aws-amplify/graphql-transformer-migrator@1.2.27) (2022-02-15) - -### Bug Fixes - -- graphql-transformer-migrator add modelgen flag after v2 migrate ([#9565](https://github.com/aws-amplify/amplify-cli/issues/9565)) ([9bff4ae](https://github.com/aws-amplify/amplify-cli/commit/9bff4ae13b44f2649b4f66df4485ca768416d707)) - -## [1.2.26](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.22...@aws-amplify/graphql-transformer-migrator@1.2.26) (2022-02-10) - -## 7.6.19 (2022-02-08) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.22](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.21...@aws-amplify/graphql-transformer-migrator@1.2.22) (2022-02-03) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.21](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.20...@aws-amplify/graphql-transformer-migrator@1.2.21) (2022-01-31) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.20](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.19...@aws-amplify/graphql-transformer-migrator@1.2.20) (2022-01-27) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.19](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.18...@aws-amplify/graphql-transformer-migrator@1.2.19) (2022-01-23) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.18](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.17...@aws-amplify/graphql-transformer-migrator@1.2.18) (2022-01-20) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.17](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.16...@aws-amplify/graphql-transformer-migrator@1.2.17) (2022-01-13) - -### Bug Fixes - -- clean up missing and unused GraphQL v2 dependencies ([#9486](https://github.com/aws-amplify/amplify-cli/issues/9486)) ([a6ca44e](https://github.com/aws-amplify/amplify-cli/commit/a6ca44e6ea0ec0a70b648e399fc3e849ccc2a7c9)) - -## [1.2.16](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.14...@aws-amplify/graphql-transformer-migrator@1.2.16) (2022-01-10) - -## 7.6.7 (2022-01-10) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.14](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.13...@aws-amplify/graphql-transformer-migrator@1.2.14) (2021-12-21) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.13](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.12...@aws-amplify/graphql-transformer-migrator@1.2.13) (2021-12-17) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.12](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.11...@aws-amplify/graphql-transformer-migrator@1.2.12) (2021-12-03) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.11](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.10...@aws-amplify/graphql-transformer-migrator@1.2.11) (2021-12-02) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.10](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.9...@aws-amplify/graphql-transformer-migrator@1.2.10) (2021-12-01) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.9](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.8...@aws-amplify/graphql-transformer-migrator@1.2.9) (2021-11-26) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.8](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.7...@aws-amplify/graphql-transformer-migrator@1.2.8) (2021-11-24) - -### Bug Fixes - -- add migration warning when [@searchable](https://github.com/searchable) is used ([#9059](https://github.com/aws-amplify/amplify-cli/issues/9059)) ([15e1a55](https://github.com/aws-amplify/amplify-cli/commit/15e1a559677e995efdadfe8d1cbfa3a35dc6b279)) - -## [1.2.7](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.6...@aws-amplify/graphql-transformer-migrator@1.2.7) (2021-11-23) - -### Bug Fixes - -- api migrate command when rest apis are added ([#9054](https://github.com/aws-amplify/amplify-cli/issues/9054)) ([df4d7c6](https://github.com/aws-amplify/amplify-cli/commit/df4d7c66b2d8c337b1fc9fb3d426a99932c0e6dd)) -- bail out of gql migration if [@auth](https://github.com/auth) uses queries/mutations ([#9004](https://github.com/aws-amplify/amplify-cli/issues/9004)) ([57a0bd5](https://github.com/aws-amplify/amplify-cli/commit/57a0bd5a64cbb6f889d5bc6d8ee7451ba3638de5)) -- **graphql-transformer-migrator:** fixed belongs to type relationshio check ([#9003](https://github.com/aws-amplify/amplify-cli/issues/9003)) ([9ecb90c](https://github.com/aws-amplify/amplify-cli/commit/9ecb90c3be958cfbf81ba4c4be7e9ce6e6c0ee2e)) - -## [1.2.6](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.5...@aws-amplify/graphql-transformer-migrator@1.2.6) (2021-11-21) - -### Bug Fixes - -- fixed snapshot ([#8987](https://github.com/aws-amplify/amplify-cli/issues/8987)) ([5e889bf](https://github.com/aws-amplify/amplify-cli/commit/5e889bf9df50597aec2168a9d72e0cda076f3d6c)) - -## [1.2.5](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.4...@aws-amplify/graphql-transformer-migrator@1.2.5) (2021-11-20) - -## 7.4.4 (2021-11-20) - -### Bug Fixes - -- **amplify-category-api:** update snapshot ([#8978](https://github.com/aws-amplify/amplify-cli/issues/8978)) ([c4ed3be](https://github.com/aws-amplify/amplify-cli/commit/c4ed3befed36bb97347a19f1decb42dba71aee92)) -- **graphql-transformer-migrator:** fix protected rules that come from groups ([#8972](https://github.com/aws-amplify/amplify-cli/issues/8972)) ([dc567e9](https://github.com/aws-amplify/amplify-cli/commit/dc567e9afe8aab901a000162148099d1553d37c5)) - -## [1.2.4](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.2...@aws-amplify/graphql-transformer-migrator@1.2.4) (2021-11-19) - -### Bug Fixes - -- **graphql-transformer-migrator:** migrate owners and group based auth correctly ([#8940](https://github.com/aws-amplify/amplify-cli/issues/8940)) ([f276a42](https://github.com/aws-amplify/amplify-cli/commit/f276a42a0e8eafe1dbeaed0d2af4b915b132ae31)) - -## 7.4.2 (2021-11-19) - -### Bug Fixes - -- **graphql-transformer-migrator:** disables field level hoisting of auth ([#8946](https://github.com/aws-amplify/amplify-cli/issues/8946)) ([a21118a](https://github.com/aws-amplify/amplify-cli/commit/a21118ae7f45dd4938b6731d1e388f2c6107e7d7)) -- passthrough group auth rule config ([#8928](https://github.com/aws-amplify/amplify-cli/issues/8928)) ([eb6a0f5](https://github.com/aws-amplify/amplify-cli/commit/eb6a0f52c3b499db8070dad7796a8ea4de099e09)) - -## [1.2.3](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.2...@aws-amplify/graphql-transformer-migrator@1.2.3) (2021-11-19) - -### Bug Fixes - -- passthrough group auth rule config ([#8928](https://github.com/aws-amplify/amplify-cli/issues/8928)) ([eb6a0f5](https://github.com/aws-amplify/amplify-cli/commit/eb6a0f52c3b499db8070dad7796a8ea4de099e09)) - -## [1.2.2](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@1.2.1...@aws-amplify/graphql-transformer-migrator@1.2.2) (2021-11-17) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -## [1.2.1](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@0.2.0...@aws-amplify/graphql-transformer-migrator@1.2.1) (2021-11-15) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -# [1.0.0](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-transformer-migrator@0.2.0...@aws-amplify/graphql-transformer-migrator@1.0.0) (2021-11-13) - -**Note:** Version bump only for package @aws-amplify/graphql-transformer-migrator - -# 0.2.0 (2021-11-11) - -### Bug Fixes - -- don't migrate AppSync auth related directives ([#8661](https://github.com/aws-amplify/amplify-cli/issues/8661)) ([903c7bf](https://github.com/aws-amplify/amplify-cli/commit/903c7bf85e0e96275267a28700364436dcaaa712)) -- exit migration if improvePluralization is false ([#8670](https://github.com/aws-amplify/amplify-cli/issues/8670)) ([cead88d](https://github.com/aws-amplify/amplify-cli/commit/cead88db132a50827ade3e08fc01ca68b5f11282)) -- gracefully exit on deprecated [@connection](https://github.com/connection) parameterization ([#8640](https://github.com/aws-amplify/amplify-cli/issues/8640)) ([4045f3a](https://github.com/aws-amplify/amplify-cli/commit/4045f3ab4aa1f3782c5a4ff5d7a1af7bd48fd00d)) -- schema migrator utility as separate command ([#8720](https://github.com/aws-amplify/amplify-cli/issues/8720)) ([46e1ee6](https://github.com/aws-amplify/amplify-cli/commit/46e1ee6a49dd86bb682b182a37626bc3f2f966ea)) - -### Features - -- Activate graphql migrator behind feature flag ([5a76b3a](https://github.com/aws-amplify/amplify-cli/commit/5a76b3a320012c09d2ff2f424283fafba74fa74d)) diff --git a/packages/amplify-graphql-transformer-migrator/package.json b/packages/amplify-graphql-transformer-migrator/package.json deleted file mode 100644 index c3010fbbe2..0000000000 --- a/packages/amplify-graphql-transformer-migrator/package.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "name": "@aws-amplify/graphql-transformer-migrator", - "version": "2.2.27", - "description": "A tool for converting schemas from Amplify's V1 transformer to the V2 transformer schema", - "repository": { - "type": "git", - "url": "https://github.com/aws-amplify/amplify-category-api.git", - "directory": "packages/amplify-graphql-transformer-migrator" - }, - "author": "Amazon Web Services", - "license": "Apache-2.0", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "keywords": [ - "graphql", - "aws", - "amplify" - ], - "publishConfig": { - "access": "public" - }, - "scripts": { - "build": "tsc", - "watch": "tsc -w", - "clean": "rimraf ./lib tsconfig.tsbuildinfo", - "test": "jest", - "extract-api": "ts-node ../../scripts/extract-api.ts" - }, - "dependencies": { - "@aws-amplify/graphql-transformer-core": "2.9.3", - "fs-extra": "^8.1.0", - "glob": "^10.3.0", - "graphql": "^15.5.0", - "graphql-transformer-common": "4.31.1", - "lodash": "^4.17.21" - }, - "peerDependencies": { - "@aws-amplify/amplify-cli-core": "^4.3.9", - "@aws-amplify/amplify-environment-parameters": "^1.9.14", - "@aws-amplify/amplify-prompts": "^2.8.6" - }, - "devDependencies": { - "@types/fs-extra": "^8.0.1", - "@types/node": "^12.12.6" - }, - "jest": { - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, - "testURL": "http://localhost", - "testRegex": "(src/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], - "collectCoverage": true, - "coverageProvider": "v8", - "coverageThreshold": { - "global": { - "branches": 82, - "functions": 90, - "lines": 90 - } - }, - "coverageReporters": [ - "clover", - "text" - ], - "testEnvironment": "../../FixJestEnvironment.js", - "collectCoverageFrom": [ - "src/**/*.ts" - ], - "coveragePathIgnorePatterns": [ - "/__tests__/" - ] - } -} diff --git a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/__snapshots__/auth-tests.ts.snap b/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/__snapshots__/auth-tests.ts.snap deleted file mode 100644 index 3bc04f4bbc..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/__snapshots__/auth-tests.ts.snap +++ /dev/null @@ -1,308 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Schema migration tests for @auth default auth is user pools group based auth migrate dynamic user pool 1`] = ` -"type Todo @model @auth(rules: [{allow: groups, groupsField: \\"groups\\"}]) { - id: ID! - title: String - groups: [String] -} - -type Task @model @auth(rules: [{allow: groups, groupsField: \\"group\\"}]) { - id: ID! - title: String - group: String -} -" -`; - -exports[`Schema migration tests for @auth default auth is user pools group based auth migrates @auth with groups correctly 1`] = ` -"type Todo @model @auth(rules: [{allow: groups, groups: [\\"Admins\\"]}]) { - id: ID! - name: String! - description: String -} -" -`; - -exports[`Schema migration tests for @auth default auth is user pools group based auth with explicit operations migrates create + delete -> private read + update 1`] = ` -"type Todo @model @auth(rules: [{allow: groups, groups: [\\"Admins\\"]}, {allow: private, operations: [read, update]}]) { - id: ID! - rating: Int - title: String -} -" -`; - -exports[`Schema migration tests for @auth default auth is user pools migrates @auth private with user pools correctly 1`] = ` -"type Todo @model @auth(rules: [{allow: private}]) { - id: ID! - name: String! - description: String -} -" -`; - -exports[`Schema migration tests for @auth default auth is user pools multi-use for user groups migrates non specified @auth correctly 1`] = ` -"type Todo @model @auth(rules: [{allow: owner}]) { - id: ID! - name: String! - description: String -} - -type Task @model @auth(rules: [{allow: private}]) { - id: ID! - title: String! - owner: String -} -" -`; - -exports[`Schema migration tests for @auth default auth is user pools owner based auth array of owners migrates owner array fields correctly 1`] = ` -"type Todo @model @auth(rules: [{allow: owner, ownerField: \\"editors\\"}]) { - id: ID! - rating: Int - title: String - editors: [String] -} -" -`; - -exports[`Schema migration tests for @auth default auth is user pools owner based auth custom identity claim migrates identity claim 1`] = ` -"type Todo @model @auth(rules: [{allow: owner, identityClaim: \\"sub\\"}]) { - id: ID! - title: String! - owner: String -} -" -`; - -exports[`Schema migration tests for @auth default auth is user pools owner based auth explicit operations adds private delete rule 1`] = ` -"type Todo @model @auth(rules: [{allow: owner}, {allow: private, operations: [read, update]}]) { - id: ID! - rating: Int - title: String -} -" -`; - -exports[`Schema migration tests for @auth default auth is user pools owner based auth explicit operations adds private update rule 1`] = ` -"type Todo @model @auth(rules: [{allow: owner}, {allow: private, operations: [update]}]) { - id: ID! - rating: Int - title: String -} -" -`; - -exports[`Schema migration tests for @auth default auth is user pools owner based auth explicit owner field migrates @auth with custom owner field correctly 1`] = ` -"type Todo @model @auth(rules: [{allow: owner, ownerField: \\"editor\\"}]) { - id: ID! - name: String! - description: String - editor: String -} -" -`; - -exports[`Schema migration tests for @auth default auth is user pools owner based auth explicit owner field migrates @auth with owners correctly 1`] = ` -"type Todo @model @auth(rules: [{allow: owner}]) { - id: ID! - name: String! - description: String - owner: String -} -" -`; - -exports[`Schema migration tests for @auth default auth is user pools owner based auth implicit owner field migrates @auth with owners and field correctly 1`] = ` -"type Todo @model @auth(rules: [{allow: owner, ownerField: \\"editor\\"}]) { - id: ID! - name: String! - description: String -} -" -`; - -exports[`Schema migration tests for @auth default auth is user pools owner based auth implicit owner field migrates @auth with owners correctly 1`] = ` -"type Todo @model @auth(rules: [{allow: owner}]) { - id: ID! - name: String! - description: String -} -" -`; - -exports[`Schema migration tests for @auth default auth is user pools owner based auth multiple owner rules retains the owner operations 1`] = ` -"type Todo @model @auth(rules: [{allow: owner, operations: [create]}, {allow: owner, ownerField: \\"admin\\", operations: [read, update, delete]}]) { - id: ID! - title: String! - admin: String - owner: String -} -" -`; - -exports[`Schema migration tests for @auth default auth uses api key migrates @auth to public @auth with api key 1`] = ` -"type Todo @model @auth(rules: [{allow: public}]) { - id: ID! - name: String! - description: String -} -" -`; - -exports[`Schema migration tests for @auth default auth uses api key migrates default api_key auth correctly 1`] = ` -"type Todo @model @auth(rules: [{allow: public}]) { - id: ID! - name: String! - description: String -} - -type Comment @model @auth(rules: [{allow: private}]) { - id: ID! - content: String! -} -" -`; - -exports[`Schema migration tests for @auth default auth uses api key migrates no @auth to public @auth with api key 1`] = ` -"type Todo @model @auth(rules: [{allow: public}]) { - id: ID! - name: String! - description: String -} -" -`; - -exports[`Schema migration tests for @auth default auth uses iam migrates @auth private with iam correctly 1`] = ` -"type Todo @model @auth(rules: [{allow: private, provider: iam}]) { - id: ID! - name: String! - description: String -} -" -`; - -exports[`Schema migration tests for @auth default auth uses iam migrates @auth public with iam correctly 1`] = ` -"type Todo @model @auth(rules: [{allow: public, provider: iam}]) { - id: ID! - name: String! - description: String -} -" -`; - -exports[`Schema migration tests for @auth default auth uses oidc migrates oidc w/ groups as expected 1`] = ` -"type Todo @model @auth(rules: [{allow: groups, provider: oidc, groups: [\\"Admins\\"], groupClaim: \\"https://myapp.com/claims/groups\\"}]) { - id: ID! - title: String! -} -" -`; - -exports[`Schema migration tests for @auth default auth uses oidc migrates over oidc w/ owner and operations 1`] = ` -"type Todo @model @auth(rules: [{allow: owner, provider: oidc, identityClaim: \\"sub\\"}, {allow: private, provider: oidc, operations: [create, read, delete]}]) { - id: ID! - title: String! -} -" -`; - -exports[`Schema migration tests for @auth default auth uses oidc ports over oidc w/ owner as expected 1`] = ` -"type Todo @model @auth(rules: [{allow: owner, provider: oidc, identityClaim: \\"sub\\"}]) { - id: ID! - title: String! -} -" -`; - -exports[`Schema migration tests for @auth field level auth keeps type auth and field auth 1`] = ` -"type Todo @model @auth(rules: [{allow: public}]) { - id: ID! - title: String! - ssn: String @auth(rules: [{allow: owner}]) -} -" -`; - -exports[`Schema migration tests for @auth field level auth migrates field level correctly with explicit operations 1`] = ` -"type FieldLevelPost @model @auth(rules: [{allow: public}]) { - id: ID! - title: String! - username: String - ssn: String @auth(rules: [{allow: owner, ownerField: \\"username\\", identityClaim: \\"username\\", operations: [create, read, update, delete]}]) -} -" -`; - -exports[`Schema migration tests for @auth field level auth multi field auth migrates correctly 1`] = ` -"type Employee @model(subscriptions: {level: public}) @auth(rules: [{allow: owner, ownerField: \\"e_mail\\", operations: [update]}, {allow: groups, groups: [\\"Admin\\"], operations: [create, update, delete]}, {allow: private, operations: [read]}]) { - e_mail: String @auth(rules: [{allow: groups, groups: [\\"Admin\\"], operations: [create, update, read]}, {allow: owner, ownerField: \\"e_mail\\", operations: [read]}]) - salary: Int @auth(rules: [{allow: groups, groups: [\\"Admin\\"], operations: [create, update, read]}, {allow: owner, ownerField: \\"e_mail\\", operations: [read]}]) - notes: String @auth(rules: [{allow: owner, ownerField: \\"e_mail\\", operations: [delete]}]) -} -" -`; - -exports[`Schema migration tests for @auth group auth ports over owner and group based rule 1`] = ` -"type Todo @model @auth(rules: [{allow: owner}, {allow: groups, groups: [\\"Admins\\"]}]) { - id: ID! - name: String! - description: String - owner: String -} -" -`; - -exports[`Schema migration tests for @auth group auth retains dynamic groups in auth rules 1`] = ` -"type Todo @model @auth(rules: [{allow: groups, groups: [\\"Admins\\"]}]) { - id: ID! - rating: Int - title: String -} -" -`; - -exports[`Schema migration tests for @auth group auth retains groupClaims in auth rules 1`] = ` -"type Todo @model @auth(rules: [{allow: groups, provider: oidc, groups: [\\"Admins\\"], groupClaim: \\"https://myapp.com/claims/groups\\"}]) { - id: ID! - title: String! -} -" -`; - -exports[`Schema migration tests for @auth relational auth migrates as expected 1`] = ` -"type Post @model @auth(rules: [{allow: owner}]) { - id: ID! - title: String! - author: User @belongsTo(fields: [\\"owner\\"]) - owner: ID! @index(name: \\"byOwner\\", sortKeyFields: [\\"id\\"]) -} - -type User @model @auth(rules: [{allow: owner}]) { - id: ID! - posts: [Post] @hasMany(indexName: \\"byOwner\\", fields: [\\"id\\"]) -} - -type FieldProtected @model @auth(rules: [{allow: private}]) { - id: ID! - owner: String - ownerOnly: String @auth(rules: [{allow: owner}]) -} - -type OpenTopLevel @model @auth(rules: [{allow: private}]) { - id: ID! - name: String - owner: String - protected: [ConnectionProtected] @hasMany(indexName: \\"byTopLevel\\", fields: [\\"id\\"]) -} - -type ConnectionProtected @model(queries: null) @auth(rules: [{allow: owner}]) { - id: ID! - name: String - owner: String - topLevelID: ID! @index(name: \\"byTopLevel\\", sortKeyFields: [\\"id\\"]) - topLevel: OpenTopLevel @belongsTo(fields: [\\"topLevelID\\"]) -} -" -`; diff --git a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/__snapshots__/migrate-tests.ts.snap b/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/__snapshots__/migrate-tests.ts.snap deleted file mode 100644 index cf10c22014..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/__snapshots__/migrate-tests.ts.snap +++ /dev/null @@ -1,332 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Schema migration tests @connection belongs to relationship 1`] = ` -"type Post @model @auth(rules: [{allow: public}]) { - id: ID! - title: String! - comments: [Comment] @hasMany(indexName: \\"byPost\\", fields: [\\"id\\"]) -} - -type Comment @model @auth(rules: [{allow: public}]) { - id: ID! - postID: ID! @index(name: \\"byPost\\", sortKeyFields: [\\"content\\"]) - content: String! - post: Post @belongsTo(fields: [\\"postID\\"]) -} -" -`; - -exports[`Schema migration tests @connection has many relationship 1`] = ` -"type Post @model @auth(rules: [{allow: public}]) { - id: ID! - title: String! - comments: [Comment] @hasMany(indexName: \\"byPost\\", fields: [\\"id\\"]) -} - -type Comment @model @auth(rules: [{allow: public}]) { - id: ID! - postID: ID! @index(name: \\"byPost\\", sortKeyFields: [\\"content\\"]) - content: String! -} -" -`; - -exports[`Schema migration tests @connection has many relationship with limit 1`] = ` -"type Post @model @auth(rules: [{allow: public}]) { - id: ID! - title: String! - comments: [Comment] @hasMany(limit: 50) -} - -type Comment @model @auth(rules: [{allow: public}]) { - id: ID! - content: String! -} -" -`; - -exports[`Schema migration tests @connection has one relationship with fields 1`] = ` -"type Project @model @auth(rules: [{allow: public}]) { - id: ID! - name: String - teamID: ID! - team: Team @hasOne(fields: [\\"teamID\\"]) -} - -type Team @model @auth(rules: [{allow: public}]) { - id: ID! - name: String! -} -" -`; - -exports[`Schema migration tests @connection has one relationship with no fields 1`] = ` -"type Project @model @auth(rules: [{allow: public}]) { - id: ID! - name: String - team: Team @hasOne -} - -type Team @model @auth(rules: [{allow: public}]) { - id: ID! - name: String! -} -" -`; - -exports[`Schema migration tests @connection many to many relationship 1`] = ` -"type Post @model @auth(rules: [{allow: public}]) { - id: ID! - title: String! - editors: [PostEditor] @hasMany(indexName: \\"byPost\\", fields: [\\"id\\"]) -} - -type PostEditor @model(queries: null) @auth(rules: [{allow: public}]) { - id: ID! - postID: ID! @index(name: \\"byPost\\", sortKeyFields: [\\"editorID\\"]) - editorID: ID! @index(name: \\"byEditor\\", sortKeyFields: [\\"postID\\"]) - post: Post! @belongsTo(fields: [\\"postID\\"]) - editor: User! @belongsTo(fields: [\\"editorID\\"]) -} - -type User @model @auth(rules: [{allow: public}]) { - id: ID! - username: String! - posts: [PostEditor] @hasMany(indexName: \\"byEditor\\", fields: [\\"id\\"]) -} -" -`; - -exports[`Schema migration tests @function directive is migrated 1`] = ` -"type Query { - echo(msg: String!): Context @function(name: \\"echo\\") - echoEnv(msg: String!): Context @function(name: \\"long-prefix-e2e-test-functions-echo-\${env}-v2\\") - duplicate(msg: String!): Context @function(name: \\"long-prefix-e2e-test-functions-echo-dev-v2\\") - pipeline(msg: String!): String @function(name: \\"echo\\") @function(name: \\"hello\\") - echoRegion(msg: String!): Context @function(name: \\"echo-\${env}\\", region: \\"us-east-1\\") -} - -type Context { - typeName: String - fieldName: String -} -" -`; - -exports[`Schema migration tests @http directive is migrated 1`] = ` -"type Comment @model @auth(rules: [{allow: public}]) { - id: ID! - title: String - simpleGet: CompObj @http(method: GET, url: \\"https://amazon.com/posts/1\\") - simpleGet2: CompObj @http(url: \\"https://amazon.com/posts/2\\") - complexPost(id: Int, title: String!, body: String, userId: Int): CompObj @http(method: POST, url: \\"https://amazon.com/posts\\") - complexPut(id: Int!, title: String, body: String, userId: Int): CompObj @http(method: PUT, url: \\"https://amazon.com/posts/\${env}/:id\\") - deleter: String @http(method: DELETE, url: \\"https://amazon.com/posts/4\\") - complexGet(data: String!, userId: Int!, _limit: Int): [CompObj] @http(url: \\"https://amazon.com:data\\") -} - -type CompObj { - userId: Int - id: Int - title: String - body: String -} -" -`; - -exports[`Schema migration tests @predictions directive is migrated 1`] = ` -"type Query { - translateImageText: String @predictions(actions: [identifyText]) - translateLabels: String @predictions(actions: [identifyLabels]) - translateThis: String @predictions(actions: [translateText]) - speakTranslatedText: String @predictions(actions: [translateText, convertTextToSpeech]) -} -" -`; - -exports[`Schema migration tests @searchable directive is migrated 1`] = ` -"type Book @model @searchable @auth(rules: [{allow: public}]) { - author: String! @primaryKey(sortKeyFields: [\\"name\\"]) - name: String! - genre: String! -} - -type Todo @model @searchable @auth(rules: [{allow: public}]) { - id: ID - name: String! - createdAt: AWSDateTime - description: String -} - -type Comment @model @searchable @auth(rules: [{allow: public}]) { - id: ID! - version: Int! @index(name: \\"commentByVersion\\", sortKeyFields: [\\"id\\"]) - content: String! -} -" -`; - -exports[`Schema migration tests Has One @connection without fields always mapped to has one, even in bidirectional 1`] = ` -"type Coffee @model @auth(rules: [{allow: public}]) { - id: ID! - energy: Energy @hasOne -} - -type Energy @model @auth(rules: [{allow: public}]) { - id: ID! - coffee: Coffee @hasOne -} -" -`; - -exports[`Schema migration tests basic @model type 1`] = ` -"type Todo @model @auth(rules: [{allow: public}]) { - id: ID! - name: String! - description: String -} -" -`; - -exports[`Schema migration tests configure a primary key 1`] = ` -"type Todo @model @auth(rules: [{allow: public}]) { - id: ID! @primaryKey - name: String! - description: String -} -" -`; - -exports[`Schema migration tests configure a secondary index 1`] = ` -"type Todo @model @auth(rules: [{allow: public}]) { - id: ID! - name: String! @index(name: \\"nameIndex\\") - description: String -} -" -`; - -exports[`Schema migration tests configure a secondary index with queryField 1`] = ` -"type Todo @model @auth(rules: [{allow: public}]) { - id: ID! - name: String! - status: String! @index(name: \\"todosByStatus\\", queryField: \\"listTodosByStatus\\") -} -" -`; - -exports[`Schema migration tests customized creation and update timestamp names 1`] = ` -"type Todo @model(timestamps: {createdAt: \\"createdOn\\", updatedAt: \\"updatedOn\\"}) @auth(rules: [{allow: public}]) { - id: ID! - str: String -} -" -`; - -exports[`Schema migration tests explicit creation and update timestamps 1`] = ` -"type Todo @model @auth(rules: [{allow: public}]) { - id: ID! - createdAt: AWSTimestamp - updatedAt: AWSTimestamp -} -" -`; - -exports[`Schema migration tests migrates complex schema from documentation 1`] = ` -"type Order @model @auth(rules: [{allow: public}]) { - id: ID! - customerID: ID! @index(name: \\"byCustomerByStatusByDate\\", sortKeyFields: [\\"status\\", \\"date\\"]) @index(name: \\"byCustomerByDate\\", sortKeyFields: [\\"date\\"]) - accountRepresentativeID: ID! @index(name: \\"byRepresentativebyDate\\", sortKeyFields: [\\"date\\"]) - productID: ID! @index(name: \\"byProduct\\", sortKeyFields: [\\"id\\"]) - status: String! - amount: Int! - date: String! -} - -type Customer @model @auth(rules: [{allow: public}]) { - id: ID! - name: String! - phoneNumber: String - accountRepresentativeID: ID! @index(name: \\"byRepresentative\\", sortKeyFields: [\\"id\\"]) - ordersByDate: [Order] @hasMany(indexName: \\"byCustomerByDate\\", fields: [\\"id\\"]) - ordersByStatusDate: [Order] @hasMany(indexName: \\"byCustomerByStatusByDate\\", fields: [\\"id\\"]) -} - -type Employee @model @auth(rules: [{allow: public}]) { - id: ID! - name: String! @index(name: \\"byName\\", queryField: \\"employeeByName\\", sortKeyFields: [\\"id\\"]) - startDate: String! - phoneNumber: String! - warehouseID: ID! @index(name: \\"byWarehouse\\", sortKeyFields: [\\"id\\"]) - jobTitle: String! @index(name: \\"byTitle\\", queryField: \\"employeesByJobTitle\\", sortKeyFields: [\\"id\\"]) - newHire: String! @index(name: \\"newHire\\", queryField: \\"employeesNewHire\\", sortKeyFields: [\\"id\\"]) @index(name: \\"newHireByStartDate\\", queryField: \\"employeesNewHireByStartDate\\", sortKeyFields: [\\"startDate\\"]) -} - -type Warehouse @model @auth(rules: [{allow: public}]) { - id: ID! - employees: [Employee] @hasMany(indexName: \\"byWarehouse\\", fields: [\\"id\\"]) -} - -type AccountRepresentative @model @auth(rules: [{allow: public}]) { - id: ID! - customers: [Customer] @hasMany(indexName: \\"byRepresentative\\", fields: [\\"id\\"]) - orders: [Order] @hasMany(indexName: \\"byRepresentativebyDate\\", fields: [\\"id\\"]) - orderTotal: Int - salesPeriod: String @index(name: \\"bySalesPeriodByOrderTotal\\", queryField: \\"repsByPeriodAndTotal\\", sortKeyFields: [\\"orderTotal\\"]) -} - -type Inventory @model @auth(rules: [{allow: public}]) { - productID: ID! @primaryKey(sortKeyFields: [\\"warehouseID\\"]) - warehouseID: ID! @index(name: \\"byWarehouseID\\", queryField: \\"itemsByWarehouseID\\") - inventoryAmount: Int! -} - -type Product @model @auth(rules: [{allow: public}]) { - id: ID! - name: String! - orders: [Order] @hasMany(indexName: \\"byProduct\\", fields: [\\"id\\"]) - inventories: [Inventory] @hasMany(fields: [\\"id\\"]) -} -" -`; - -exports[`Schema migration tests multiple @model types 1`] = ` -"type Todo @model @auth(rules: [{allow: public}]) { - id: ID! - name: String! - description: String -} - -type Ope @model @auth(rules: [{allow: public}]) { - foo: ID! - bar: String -} -" -`; - -exports[`Schema migration tests no amplify directives in schema 1`] = ` -"type Todo { - id: ID! - name: String! - description: String -} -" -`; - -exports[`Schema migration tests passes built-in directives through 1`] = ` -"scalar UUID @specifiedBy(url: \\"https://tools.ietf.org/html/rfc4122\\") - -type Todo { - newField: String - oldField: String @deprecated(reason: \\"Use newField.\\") -} -" -`; - -exports[`Schema migration tests renamed queries/mutations/subscriptions 1`] = ` -"type Entity @model(mutations: null, subscriptions: null, queries: {get: \\"getEntity\\"}) @auth(rules: [{allow: public}]) { - id: ID! - str: String -} -" -`; diff --git a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/auth-tests.ts b/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/auth-tests.ts deleted file mode 100644 index 5349c9b4c7..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/auth-tests.ts +++ /dev/null @@ -1,488 +0,0 @@ -import { parse } from 'graphql'; -import { migrateGraphQLSchema } from '../../schema-migrator'; - -function migrateAndValidate(inputSchema: string, defaultAuth: string = 'apiKey'): void { - const docNode = parse(inputSchema); - const migratedSchema = migrateGraphQLSchema(inputSchema, defaultAuth, docNode); - - parse(migratedSchema); - expect(migratedSchema).toMatchSnapshot(); -} - -const API_KEY = 'apiKey'; -const USER_POOLS = 'userPools'; -const IAM = 'iam'; -const OIDC = 'oidc'; - -describe('Schema migration tests for @auth', () => { - describe('default auth uses api key', () => { - it('migrates no @auth to public @auth with api key', () => { - const schema = ` - type Todo @model { - id: ID! - name: String! - description: String - }`; - - migrateAndValidate(schema, API_KEY); - }); - - it('migrates default api_key auth correctly', () => { - const schema = ` - type Todo @model { - id: ID! - name: String! - description: String - } - - type Comment @model @auth(rules: [{ allow: private }]) { - id: ID! - content: String! - }`; - - migrateAndValidate(schema, API_KEY); - }); - - it('migrates @auth to public @auth with api key', () => { - const schema = ` - type Todo @model @auth(rules: [{ allow: public }]) { - id: ID! - name: String! - description: String - }`; - - migrateAndValidate(schema, API_KEY); - }); - }); - - describe('default auth is user pools', () => { - it('migrates @auth private with user pools correctly', () => { - const schema = ` - type Todo @model @auth(rules: [{ allow: private }]) { - id: ID! - name: String! - description: String - }`; - - migrateAndValidate(schema, USER_POOLS); - }); - - describe('owner based auth', () => { - describe('implicit owner field', () => { - it('migrates @auth with owners correctly', () => { - const schema = ` - type Todo @model @auth(rules: [{ allow: owner }]) { - id: ID! - name: String! - description: String - }`; - - migrateAndValidate(schema, USER_POOLS); - }); - - it('migrates @auth with owners and field correctly', () => { - const schema = ` - type Todo @model @auth(rules: [{ allow: owner, ownerField: "editor" }]) { - id: ID! - name: String! - description: String - }`; - - migrateAndValidate(schema, USER_POOLS); - }); - }); - - describe('explicit owner field', () => { - it('migrates @auth with owners correctly', () => { - const schema = ` - type Todo @model @auth(rules: [{ allow: owner }]) { - id: ID! - name: String! - description: String - owner: String - }`; - - migrateAndValidate(schema, USER_POOLS); - }); - - it('migrates @auth with custom owner field correctly', () => { - const schema = ` - type Todo @model @auth(rules: [{ allow: owner, ownerField: "editor" }]) { - id: ID! - name: String! - description: String - editor: String - }`; - - migrateAndValidate(schema, USER_POOLS); - }); - }); - - describe('explicit operations', () => { - it('adds private update rule', () => { - const schema = ` - type Todo - @model - @auth(rules: [{ allow: owner, operations: [create, read, delete] }]) { - id: ID! - rating: Int - title: String - }`; - - migrateAndValidate(schema, USER_POOLS); - }); - - it('adds private delete rule', () => { - const schema = ` - type Todo - @model - @auth(rules: [{ allow: owner, operations: [create, delete] }]) { - id: ID! - rating: Int - title: String - }`; - - migrateAndValidate(schema, USER_POOLS); - }); - }); - - describe('multiple owner rules', () => { - it('retains the owner operations', () => { - const schema = ` - type Todo - @model - @auth(rules: [ - { allow: owner, operations: [create] }, - { allow: owner, ownerField: "admin", operations: [read, update, delete] } - ]) { - id: ID! - title: String! - admin: String - owner: String - }`; - migrateAndValidate(schema, USER_POOLS); - }); - }); - - describe('array of owners', () => { - it('migrates owner array fields correctly', () => { - const schema = ` - type Todo - @model - @auth(rules: [{ allow: owner, ownerField: "editors" }]) { - id: ID! - rating: Int - title: String - editors: [String] - }`; - - migrateAndValidate(schema, USER_POOLS); - }); - }); - - describe('custom identity claim', () => { - it('migrates identity claim', () => { - const schema = ` - type Todo - @model - @auth(rules: [{ allow: owner, identityClaim: "sub" }]) { - id: ID! - title: String! - owner: String - }`; - - migrateAndValidate(schema, USER_POOLS); - }); - }); - }); - - describe('group based auth', () => { - it('migrates @auth with groups correctly', () => { - const schema = ` - type Todo @model @auth(rules: [{ allow: groups, groups: ["Admins"] }]) { - id: ID! - name: String! - description: String - }`; - - migrateAndValidate(schema, USER_POOLS); - }); - - describe('with explicit operations', () => { - it('migrates create + delete -> private read + update', () => { - const schema = ` - type Todo - @model - @auth(rules: [{ allow: groups, groups: ["Admins"], operations: [create, delete] }]) { - id: ID! - rating: Int - title: String - }`; - - migrateAndValidate(schema, USER_POOLS); - }); - }); - - it('migrate dynamic user pool', () => { - const schema = ` - type Todo - @model - @auth(rules: [ - { allow: groups, groupsField: "groups" } - ]) { - id: ID! - title: String - groups: [String] - } - type Task - @model - @auth(rules: [{ allow: groups, groupsField: "group" }]) { - id: ID! - title: String - group: String - }`; - - migrateAndValidate(schema, USER_POOLS); - }); - }); - - describe('multi-use for user groups', () => { - it('migrates non specified @auth correctly', () => { - const schema = ` - type Todo @model @auth(rules: [{ allow: owner }]) { - id: ID! - name: String! - description: String - } - - type Task @model { - id: ID! - title: String! - owner: String - }`; - - migrateAndValidate(schema, USER_POOLS); - }); - }); - }); - - describe('default auth uses iam', () => { - it('migrates @auth public with iam correctly', () => { - const schema = ` - type Todo @model @auth(rules: [{ allow: public, provider: iam }]) { - id: ID! - name: String! - description: String - }`; - - migrateAndValidate(schema, IAM); - }); - - it('migrates @auth private with iam correctly', () => { - const schema = ` - type Todo @model @auth(rules: [{ allow: private, provider: iam }]) { - id: ID! - name: String! - description: String - }`; - - migrateAndValidate(schema, IAM); - }); - }); - - describe('default auth uses oidc', () => { - it('ports over oidc w/ owner as expected', () => { - const schema = ` - type Todo - @model - @auth(rules: [{ allow: owner, provider: oidc, identityClaim: "sub" }]) { - id: ID! - title: String! - }`; - - migrateAndValidate(schema, OIDC); - }); - - it('migrates over oidc w/ owner and operations', () => { - const schema = ` - type Todo - @model - @auth(rules: [{ allow: owner, provider: oidc, identityClaim: "sub", operations: [update] }]) { - id: ID! - title: String! - }`; - - migrateAndValidate(schema, OIDC); - }); - - it('migrates oidc w/ groups as expected', () => { - const schema = ` - type Todo - @model - @auth( - rules: [ - { - allow: groups - provider: oidc - groups: ["Admins"] - groupClaim: "https://myapp.com/claims/groups" - } - ] - ) { - id: ID! - title: String! - }`; - - migrateAndValidate(schema, OIDC); - }); - }); - - describe('group auth', () => { - it('retains dynamic groups in auth rules', () => { - const schema = /* GraphQL */ ` - type Todo @model @auth(rules: [{ allow: groups, groups: ["Admins"] }]) { - id: ID! - rating: Int - title: String - } - `; - - migrateAndValidate(schema); - }); - - it('retains groupClaims in auth rules', () => { - const schema = /* GraphQL */ ` - type Todo - @model - @auth(rules: [{ allow: groups, provider: oidc, groups: ["Admins"], groupClaim: "https://myapp.com/claims/groups" }]) { - id: ID! - title: String! - } - `; - - migrateAndValidate(schema); - }); - - it('ports over owner and group based rule', () => { - const schema = ` - type Todo - @model - @auth (rules: [ - { allow: owner }, - { allow: groups, groups: ["Admins"] } - ]) { - id: ID! - name: String! - description: String - owner: String - }`; - - migrateAndValidate(schema); - }); - }); - - describe('field level auth', () => { - it('keeps type auth and field auth', () => { - const schema = ` - type Todo @model { - id: ID! - title: String! - ssn: String @auth(rules: [{ allow: owner }]) - }`; - - migrateAndValidate(schema, API_KEY); - }); - - it('migrates field level correctly with explicit operations', () => { - const schema = ` - type FieldLevelPost @model { - id: ID! - title: String! - username: String - ssn: String - @auth( - rules: [ - { - allow: owner - ownerField: "username" - identityClaim: "username" - operations: [create, read, update, delete] - } - ] - ) - }`; - - migrateAndValidate(schema, API_KEY); - }); - - describe('multi field auth', () => { - it('migrates correctly', () => { - const schema = ` - type Employee @model ( - subscriptions: { - level: public - } - ) @auth(rules: [ - { allow: owner, ownerField: "e_mail", operations: [update] }, - { allow: groups, groups: ["Admin"], operations: [create, update, delete] } - ]) { - e_mail: String @auth(rules: [ - { allow: groups, groups: ["Admin"], operations: [create, update, read] } - { allow: owner, ownerField: "e_mail", operations: [read] } - ]) - salary: Int @auth(rules: [ - { allow: groups, groups: ["Admin"], operations: [create, update, read] } - { allow: owner, ownerField: "e_mail", operations: [read] } - ]) - notes: String @auth(rules: [{ allow: owner, ownerField: "e_mail", operations: [delete] }]) - }`; - - migrateAndValidate(schema, USER_POOLS); - }); - }); - }); - - describe('relational auth', () => { - it('migrates as expected', () => { - const schema = ` - type Post - @model - @auth(rules: [{ allow: owner }]) - @key(name: "byOwner", fields: ["owner", "id"]) - { - id: ID! - title: String! - author: User @connection(fields: ["owner"]) - owner: ID! - } - type User @model @auth(rules: [{ allow: owner }]) { - id: ID! - posts: [Post] @connection(keyName: "byOwner", fields: ["id"]) - } - type FieldProtected @model { - id: ID! - owner: String - ownerOnly: String @auth(rules: [{ allow: owner }]) - } - type OpenTopLevel @model { - id: ID! - name: String - owner: String - protected: [ConnectionProtected] @connection(keyName: "byTopLevel", fields: ["id"]) - } - type ConnectionProtected - @model(queries: null) - @auth(rules: [{ allow: owner }]) - @key(name: "byTopLevel", fields: ["topLevelID", "id"]) - { - id: ID! - name: String - owner: String - topLevelID: ID! - topLevel: OpenTopLevel @connection(fields: ["topLevelID"]) - }`; - - migrateAndValidate(schema, USER_POOLS); - }); - }); -}); diff --git a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/migrate-tests.ts b/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/migrate-tests.ts deleted file mode 100644 index d0e6448bcd..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/migrate-tests.ts +++ /dev/null @@ -1,421 +0,0 @@ -import { parse } from 'graphql'; -import { migrateGraphQLSchema } from '../../schema-migrator'; - -function migrateAndValidate(inputSchema: string, defaultAuth: string = 'apiKey'): void { - const docNode = parse(inputSchema); - const migratedSchema = migrateGraphQLSchema(inputSchema, defaultAuth, docNode); - - parse(migratedSchema); - expect(migratedSchema).toMatchSnapshot(); -} - -describe('Schema migration tests', () => { - it('no amplify directives in schema', () => { - const schema = ` - type Todo { - id: ID! - name: String! - description: String - }`; - - migrateAndValidate(schema); - }); - - it('passes built-in directives through', () => { - const schema = ` - scalar UUID @specifiedBy(url: "https://tools.ietf.org/html/rfc4122") - - type Todo { - newField: String - oldField: String @deprecated(reason: "Use newField.") - }`; - - migrateAndValidate(schema); - }); - - it('basic @model type', () => { - const schema = ` - type Todo @model { - id: ID! - name: String! - description: String - }`; - - migrateAndValidate(schema); - }); - - it('multiple @model types', async () => { - const schema = ` - type Todo @model { - id: ID! - name: String! - description: String - } - - type Ope @model { - foo: ID! - bar: String - }`; - - migrateAndValidate(schema); - }); - - it('customized creation and update timestamp names', async () => { - const schema = ` - type Todo @model(timestamps: { createdAt: "createdOn", updatedAt: "updatedOn" }) { - id: ID! - str: String - }`; - - migrateAndValidate(schema); - }); - - it('explicit creation and update timestamps', async () => { - const schema = ` - type Todo @model { - id: ID! - createdAt: AWSTimestamp - updatedAt: AWSTimestamp - }`; - - migrateAndValidate(schema); - }); - - it('renamed queries/mutations/subscriptions', () => { - const schema = ` - type Entity @model(mutations: null, subscriptions: null, queries: { get: "getEntity" }) { - id: ID! - str: String - }`; - - migrateAndValidate(schema); - }); - - it('configure a primary key', () => { - const schema = ` - type Todo @model - @key(fields: ["id"]) { - id: ID! - name: String! - description: String - }`; - - migrateAndValidate(schema); - }); - - it('configure a secondary index', () => { - const schema = ` - type Todo @model - @key(name: "nameIndex", fields: ["name"]) { - id: ID! - name: String! - description: String - }`; - - migrateAndValidate(schema); - }); - - it('configure a secondary index with queryField', () => { - const schema = ` - type Todo @model - @key(name: "todosByStatus", fields: ["status"], queryField: "listTodosByStatus") { - id: ID! - name: String! - status: String! - }`; - - migrateAndValidate(schema); - }); - - it('@connection has one relationship with no fields', () => { - const schema = ` - type Project @model { - id: ID! - name: String - team: Team @connection - } - - type Team @model { - id: ID! - name: String! - }`; - - migrateAndValidate(schema); - }); - - it('@connection has one relationship with fields', () => { - const schema = ` - type Project @model { - id: ID! - name: String - teamID: ID! - team: Team @connection(fields: ["teamID"]) - } - - type Team @model { - id: ID! - name: String! - }`; - - migrateAndValidate(schema); - }); - - it('@connection has many relationship', () => { - const schema = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection(keyName: "byPost", fields: ["id"]) - } - - type Comment @model - @key(name: "byPost", fields: ["postID", "content"]) { - id: ID! - postID: ID! - content: String! - }`; - - migrateAndValidate(schema); - }); - - it('@connection has many relationship with limit', () => { - const schema = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection(limit: 50) - } - - type Comment @model { - id: ID! - content: String! - }`; - - migrateAndValidate(schema); - }); - - it('@connection belongs to relationship', () => { - const schema = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection(keyName: "byPost", fields: ["id"]) - } - - type Comment @model - @key(name: "byPost", fields: ["postID", "content"]) { - id: ID! - postID: ID! - content: String! - post: Post @connection(fields: ["postID"]) - }`; - - migrateAndValidate(schema); - }); - - it('@connection many to many relationship', () => { - const schema = ` - type Post @model { - id: ID! - title: String! - editors: [PostEditor] @connection(keyName: "byPost", fields: ["id"]) - } - - type PostEditor - @model(queries: null) - @key(name: "byPost", fields: ["postID", "editorID"]) - @key(name: "byEditor", fields: ["editorID", "postID"]) { - id: ID! - postID: ID! - editorID: ID! - post: Post! @connection(fields: ["postID"]) - editor: User! @connection(fields: ["editorID"]) - } - - type User @model { - id: ID! - username: String! - posts: [PostEditor] @connection(keyName: "byEditor", fields: ["id"]) - }`; - - migrateAndValidate(schema); - }); - - it('@function directive is migrated', () => { - const schema = ` - type Query { - echo(msg: String!): Context @function(name: "echo") - echoEnv(msg: String!): Context @function(name: "long-prefix-e2e-test-functions-echo-\${env}-v2") - duplicate(msg: String!): Context @function(name: "long-prefix-e2e-test-functions-echo-dev-v2") - pipeline(msg: String!): String @function(name: "echo") @function(name: "hello") - echoRegion(msg: String!): Context @function(name: "echo-\${env}" region: "us-east-1") - } - - type Context { - typeName: String - fieldName: String - }`; - - migrateAndValidate(schema); - }); - - it('@searchable directive is migrated', () => { - const schema = ` - type Book @model @key(fields: ["author", "name"]) @searchable { - author: String! - name: String! - genre: String! - } - - type Todo @model @searchable { - id: ID - name: String! - createdAt: AWSDateTime - description: String - } - - type Comment @model @key(name: "commentByVersion", fields: ["version", "id"]) @searchable { - id: ID! - version: Int! - content: String! - }`; - - migrateAndValidate(schema); - }); - - it('@http directive is migrated', () => { - const schema = ` - type Comment @model { - id: ID! - title: String - simpleGet: CompObj @http(method: GET, url: "https://amazon.com/posts/1") - simpleGet2: CompObj @http(url: "https://amazon.com/posts/2") - complexPost( - id: Int, - title: String!, - body: String, - userId: Int - ): CompObj @http(method: POST, url: "https://amazon.com/posts") - complexPut( - id: Int!, - title: String, - body: String, - userId: Int - ): CompObj @http(method: PUT, url: "https://amazon.com/posts/$\{env}/:id") - deleter: String @http(method: DELETE, url: "https://amazon.com/posts/4") - complexGet( - data: String!, - userId: Int!, - _limit: Int - ): [CompObj] @http(url: "https://amazon.com:data") - } - type CompObj { - userId: Int - id: Int - title: String - body: String - }`; - - migrateAndValidate(schema); - }); - - it('@predictions directive is migrated', () => { - const schema = ` - type Query { - translateImageText: String @predictions(actions: [identifyText]) - translateLabels: String @predictions(actions: [identifyLabels]) - translateThis: String @predictions(actions: [translateText]) - speakTranslatedText: String @predictions(actions: [translateText, convertTextToSpeech]) - }`; - - migrateAndValidate(schema); - }); - - it('migrates complex schema from documentation', () => { - const schema = ` - type Order @model - @key(name: "byCustomerByStatusByDate", fields: ["customerID", "status", "date"]) - @key(name: "byCustomerByDate", fields: ["customerID", "date"]) - @key(name: "byRepresentativebyDate", fields: ["accountRepresentativeID", "date"]) - @key(name: "byProduct", fields: ["productID", "id"]) { - id: ID! - customerID: ID! - accountRepresentativeID: ID! - productID: ID! - status: String! - amount: Int! - date: String! - } - - type Customer @model - @key(name: "byRepresentative", fields: ["accountRepresentativeID", "id"]) { - id: ID! - name: String! - phoneNumber: String - accountRepresentativeID: ID! - ordersByDate: [Order] @connection(keyName: "byCustomerByDate", fields: ["id"]) - ordersByStatusDate: [Order] @connection(keyName: "byCustomerByStatusByDate", fields: ["id"]) - } - - type Employee @model - @key(name: "newHire", fields: ["newHire", "id"], queryField: "employeesNewHire") - @key(name: "newHireByStartDate", fields: ["newHire", "startDate"], queryField: "employeesNewHireByStartDate") - @key(name: "byName", fields: ["name", "id"], queryField: "employeeByName") - @key(name: "byTitle", fields: ["jobTitle", "id"], queryField: "employeesByJobTitle") - @key(name: "byWarehouse", fields: ["warehouseID", "id"]) { - id: ID! - name: String! - startDate: String! - phoneNumber: String! - warehouseID: ID! - jobTitle: String! - newHire: String! # We have to use String type, because Boolean types cannot be sort keys - } - - type Warehouse @model { - id: ID! - employees: [Employee] @connection(keyName: "byWarehouse", fields: ["id"]) - } - - type AccountRepresentative @model - @key(name: "bySalesPeriodByOrderTotal", fields: ["salesPeriod", "orderTotal"], queryField: "repsByPeriodAndTotal") { - id: ID! - customers: [Customer] @connection(keyName: "byRepresentative", fields: ["id"]) - orders: [Order] @connection(keyName: "byRepresentativebyDate", fields: ["id"]) - orderTotal: Int - salesPeriod: String - } - - type Inventory @model - @key(name: "byWarehouseID", fields: ["warehouseID"], queryField: "itemsByWarehouseID") - @key(fields: ["productID", "warehouseID"]) { - productID: ID! - warehouseID: ID! - inventoryAmount: Int! - } - - type Product @model { - id: ID! - name: String! - orders: [Order] @connection(keyName: "byProduct", fields: ["id"]) - inventories: [Inventory] @connection(fields: ["id"]) - }`; - - migrateAndValidate(schema); - }); - - it('Has One @connection without fields always mapped to has one, even in bidirectional', () => { - const schema = ` - type Coffee @model { - id: ID! - energy: Energy @connection # => @hasOne - } - - type Energy @model { - id: ID! - coffee: Coffee @connection # => @hasOne - }`; - - migrateAndValidate(schema); - }); -}); diff --git a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/.config/local-env-info.json b/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/.config/local-env-info.json deleted file mode 100644 index 9d540b11e5..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/.config/local-env-info.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "envName": "testtest" -} diff --git a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/backend/amplify-meta.json b/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/backend/amplify-meta.json deleted file mode 100644 index 252d4c2acf..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/backend/amplify-meta.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "api": { - "testapi": { - "service": "AppSync", - "providerPlugin": "awscloudformation", - "output": { - "authConfig": { - "defaultAuthentication": { - "authenticationType": "API_KEY", - "apiKeyConfig": { - "apiKeyExpirationDays": 7 - } - }, - "additionalAuthenticationProviders": [] - } - } - } - } -} diff --git a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/backend/api/testapi/schema/Mud.graphql b/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/backend/api/testapi/schema/Mud.graphql deleted file mode 100644 index 5a7454f4bc..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/backend/api/testapi/schema/Mud.graphql +++ /dev/null @@ -1,4 +0,0 @@ -type Mud @model { - id: ID! - obligations: [Obligation] @connection(keyName: "byMud", fields: ["id"]) # => @hasMany(indexName: "byMud", fields: ["id"]) -} diff --git a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/backend/api/testapi/schema/nested/Obligation.graphql b/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/backend/api/testapi/schema/nested/Obligation.graphql deleted file mode 100644 index 295961264c..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/backend/api/testapi/schema/nested/Obligation.graphql +++ /dev/null @@ -1,5 +0,0 @@ -type Obligation @model @key(name: "byMud", fields: ["mudID", "content"]) { - id: ID! - mudID: ID # => @index(name: "byMud", sortKeyFields: ["content"]) - content: String -} diff --git a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/backend/backend-config.json b/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/backend/backend-config.json deleted file mode 100644 index 252d4c2acf..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/backend/backend-config.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "api": { - "testapi": { - "service": "AppSync", - "providerPlugin": "awscloudformation", - "output": { - "authConfig": { - "defaultAuthentication": { - "authenticationType": "API_KEY", - "apiKeyConfig": { - "apiKeyExpirationDays": 7 - } - }, - "additionalAuthenticationProviders": [] - } - } - } - } -} diff --git a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/cli.json b/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/cli.json deleted file mode 100644 index 5d758b56b7..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/cli.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "features": { - "graphqltransformer": { - "improvepluralization": true, - "useexperimentalpipelinedtransformer": false, - "transformerversion": 1, - "suppressschemamigrationprompt": false - } - } -} diff --git a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/team-provider-info.json b/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/team-provider-info.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/mock-projects/v1-schema-project/amplify/team-provider-info.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/schema-inspector.test.ts b/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/schema-inspector.test.ts deleted file mode 100644 index c92e46176f..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/schema-inspector.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { detectDeprecatedConnectionUsage, detectPassthroughDirectives } from '../../schema-inspector'; - -test('deprecated @connection parameterization fails gracefully', async () => { - const schema = /* GraphQL */ ` - type PostConnection @model @auth(rules: [{ allow: public }]) { - id: ID! - title: String! - comments: [CommentConnection] @connection(name: "PostComments") - } - - type CommentConnection @model { - id: ID! - content: String! - post: PostConnection @connection(name: "PostComments") - } - `; - const result = await detectDeprecatedConnectionUsage(schema); - expect(result).toBe(true); -}); - -test('AppSync auth directives are not migrated', async () => { - const denylist = ['aws_api_key', 'aws_iam', 'aws_oidc', 'aws_cognito_user_pools', 'aws_auth']; - - for (const directive of denylist) { - const schema = ` - type Todo @model @${directive} { - id: ID! - }`; - const result = await detectPassthroughDirectives(schema); - - expect(result).toMatchInlineSnapshot(` - Array [ - "${directive}", - ] - `); - } -}); - -test('custom directives are not migrated', async () => { - const schema = ` - type Restaurant @model { - blt: String! @sandwich - } - `; - const result = await detectPassthroughDirectives(schema); - - expect(result).toMatchInlineSnapshot(` - Array [ - "sandwich", - ] - `); -}); - -test('@versioned is not migrated', async () => { - const schema = ` - type Restaurant @model @versioned { - blt: String! - } - `; - const result = await detectPassthroughDirectives(schema); - - expect(result).toMatchInlineSnapshot(` - Array [ - "versioned", - ] - `); -}); diff --git a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/schema-migrator.test.ts b/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/schema-migrator.test.ts deleted file mode 100644 index 3aea070e46..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/__tests__/migration/schema-migrator.test.ts +++ /dev/null @@ -1,198 +0,0 @@ -const getParamMock = jest.fn(); // Mock must be declared before imports: https://jestjs.io/docs/manual-mocks#using-with-es-module-imports - -import * as os from 'os'; -import * as path from 'path'; -import * as fs from 'fs-extra'; -import { printer, prompter } from '@aws-amplify/amplify-prompts'; -import { pathManager, FeatureFlags } from '@aws-amplify/amplify-cli-core'; -import { attemptV2TransformerMigration, revertV2Migration } from '../../schema-migrator'; - -jest.mock('@aws-amplify/amplify-prompts'); -const prompter_mock = prompter as jest.Mocked; -prompter_mock.confirmContinue.mockResolvedValue(true); - -jest.mock('@aws-amplify/amplify-environment-parameters', () => ({ - getEnvParamManager: jest.fn().mockReturnValue({ - getResourceParamManager: jest.fn().mockReturnValue({ - getParam: getParamMock, - }), - }), -})); - -const testProjectPath = path.resolve(__dirname, 'mock-projects', 'v1-schema-project'); - -const resourceDir = (projectDir: string) => path.join(projectDir, 'amplify', 'backend', 'api', 'testapi'); -const cliJsonPath = (projectDir: string) => path.join(projectDir, 'amplify', 'cli.json'); -const apiName = 'testapi'; -const envName = 'testtest'; - -describe('attemptV2TransformerMigration', () => { - let tempProjectDir: string; - beforeEach(async () => { - const randomSuffix = (Math.random() * 10000).toString().split('.')[0]; - tempProjectDir = path.join(os.tmpdir(), `schema-migrator-test-${randomSuffix}`); - await fs.copy(testProjectPath, tempProjectDir); - jest.spyOn(pathManager, 'findProjectRoot').mockReturnValue(tempProjectDir); - // used by pathManager - // Will remove when removing pathManager - FeatureFlags.initialize({ getCurrentEnvName: () => envName }); - }); - - afterEach(async () => { - await fs.remove(tempProjectDir); - }); - - it('migrates schemas and sets FF', async () => { - const apiResourceDir = resourceDir(tempProjectDir); - await attemptV2TransformerMigration(apiResourceDir, apiName, { transformerVersion: 1, improvePluralization: true }, envName); - expect(await fs.readFile(path.join(apiResourceDir, 'schema', 'Mud.graphql'), 'utf8')).toMatchInlineSnapshot(` - "type Mud @model @auth(rules: [{allow: public}]) { - id: ID! - obligations: [Obligation] @hasMany(indexName: \\"byMud\\", fields: [\\"id\\"]) - } - " - `); - expect(await fs.readFile(path.join(apiResourceDir, 'schema', 'nested', 'Obligation.graphql'), 'utf8')).toMatchInlineSnapshot(` - "type Obligation @model @auth(rules: [{allow: public}]) { - id: ID! - mudID: ID @index(name: \\"byMud\\", sortKeyFields: [\\"content\\"]) - content: String - } - " - `); - const cliJsonFile = await fs.readJSON(cliJsonPath(tempProjectDir), { encoding: 'utf8' }); - expect(cliJsonFile.features.graphqltransformer.useexperimentalpipelinedtransformer).toBe(true); - expect(cliJsonFile.features.graphqltransformer.transformerversion).toBe(2); - expect(cliJsonFile.features.graphqltransformer.suppressschemamigrationprompt).toBe(true); - expect(cliJsonFile.features.codegen.useappsyncmodelgenplugin).toBe(true); - }); - - it('leaves project unchanged when migrating and rolling back', async () => { - const apiResourceDir = resourceDir(tempProjectDir); - await attemptV2TransformerMigration(apiResourceDir, apiName, { transformerVersion: 1, improvePluralization: true }, envName); - await revertV2Migration(apiResourceDir, envName); - const projectSchema1 = await fs.readFile(path.join(apiResourceDir, 'schema', 'Mud.graphql'), 'utf8'); - const projectSchema2 = await fs.readFile(path.join(apiResourceDir, 'schema', 'nested', 'Obligation.graphql'), 'utf8'); - const projectCliJson = await fs.readJSON(cliJsonPath(tempProjectDir), { encoding: 'utf8' }); - - const origApiResourceDir = resourceDir(testProjectPath); - const originalSchema1 = await fs.readFile(path.join(origApiResourceDir, 'schema', 'Mud.graphql'), 'utf8'); - const originalSchema2 = await fs.readFile(path.join(origApiResourceDir, 'schema', 'nested', 'Obligation.graphql'), 'utf8'); - const originalCliJson = await fs.readJSON(cliJsonPath(testProjectPath), { encoding: 'utf8' }); - - expect(projectSchema1).toEqual(originalSchema1); - expect(projectSchema2).toEqual(originalSchema2); - expect(projectCliJson).toEqual(originalCliJson); - }); - - it('succeeds but warns when overwritten resolvers are detected', async () => { - const apiResourceDir = resourceDir(tempProjectDir); - const resolversDir = path.join(apiResourceDir, 'resolvers'); - const overwrittenPath = path.join(resolversDir, 'Query.listTodos.postAuth.2.req.vtl'); - - fs.mkdirSync(resolversDir); - fs.writeFileSync(overwrittenPath, '{}'); - await attemptV2TransformerMigration(apiResourceDir, apiName, { transformerVersion: 1, improvePluralization: true }, envName); - expect(printer.info).toHaveBeenCalledWith(expect.stringMatching('You have overridden an Amplify generated resolver')); - - const cliJsonFile = await fs.readJSON(cliJsonPath(tempProjectDir), { encoding: 'utf8' }); - expect(cliJsonFile.features.graphqltransformer.useexperimentalpipelinedtransformer).toBe(true); - expect(cliJsonFile.features.graphqltransformer.transformerversion).toBe(2); - expect(cliJsonFile.features.graphqltransformer.suppressschemamigrationprompt).toBe(true); - expect(cliJsonFile.features.codegen.useappsyncmodelgenplugin).toBe(true); - }); - - it('succeeds but warns when custom roots/resolvers are detected', async () => { - const apiResourceDir = resourceDir(tempProjectDir); - const schemaPath = path.join(apiResourceDir, 'schema', 'schema.graphql'); - - fs.writeFileSync(schemaPath, 'type Query { listFoos: String }'); - await attemptV2TransformerMigration(apiResourceDir, apiName, { transformerVersion: 1, improvePluralization: true }, envName); - expect(printer.info).toHaveBeenCalledWith( - expect.stringMatching('You have defined custom Queries, Mutations, and/or Subscriptions in your GraphQL schema'), - ); - - const cliJsonFile = await fs.readJSON(cliJsonPath(tempProjectDir), { encoding: 'utf8' }); - expect(cliJsonFile.features.graphqltransformer.useexperimentalpipelinedtransformer).toBe(true); - expect(cliJsonFile.features.graphqltransformer.transformerversion).toBe(2); - expect(cliJsonFile.features.graphqltransformer.suppressschemamigrationprompt).toBe(true); - expect(cliJsonFile.features.codegen.useappsyncmodelgenplugin).toBe(true); - }); - - it('succeeds but warns when improvePluralization FF is false', async () => { - const apiResourceDir = resourceDir(tempProjectDir); - let cliJsonFile = await fs.readJSON(cliJsonPath(tempProjectDir), { encoding: 'utf8' }); - - await fs.writeJSON(cliJsonPath(tempProjectDir), cliJsonFile); - await attemptV2TransformerMigration(apiResourceDir, apiName, { transformerVersion: 1, improvePluralization: false }, envName); - expect(printer.info).toHaveBeenCalledWith(expect.stringMatching('You do not have the "improvePluralization" Feature Flag enabled')); - - cliJsonFile = await fs.readJSON(cliJsonPath(tempProjectDir), { encoding: 'utf8' }); - expect(cliJsonFile.features.graphqltransformer.useexperimentalpipelinedtransformer).toBe(true); - expect(cliJsonFile.features.graphqltransformer.transformerversion).toBe(2); - expect(cliJsonFile.features.graphqltransformer.suppressschemamigrationprompt).toBe(true); - expect(cliJsonFile.features.codegen.useappsyncmodelgenplugin).toBe(true); - }); - - it('fails if GQL API is configured to use SQL', async () => { - getParamMock.mockReturnValueOnce('mockRdsParam'); - const apiResourceDir = resourceDir(tempProjectDir); - await attemptV2TransformerMigration(apiResourceDir, apiName, { transformerVersion: 1, improvePluralization: true }, envName); - expect(printer.info).toHaveBeenCalledWith(expect.stringMatching('GraphQL APIs using Aurora RDS cannot be migrated.')); - - const cliJsonFile = await fs.readJSON(cliJsonPath(tempProjectDir), { encoding: 'utf8' }); - expect(cliJsonFile.features.graphqltransformer.useexperimentalpipelinedtransformer).toBe(false); - expect(cliJsonFile.features.graphqltransformer.transformerversion).toBe(1); - expect(cliJsonFile.features.graphqltransformer.suppressschemamigrationprompt).toBe(false); - }); - - it('fails if @auth uses queries or mutations', async () => { - const apiResourceDir = resourceDir(tempProjectDir); - const schemaPath = path.join(apiResourceDir, 'schema', 'schema.graphql'); - - fs.writeFileSync( - schemaPath, - ` - type Post @model @auth(rules: [{allow: groups, groups: ["Admin", "Dev"], queries: [get, list], operations: [create, update, delete]}]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `, - ); - await attemptV2TransformerMigration(apiResourceDir, apiName, { transformerVersion: 1, improvePluralization: true }, envName); - expect(printer.info).toHaveBeenCalledWith(expect.stringMatching('You are using queries or mutations in at least one @auth rule.')); - - const cliJsonFile = await fs.readJSON(cliJsonPath(tempProjectDir), { encoding: 'utf8' }); - expect(cliJsonFile.features.graphqltransformer.useexperimentalpipelinedtransformer).toBe(false); - expect(cliJsonFile.features.graphqltransformer.transformerversion).toBe(1); - expect(cliJsonFile.features.graphqltransformer.suppressschemamigrationprompt).toBe(false); - }); - - it('Correctly returns the codegen useappsyncmodelgenplugin flag to empty state after @auth queries failure', async () => { - const apiResourceDir = resourceDir(tempProjectDir); - const schemaPath = path.join(apiResourceDir, 'schema', 'schema.graphql'); - - fs.writeFileSync( - schemaPath, - ` - type Post @model @auth(rules: [{allow: groups, groups: ["Admin", "Dev"], queries: [get, list], operations: [create, update, delete]}]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `, - ); - const improvedPluralizationEnabled = true; - await attemptV2TransformerMigration(apiResourceDir, apiName, { transformerVersion: 1, improvePluralization: true }, envName); - expect(printer.info).toHaveBeenCalledWith(expect.stringMatching('You are using queries or mutations in at least one @auth rule.')); - - const cliJsonFile = await fs.readJSON(cliJsonPath(tempProjectDir), { encoding: 'utf8' }); - expect(cliJsonFile.features.graphqltransformer.useexperimentalpipelinedtransformer).toBe(false); - expect(cliJsonFile.features.graphqltransformer.transformerversion).toBe(1); - expect(cliJsonFile.features.graphqltransformer.suppressschemamigrationprompt).toBe(false); - expect(cliJsonFile.features?.codegen?.useappsyncmodelgenplugin).toBeUndefined(); - }); -}); diff --git a/packages/amplify-graphql-transformer-migrator/src/constants/graphql-directives.ts b/packages/amplify-graphql-transformer-migrator/src/constants/graphql-directives.ts deleted file mode 100644 index 207a018462..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/constants/graphql-directives.ts +++ /dev/null @@ -1,150 +0,0 @@ -export const GRAPHQL_DIRECTIVES_SCHEMA = ` -directive @model( - queries: ModelQueryMap - mutations: ModelMutationMap - subscriptions: ModelSubscriptionMap - timestamps: TimestampConfiguration -) on OBJECT -input ModelMutationMap { - create: String - update: String - delete: String -} -input ModelQueryMap { - get: String - list: String -} -input ModelSubscriptionMap { - onCreate: [String] - onUpdate: [String] - onDelete: [String] - level: ModelSubscriptionLevel -} -enum ModelSubscriptionLevel { - off - public - on -} -input TimestampConfiguration { - createdAt: String - updatedAt: String -} - -directive @function(name: String!, region: String) repeatable on FIELD_DEFINITION - -directive @http(method: HttpMethod = GET, url: String!, headers: [HttpHeader] = []) on FIELD_DEFINITION -enum HttpMethod { - GET - POST - PUT - DELETE - PATCH -} -input HttpHeader { - key: String - value: String -} - -directive @key(name: String, fields: [String!]!, queryField: String) repeatable on OBJECT - -directive @connection( - name: String - keyField: String - sortField: String - keyName: String - limit: Int - fields: [String!] -) on FIELD_DEFINITION - -directive @predictions(actions: [PredictionsActions!]!) on FIELD_DEFINITION -enum PredictionsActions { - identifyText - identifyLabels - convertTextToSpeech - translateText -} - -directive @searchable(queries: SearchableQueryMap) on OBJECT -input SearchableQueryMap { - search: String -} - -directive @auth(rules: [AuthRule!]!) on OBJECT | FIELD_DEFINITION -input AuthRule { - # Specifies the auth rule's strategy. Allowed values are 'owner', 'groups', 'public', 'private'. - allow: AuthStrategy! - - # Legacy name for identityClaim - identityField: String @deprecated(reason: "The 'identityField' argument is replaced by the 'identityClaim'.") - - # Specifies the name of the provider to use for the rule. This overrides the default provider - # when 'public' and 'private' AuthStrategy is used. Specifying a provider for 'owner' or 'groups' - # are not allowed. - provider: AuthProvider - - # Specifies the name of the claim to look for on the request's JWT token - # from Cognito User Pools (and in the future OIDC) that contains the identity - # of the user. If 'allow' is 'groups', this value should point to a list of groups - # in the claims. If 'allow' is 'owner', this value should point to the logged in user identity string. - # Defaults to "cognito:username" for Cognito User Pools auth. - identityClaim: String - - # Allows for custom config of 'groups' which is validated against the JWT - # Specifies a static list of groups that should have access to the object - groupClaim: String - - # Allowed when the 'allow' argument is 'owner'. - # Specifies the field of type String or [String] that contains owner(s) that can access the object. - ownerField: String # defaults to "owner" - # Allowed when the 'allow' argument is 'groups'. - # Specifies the field of type String or [String] that contains group(s) that can access the object. - groupsField: String - - # Allowed when the 'allow' argument is 'groups'. - # Specifies a static list of groups that should have access to the object. - groups: [String] - - # Specifies operations to which this auth rule should be applied. - operations: [ModelOperation] - - # Deprecated. It is recommended to use the 'operations' arguments. - queries: [ModelQuery] - @deprecated(reason: "The 'queries' argument will be replaced by the 'operations' argument in a future release.") - - # Deprecated. It is recommended to use the 'operations' arguments. - mutations: [ModelMutation] - @deprecated(reason: "The 'mutations' argument will be replaced by the 'operations' argument in a future release.") -} -enum AuthStrategy { - owner - groups - private - public -} -enum AuthProvider { - apiKey - iam - oidc - userPools -} -enum ModelOperation { - create - update - delete - read - get - list - search - listen - sync -} -enum ModelQuery @deprecated(reason: "ModelQuery will be replaced by the 'ModelOperation' in a future release.") { - get - list -} -enum ModelMutation @deprecated(reason: "ModelMutation will be replaced by the 'ModelOperation' in a future release.") { - create - update - delete -} -`; diff --git a/packages/amplify-graphql-transformer-migrator/src/index.ts b/packages/amplify-graphql-transformer-migrator/src/index.ts deleted file mode 100644 index a740b0939e..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { attemptV2TransformerMigration, revertV2Migration, runMigration } from './schema-migrator'; -// No-op change to trigger re-publish diff --git a/packages/amplify-graphql-transformer-migrator/src/migrators/auth/defaultAuth.ts b/packages/amplify-graphql-transformer-migrator/src/migrators/auth/defaultAuth.ts deleted file mode 100644 index 4d36a98bf7..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/migrators/auth/defaultAuth.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { createAuthRule } from '../generators'; -import { hasAuthDirectives, addAuthRuleToNode } from '.'; - -const defaultAuthModeMap: Map = new Map([ - ['apiKey', 'public'], - ['iam', 'private'], - ['userPools', 'private'], - ['oidc', 'private'], -]); - -export function migrateDefaultAuthMode(node: any, defaultAuthMode: any) { - if (defaultAuthMode === 'iam') { - return; - } - - if (!hasAuthDirectives(node)) { - const authRule = createAuthRule(defaultAuthModeMap.get(defaultAuthMode), defaultAuthMode); - addAuthRuleToNode(node, authRule); - } -} diff --git a/packages/amplify-graphql-transformer-migrator/src/migrators/auth/index.ts b/packages/amplify-graphql-transformer-migrator/src/migrators/auth/index.ts deleted file mode 100644 index 888564115e..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/migrators/auth/index.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { isModelType } from '../model'; -import { createArgumentNode, createDirectiveNode, createListValueNode } from '../generators'; -import { migrateDefaultAuthMode } from './defaultAuth'; -import { migrateOwnerAuth } from './ownerAuth'; - -export function hasAuthDirectives(node: any) { - return node.directives.some((dir: any) => dir.name.value === 'auth'); -} - -export function getAuthRules(node: any) { - return node.directives.find((dir: any) => dir.name.value === 'auth').arguments[0].value.values; -} - -export function setAuthRules(node: any, rules: any) { - node.directives.find((dir: any) => dir.name.value === 'auth').arguments[0].value.values = rules; -} - -export function addAuthRuleToNode(node: any, rule: any) { - if (!hasAuthDirectives(node)) { - const valueNode = createListValueNode([rule]); - const authDirArgs = createArgumentNode('rules', valueNode); - const authDir = createDirectiveNode('auth', [authDirArgs]); - node.directives.push(authDir); - } else { - const authRules = getAuthRules(node); - if (authRules) { - authRules.push(rule); - } - } -} - -export const defaultProviderMap: Map = new Map([ - ['public', 'apiKey'], - ['private', 'userPools'], - ['owner', 'userPools'], - ['groups', 'userPools'], -]); - -export function migrateAuth(node: any, defaultAuthMode: any) { - if (!isModelType(node)) { - return; - } - - if (hasAuthDirectives(node)) { - migrateOwnerAuth(node, defaultAuthMode); - } - - migrateDefaultAuthMode(node, defaultAuthMode); -} diff --git a/packages/amplify-graphql-transformer-migrator/src/migrators/auth/ownerAuth.ts b/packages/amplify-graphql-transformer-migrator/src/migrators/auth/ownerAuth.ts deleted file mode 100644 index 2638d17d2e..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/migrators/auth/ownerAuth.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { createAuthRule } from '../generators'; -import { getAuthRules } from '.'; - -function getPrivateAuthRule(rules: any, provider: any) { - return rules.find((rule: any) => { - const foundStrategy = rule.fields.find((f: any) => f.name.value === 'allow')?.value?.value; - const foundProvider = rule.fields.find((f: any) => f.name.value === 'provider')?.value?.value; - - if (foundStrategy !== 'private') { - return false; - } - - if (provider === 'userPools' && (foundProvider === undefined || foundProvider === 'userPools')) { - return true; - } else if (provider === 'iam' && foundProvider === 'iam') { - return true; - } - return false; - }); -} - -function getOwnerAuthRules(rules: any) { - return rules.filter((rule: any) => rule.fields.find((f: any) => f?.name?.value === 'allow')?.value?.value === 'owner'); -} - -function getGroupAuthRules(rules: any) { - return rules.filter((rule: any) => rule.fields.find((f: any) => f?.name?.value === 'allow')?.value?.value === 'groups'); -} - -const ops = ['create', 'read', 'update', 'delete']; - -export function migrateOwnerAuth(node: any, defaultAuthMode: any) { - const authRules = getAuthRules(node); - - // check if owner-based auth exist and if operations allow everything. - const deniedOperations: Set = new Set(); - const userBasedRulesWithProtection = getOwnerAuthRules(authRules).concat(getGroupAuthRules(authRules)); - if (userBasedRulesWithProtection.length === 0) return; - - userBasedRulesWithProtection.forEach((rule: any) => { - const operationsFieldIndex = rule.fields.findIndex((f: any) => f.name.value === 'operations'); - - if (operationsFieldIndex === -1) { - ops.forEach((op) => deniedOperations.add(op)); - } else { - // remember denied operations - rule.fields[operationsFieldIndex].value.values.forEach((op: any) => deniedOperations.add(op.value)); - // maintain full CRUD access for owners - if (userBasedRulesWithProtection.length === 1) rule.fields.splice(operationsFieldIndex, 1); - } - }); - - const hasAllImplicitOperations = deniedOperations.size === 4; - const privateRule = getPrivateAuthRule(authRules, defaultAuthMode); - - if (hasAllImplicitOperations || privateRule) return; - - const explicitOperations = ops.filter((x) => !deniedOperations.has(x)); - - authRules.push(createAuthRule('private', defaultAuthMode, explicitOperations)); -} diff --git a/packages/amplify-graphql-transformer-migrator/src/migrators/connection/index.ts b/packages/amplify-graphql-transformer-migrator/src/migrators/connection/index.ts deleted file mode 100644 index e98ab5e2e6..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/migrators/connection/index.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { isListType } from 'graphql-transformer-common'; - -const validConnectionDirectiveNames = new Set(['hasOne', 'hasMany', 'connection']); - -export function getFieldsWithConnection(fields: any) { - return fields.filter((field: any) => field.directives.find((d: any) => d.name.value === 'connection')); -} - -export function getConnectionFieldsArg(connection: any) { - return connection.arguments.find((a: any) => a?.name?.value === 'fields')?.value?.values?.map((v: any) => v.value); -} - -export function isFieldIndex(field: any) { - return field.directives.some((dir: any) => dir.name.value === 'index'); -} - -export function getConnectionDirective(field: any) { - return field.directives.find( - (d: any) => d.name.value === 'connection' || d.name.value === 'hasMany' || d.name.value === 'hasOne' || d.name.value === 'belongsTo', - ); -} - -function getRelatedType(output: any, relatedTypeName: any) { - const relatedType = output.definitions.find((d: any) => d.kind === 'ObjectTypeDefinition' && d.name.value === relatedTypeName); - - return relatedType; -} - -function getFieldType(field: any): any { - if (field.type.kind === 'NamedType') { - return field.type.name.value; - } else { - return getFieldType(field.type); - } -} - -export function migrateConnection(node: any, ast: any) { - const connections = getFieldsWithConnection(node.fields); - if (connections.length === 0) { - return; - } - - connections.forEach((connectionField: any) => { - const connectionDirective = getConnectionDirective(connectionField); - let typeIsList = connectionField.type ? isListType(connectionField.type) : false; - if (typeIsList) { - connectionDirective.name.value = 'hasMany'; - const keyNameArg = connectionDirective.arguments.find((a: any) => a.name.value === 'keyName'); - - if (keyNameArg) { - keyNameArg.name.value = 'indexName'; - } - } else { - const relatedType = getRelatedType(ast, getFieldType(connectionField)); - const biDirectionalRelation = relatedType.fields.find((relatedField: any) => { - if (getFieldType(relatedField) !== node.name.value) { - return false; - } - - const fieldsArg = node.fields.find((f: any) => f.name.value === getConnectionFieldsArg(connectionDirective)?.[0]); - if (fieldsArg && !isFieldIndex(fieldsArg)) { - return false; - } - - return relatedField?.directives?.find((relatedDirective: any) => { - return validConnectionDirectiveNames.has(relatedDirective.name.value); - }); - }); - - if (biDirectionalRelation?.type && isListType(biDirectionalRelation.type)) { - connectionDirective.name.value = 'belongsTo'; - } else { - connectionDirective.name.value = 'hasOne'; - } - } - }); -} diff --git a/packages/amplify-graphql-transformer-migrator/src/migrators/generators/index.ts b/packages/amplify-graphql-transformer-migrator/src/migrators/generators/index.ts deleted file mode 100644 index 76f0791d23..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/migrators/generators/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { parseValue } from 'graphql'; -import { defaultProviderMap } from '../auth'; - -/** - * Create a graphql name node given a name value - */ -export function createNameNode(name: any) { - return { - kind: 'Name', - value: name, - }; -} - -export function createDirectiveNode(name: any, args: any) { - return { - kind: 'Directive', - name: createNameNode(name), - arguments: args, - }; -} - -export function createArgumentNode(name: any, value: any) { - return { - kind: 'Argument', - name: createNameNode(name), - value: value, - }; -} - -export function createListValueNode(values: any) { - return { - kind: 'ListValue', - values: values, - }; -} - -/** - * Note this only supports strategy, provider and operations. Group and owner auth is not supported - */ -export function createAuthRule(strategy: any, provider: any, operations?: any) { - let rule = `{allow: ${strategy}`; - if (provider && provider !== defaultProviderMap.get(strategy)) { - rule += `, provider: ${provider}`; - } - - if (operations && operations.length !== 4) { - rule += `, operations: [${operations.join(', ')}]`; - } - rule += '}'; - return parseValue(rule); -} diff --git a/packages/amplify-graphql-transformer-migrator/src/migrators/key/index.ts b/packages/amplify-graphql-transformer-migrator/src/migrators/key/index.ts deleted file mode 100644 index f0a7cb0b7f..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/migrators/key/index.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { createArgumentNode, createDirectiveNode } from '../generators'; - -export function isPrimaryKey(directive: any): boolean { - return ( - directive.name.value === 'key' && - directive.arguments.some((a: any) => a.name.value === 'fields') && - !directive.arguments.some((a: any) => a.name.value === 'name') - ); -} - -export function migratePrimaryKey(node: any, directive: any) { - let fields = directive.arguments.find((i: any) => i.name.value === 'fields'); - const fieldIndex = node.fields.findIndex((field: any) => field.name.value === fields.value.values[0].value); - let args: any[] = []; - if (fields.value.values.length !== 1) { - args = [ - createArgumentNode('sortKeyFields', { - ...fields.value, - values: fields.value.values.slice(1), - }), - ]; - } - node.fields[fieldIndex].directives.push(createDirectiveNode('primaryKey', args)); -} - -export function isSecondaryKey(directive: any) { - return ( - directive.name.value === 'key' && - directive.arguments.some((a: any) => a.name.value === 'fields') && - directive.arguments.some((a: any) => a.name.value === 'name') - ); -} - -export function migrateSecondaryKey(node: any, directive: any) { - let fields = directive.arguments.find((i: any) => i.name.value === 'fields'); - const fieldIndex = node.fields.findIndex((field: any) => field.name.value === fields.value.values[0].value); - let args = directive.arguments.filter((i: any) => i.name.value !== 'fields'); - if (fields.value.values.length !== 1) { - args = [ - ...args, - createArgumentNode('sortKeyFields', { - ...fields.value, - values: fields.value.values.slice(1), - }), - ]; - } - node.fields[fieldIndex].directives.push(createDirectiveNode('index', args)); -} - -export function migrateKeys(node: any) { - const dirs = node.directives; - if (!dirs) { - return; - } - let keys = []; - for (const dir of dirs) { - if (dir.name.value === 'key') { - keys.push(dir); - } - } - node.directives = dirs.filter((dir: any) => dir.name.value !== 'key'); - for (const index of keys) { - if (isPrimaryKey(index)) { - migratePrimaryKey(node, index); - } else if (isSecondaryKey(index)) { - migrateSecondaryKey(node, index); - } - } -} diff --git a/packages/amplify-graphql-transformer-migrator/src/migrators/model/index.ts b/packages/amplify-graphql-transformer-migrator/src/migrators/model/index.ts deleted file mode 100644 index 0d007319eb..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/migrators/model/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function isModelType(node: any) { - return node.directives.find((dir: any) => dir.name.value === 'model'); -} diff --git a/packages/amplify-graphql-transformer-migrator/src/schema-backup.ts b/packages/amplify-graphql-transformer-migrator/src/schema-backup.ts deleted file mode 100644 index 2f3a6b72c6..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/schema-backup.ts +++ /dev/null @@ -1,27 +0,0 @@ -import * as path from 'path'; -import * as fs from 'fs-extra'; - -export const backupLocation = (resourceDir: string) => path.join(resourceDir, '.migration-backup'); - -export const backupSchemas = async (resourceDir: string): Promise => { - const schemaFilePath = path.join(resourceDir, 'schema.graphql'); - const schemaDirPath = path.join(resourceDir, 'schema'); - const schemaFileExists = fs.existsSync(schemaFilePath); - const schemaDirectoryExists = fs.existsSync(schemaDirPath); - if (schemaFileExists) { - await fs.copy(schemaFilePath, path.join(backupLocation(resourceDir), 'schema.graphql'), { overwrite: false, errorOnExist: true }); - return; - } - if (schemaDirectoryExists) { - await fs.copy(schemaDirPath, path.join(backupLocation(resourceDir), 'schema'), { overwrite: false, errorOnExist: true }); - } -}; - -export const restoreSchemas = async (resourceDir: string): Promise => { - await fs.copy(backupLocation(resourceDir), resourceDir); - await fs.remove(backupLocation(resourceDir)); -}; - -export function doesBackupExist(resourceDir: string): boolean { - return fs.existsSync(backupLocation(resourceDir)); -} diff --git a/packages/amplify-graphql-transformer-migrator/src/schema-inspector.ts b/packages/amplify-graphql-transformer-migrator/src/schema-inspector.ts deleted file mode 100644 index 29189b6eb8..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/schema-inspector.ts +++ /dev/null @@ -1,86 +0,0 @@ -import * as path from 'path'; -import { getEnvParamManager } from '@aws-amplify/amplify-environment-parameters'; -import { pathManager } from '@aws-amplify/amplify-cli-core'; -import { DocumentNode } from 'graphql/language'; -import { visit } from 'graphql'; -import { collectDirectives, collectDirectivesByTypeNames, APICategory } from '@aws-amplify/graphql-transformer-core'; -import * as fs from 'fs-extra'; -import { listContainsOnlySetString } from './utils'; - -export function graphQLUsingSQL(apiName: string): boolean { - const apiParameterManager = getEnvParamManager().getResourceParamManager(APICategory, apiName); - return !!apiParameterManager.getParam('rdsClusterIdentifier'); -} - -export function detectCustomRootTypes(schema: DocumentNode): boolean { - let customResolversUsed = false; - visit(schema, { - ObjectTypeDefinition: { - enter(node) { - if (node.name.value === 'Mutation' || node.name.value === 'Query' || node.name.value === 'Subscription') { - customResolversUsed = true; - } - }, - }, - }); - return customResolversUsed; -} - -export function detectOverriddenResolvers(apiName: string): boolean { - const resolversDir = path.join(pathManager.getResourceDirectoryPath(undefined, 'api', apiName), 'resolvers'); - if (!fs.existsSync(resolversDir)) { - return false; - } - const vtlFiles = fs.readdirSync(resolversDir).filter((file) => file.endsWith('.vtl')); - return !!vtlFiles.length; -} - -export async function detectPassthroughDirectives(schema: string): Promise> { - const supportedDirectives = new Set(['connection', 'key', 'auth', 'model', 'function', 'predictions', 'aws_subscribe']); - const directiveMap: any = collectDirectivesByTypeNames(schema).types; - const passthroughDirectiveSet = new Set(); - for (const type of Object.keys(directiveMap)) { - for (const dirName of listContainsOnlySetString(directiveMap[type], supportedDirectives)) { - passthroughDirectiveSet.add(dirName); - } - } - - return Array.from(passthroughDirectiveSet); -} - -export function detectDeprecatedConnectionUsage(schema: string): boolean { - const directives = collectDirectives(schema); - const deprecatedConnectionArgs = ['name', 'keyField', 'sortField', 'limit']; - const connectionDirectives = directives.filter((directive) => directive.name.value === 'connection'); - for (const connDir of connectionDirectives) { - if (connDir.arguments?.some((arg) => deprecatedConnectionArgs.includes(arg.name.value))) { - return true; - } - } - return false; -} - -export function authRuleUsesQueriesOrMutations(schema: string): boolean { - const authDirectives = collectDirectives(schema).filter((directive) => directive.name.value === 'auth'); - - for (const authDir of authDirectives) { - const rulesArg = - authDir.arguments - ?.filter((arg) => arg.name.value === 'rules' && arg.value.kind === 'ListValue') - .map((arg: any) => arg.value.values) ?? []; - - for (const rules of rulesArg) { - for (const rule of rules) { - for (const field of rule.fields) { - const fieldName = field.name.value; - - if (fieldName === 'queries' || fieldName === 'mutations') { - return true; - } - } - } - } - } - - return false; -} diff --git a/packages/amplify-graphql-transformer-migrator/src/schema-migrator.ts b/packages/amplify-graphql-transformer-migrator/src/schema-migrator.ts deleted file mode 100644 index 6f6ff5f311..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/schema-migrator.ts +++ /dev/null @@ -1,225 +0,0 @@ -import * as path from 'path'; -import * as os from 'os'; -import * as fs from 'fs-extra'; -import { Kind, parse, print, visit } from 'graphql'; -import { DocumentNode } from 'graphql/language'; -import { printer, prompter } from '@aws-amplify/amplify-prompts'; -import { validateModelSchema, SchemaValidationError } from '@aws-amplify/graphql-transformer-core'; -import * as glob from 'glob'; -import { migrateKeys } from './migrators/key'; -import { migrateAuth } from './migrators/auth'; -import { migrateConnection } from './migrators/connection'; -import { combineSchemas, getDefaultAuth, replaceFile, SchemaDocument } from './utils'; -import { - authRuleUsesQueriesOrMutations, - detectCustomRootTypes, - detectDeprecatedConnectionUsage, - detectOverriddenResolvers, - detectPassthroughDirectives, - graphQLUsingSQL, -} from './schema-inspector'; -import { backupCliJson, revertTransformerVersion, updateTransformerVersion } from './state-migrator'; -import { GRAPHQL_DIRECTIVES_SCHEMA } from './constants/graphql-directives'; -import { backupLocation, backupSchemas, doesBackupExist, restoreSchemas } from './schema-backup'; - -const cliToMigratorAuthMap: Map = new Map([ - ['API_KEY', 'apiKey'], - ['AWS_IAM', 'iam'], - ['AMAZON_COGNITO_USER_POOLS', 'userPools'], - ['OPENID_CONNECT', 'oidc'], -]); - -const MIGRATION_DOCS_URL = 'https://docs.amplify.aws/cli/migration/transformer-migration/'; - -export async function attemptV2TransformerMigration( - resourceDir: string, - apiName: string, - featureFlags: { transformerVersion: number; improvePluralization: boolean }, - envName?: string, -): Promise { - const schemaDocs = await getSchemaDocs(resourceDir); - const fullSchema = combineSchemas(schemaDocs); - const { transformerVersion, improvePluralization } = featureFlags; - const autoMigrationDetectionResult = await canAutoMigrate(fullSchema, apiName, resourceDir, transformerVersion); - const postMigrationStatusMessage = await getPostMigrationStatusMessage(fullSchema, apiName, improvePluralization); - - if (typeof autoMigrationDetectionResult === 'string') { - printer.info(autoMigrationDetectionResult); - return; - } - - const defaultAuth = await getDefaultAuth(); - const authMode = cliToMigratorAuthMap.get(defaultAuth); - if (!authMode) { - throw Error(`Unidentified authorization mode for API found: ${defaultAuth}`); - } - - if (schemaHasComments(fullSchema)) { - printer.warn( - `Warning: The migration will not carry over any existing comments in your GraphQL schema, you'll be able to manually copy them in from the back-ups stored at ${backupLocation( - resourceDir, - )}.`, - ); - } - - try { - await backupSchemas(resourceDir); - await backupCliJson(resourceDir, envName); - await runMigration(schemaDocs, authMode); - await updateTransformerVersion(envName); - } catch (error) { - printer.error('Error encountered migrating schemas'); - printer.info('Restoring original schemas'); - try { - await runRevert(resourceDir, envName); - } catch (undoError) { - printer.error('Error encountered restoring original schemas:'); - printer.info(error); - } - throw error; - } - printer.success('Automatic migration complete!'); - printer.info(`Original schemas are backed up at ${backupLocation(resourceDir)}`); - printer.info(postMigrationStatusMessage); - printer.info(`More migration instructions can be found at ${MIGRATION_DOCS_URL}`); - printer.info(`To revert the migration run 'amplify migrate api --revert'`); -} - -export async function revertV2Migration(resourceDir: string, envName: string) { - if (!doesBackupExist(resourceDir)) { - printer.error(`No backup found at ${backupLocation(resourceDir)}`); - return; - } - printer.warn( - 'Reverting migration will restore all schemas to their state before `amplify migrate api`. This will wipe out any schema changes you have made since migrating.', - ); - if (!(await prompter.confirmContinue())) { - return; - } - await runRevert(resourceDir, envName); -} - -export async function runMigration(schemas: SchemaDocument[], authMode: string): Promise { - const schemaList = schemas.map((doc) => doc.schema); - - const fullSchema = schemaList.join('\n'); - const fullSchemaNode = parse(fullSchema); - doSchemaValidation(fullSchema); - - const newSchemaList: SchemaDocument[] = new Array(); - for (const doc of schemas) { - const newSchema = await migrateGraphQLSchema(doc.schema, authMode, fullSchemaNode); - newSchemaList.push({ schema: newSchema, filePath: doc.filePath }); - } - - await Promise.all(newSchemaList.map((doc) => replaceFile(doc.schema, doc.filePath))); -} - -/** - * Exported for testing - */ -export function migrateGraphQLSchema(schema: string, authMode: string, massSchema: DocumentNode): string { - let output = parse(schema); - visit(output, { - ObjectTypeDefinition: { - enter(node) { - migrateKeys(node); - migrateAuth(node, authMode); - migrateConnection(node, massSchema); - return node; - }, - }, - }); - - return print(output); -} - -async function runRevert(resourceDir: string, envName?: string) { - await restoreSchemas(resourceDir); - await revertTransformerVersion(resourceDir, envName); -} - -function doSchemaValidation(schema: string) { - const appendedSchema = schema + GRAPHQL_DIRECTIVES_SCHEMA; - const parsedSchema = parse(appendedSchema); - - let allModelDefinitions = [...parsedSchema.definitions]; - const errors = validateModelSchema({ kind: Kind.DOCUMENT, definitions: allModelDefinitions }); - if (errors && errors.length) { - throw new SchemaValidationError(errors); - } -} - -const getSchemaDocs = async (resourceDir: string): Promise => { - const schemaFilePath = path.join(resourceDir, 'schema.graphql'); - const schemaDirectoryPath = path.join(resourceDir, 'schema'); - const schemaFileExists = fs.existsSync(schemaFilePath); - const schemaDirectoryExists = fs.existsSync(schemaDirectoryPath); - - if (!schemaFileExists && !schemaDirectoryExists) { - return []; - } - if (schemaFileExists) { - return [{ schema: await fs.readFile(schemaFilePath, 'utf8'), filePath: schemaFilePath }]; - } else if (schemaDirectoryExists) { - const schemaFiles = glob.sync('**/*.graphql', { cwd: schemaDirectoryPath }).map((fileName) => path.join(schemaDirectoryPath, fileName)); - return await Promise.all(schemaFiles.map(async (fileName) => ({ schema: await fs.readFile(fileName, 'utf8'), filePath: fileName }))); - } - return []; -}; - -function schemaHasComments(fullSchema: string): boolean { - return /#/.test(fullSchema); -} - -// returns true if the project can be auto-migrated to v2, or a message explaining why the project cannot be auto-migrated -async function canAutoMigrate( - fullSchema: string, - apiName: string, - resourceDir: string, - transformerVersion: number, -): Promise { - if (graphQLUsingSQL(apiName)) { - return 'GraphQL APIs using Aurora RDS cannot be migrated.'; - } - if (transformerVersion === 2) { - return 'GraphQL Transformer version 2 is already enabled. No migration is necessary.'; - } - if (detectDeprecatedConnectionUsage(fullSchema)) { - return 'You are using the deprecated parameterization of @connection which cannot be automatically migrated.'; - } - if (doesBackupExist(resourceDir)) { - return `A schema backup already exists at ${backupLocation(resourceDir)}. Remove or copy these files to a different location.`; - } - if (authRuleUsesQueriesOrMutations(fullSchema)) { - return 'You are using queries or mutations in at least one @auth rule. These cannot be automatically migrated.'; - } - return true; -} - -async function getPostMigrationStatusMessage(fullSchema: string, apiName: string, improvePluralization: boolean): Promise { - const usingCustomRootTypes = detectCustomRootTypes(parse(fullSchema)); - const usingOverriddenResolvers = detectOverriddenResolvers(apiName); - const passthroughDirectives: Array = await detectPassthroughDirectives(fullSchema); - if (!usingCustomRootTypes && !usingOverriddenResolvers && passthroughDirectives.length === 0 && improvePluralization) { - return ''; - } - const messageLines = [ - 'The following project state(s) were detected which may need additional attention to ensure they continue to work as expected with the new GraphQL transformer', - ]; - if (usingCustomRootTypes) { - messageLines.push('- You have defined custom Queries, Mutations, and/or Subscriptions in your GraphQL schema'); - } - if (usingOverriddenResolvers) { - messageLines.push('- You have overridden an Amplify generated resolver'); - } - if (passthroughDirectives.length > 0) { - messageLines.push( - `- You are using the following directives which are not handled by the transformer:${os.EOL}\t${passthroughDirectives.join(', ')}`, - ); - } - if (!improvePluralization) { - messageLines.push('- You do not have the "improvePluralization" Feature Flag enabled'); - } - return messageLines.join(os.EOL); -} diff --git a/packages/amplify-graphql-transformer-migrator/src/state-migrator.ts b/packages/amplify-graphql-transformer-migrator/src/state-migrator.ts deleted file mode 100644 index af16b6285d..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/state-migrator.ts +++ /dev/null @@ -1,57 +0,0 @@ -import * as path from 'path'; -import * as fs from 'fs-extra'; -import _ from 'lodash'; -import { FeatureFlags, JSONUtilities, pathManager, stateManager } from '@aws-amplify/amplify-cli-core'; - -export const backupLocation = (resourceDir: string) => path.join(resourceDir, '.migration-config-backup'); - -export const updateTransformerVersion = async (env?: string): Promise => { - const mutation = (cliJSON: any) => { - _.set(cliJSON, ['features', 'graphqltransformer', 'useexperimentalpipelinedtransformer'], true); - _.set(cliJSON, ['features', 'graphqltransformer', 'transformerversion'], 2); - _.set(cliJSON, ['features', 'graphqltransformer', 'suppressschemamigrationprompt'], true); - _.set(cliJSON, ['features', 'codegen', 'useappsyncmodelgenplugin'], true); - }; - await mutateCliJsonFile(mutation, env); -}; - -export const backupCliJson = async (resourceDir: string, env?: string): Promise => { - const cliJson = getCliJsonFile(env); - const backupPath = path.join(backupLocation(resourceDir), 'cli.json'); - JSONUtilities.writeJson(backupPath, cliJson); -}; - -export const revertTransformerVersion = async (resourceDir: string, env?: string): Promise => { - const backupPath = path.join(backupLocation(resourceDir), 'cli.json'); - const backupJson: any = JSONUtilities.readJson(backupPath); - const mutation = (cliJson: any) => { - _.set(cliJson, ['features'], backupJson['features']); - }; - await mutateCliJsonFile(mutation, env); - fs.removeSync(backupLocation(resourceDir)); -}; - -const mutateCliJsonFile = async (mutation: (cliObj: any) => void, env?: string): Promise => { - const projectPath = pathManager.findProjectRoot() ?? process.cwd(); - let envCLI = true; - let cliJSON; - if (env) { - cliJSON = stateManager.getCLIJSON(projectPath, env, { throwIfNotExist: false }); - } - if (!cliJSON) { - envCLI = false; - cliJSON = stateManager.getCLIJSON(projectPath); - } - mutation(cliJSON); - stateManager.setCLIJSON(projectPath, cliJSON, envCLI ? env : undefined); - await FeatureFlags.reloadValues(); -}; - -const getCliJsonFile = (env?: string): Promise => { - const projectPath = pathManager.findProjectRoot() ?? process.cwd(); - let cliJSON; - if (env) { - cliJSON = stateManager.getCLIJSON(projectPath, env, { throwIfNotExist: false }); - } - return cliJSON ?? stateManager.getCLIJSON(projectPath); -}; diff --git a/packages/amplify-graphql-transformer-migrator/src/utils.ts b/packages/amplify-graphql-transformer-migrator/src/utils.ts deleted file mode 100644 index b36685fa82..0000000000 --- a/packages/amplify-graphql-transformer-migrator/src/utils.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { stateManager } from '@aws-amplify/amplify-cli-core'; -import * as fs from 'fs-extra'; -import _ from 'lodash'; - -export type SchemaDocument = { - schema: string; - filePath: string; -}; - -export type DiffDocument = { - schemaDiff: string; - filePath: string; -}; - -export async function replaceFile(newSchema: string, filePath: string): Promise { - await fs.writeFile(filePath, newSchema, { encoding: 'utf-8', flag: 'w' }); -} - -export function combineSchemas(schemaDocs: SchemaDocument[]): string { - let schemaList: string[] = new Array(schemaDocs.length); - schemaDocs.forEach((doc, idx) => { - schemaList[idx] = doc.schema; - }); - - return schemaList.join('\n'); -} - -export async function getDefaultAuth(): Promise { - const backendConfig = stateManager.getBackendConfig(); - - // Only support one GraphQL API, so grab the ID - const [gqlAPI] = _.filter(backendConfig.api, (api: Record) => api.service === 'AppSync'); - - if (!gqlAPI) { - return 'AMAZON_COGNITO_USER_POOLS'; - } - return gqlAPI.output.authConfig.defaultAuthentication.authenticationType; -} - -export function listContainsOnlySetString(list: Array, set: Set): Array { - return list.filter((str) => { - return !set.has(str); - }); -} diff --git a/packages/amplify-graphql-transformer-migrator/tsconfig.json b/packages/amplify-graphql-transformer-migrator/tsconfig.json deleted file mode 100644 index 700094d05e..0000000000 --- a/packages/amplify-graphql-transformer-migrator/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "rootDir": "src", - "outDir": "lib" - }, - "references": [ - { - "path": "../amplify-graphql-transformer-interfaces" - } - ], - "include": ["src"] -} diff --git a/packages/amplify-util-mock/.gitignore b/packages/amplify-util-mock/.gitignore deleted file mode 100644 index 4ea619fb38..0000000000 --- a/packages/amplify-util-mock/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -lib -coverage -reports \ No newline at end of file diff --git a/packages/amplify-util-mock/.npmignore b/packages/amplify-util-mock/.npmignore deleted file mode 100644 index d8a7ec01f9..0000000000 --- a/packages/amplify-util-mock/.npmignore +++ /dev/null @@ -1,6 +0,0 @@ -**/__mocks__/** -**/__tests__/** -**/__e2e__/** -src -tsconfig.json -tsconfig.tsbuildinfo diff --git a/packages/amplify-util-mock/API.md b/packages/amplify-util-mock/API.md deleted file mode 100644 index 737687e4ee..0000000000 --- a/packages/amplify-util-mock/API.md +++ /dev/null @@ -1,15 +0,0 @@ -## API Report File for "amplify-category-api-util-mock" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -// @public (undocumented) -export function executeAmplifyCommand(context: any): Promise; - -// @public (undocumented) -export function handleAmplifyEvent(context: any, args: any): Promise; - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/amplify-util-mock/Readme.md b/packages/amplify-util-mock/Readme.md deleted file mode 100644 index 63b01f3192..0000000000 --- a/packages/amplify-util-mock/Readme.md +++ /dev/null @@ -1,16 +0,0 @@ -# Amplify CLI Mocking Plugin - -Mock Util plugin provides support for running API and storage servers locally on developers computer before pushing resources to the cloud. - -Mocking is intended for testing only, and should not be utilized for production workloads - -## Commands Summary - -The current set of commands supported by the Amplify Mock Util Plugin - -| Command | Description | -| --------------------- | ------------------------------------------------------- | -| amplify mock | Run mock server for supported categories | -| amplify mock api | Run mock GraphQL server to simulate AppSync | -| amplify mock function | Locally test/invoke the function in your local backend. | -| amplify mock storage | Run mock server to simulate S3 | diff --git a/packages/amplify-util-mock/amplify-plugin.json b/packages/amplify-util-mock/amplify-plugin.json deleted file mode 100644 index 16fb42f48f..0000000000 --- a/packages/amplify-util-mock/amplify-plugin.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "mock", - "type": "util", - "commands": ["api", "function", "mock", "storage", "help"], - "eventHandlers": [] -} diff --git a/packages/amplify-util-mock/src/CFNParser/appsync-resource-processor.ts b/packages/amplify-util-mock/src/CFNParser/appsync-resource-processor.ts deleted file mode 100644 index aa3005ee51..0000000000 --- a/packages/amplify-util-mock/src/CFNParser/appsync-resource-processor.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { AmplifyAppSyncSimulatorAuthenticationType, AmplifyAppSyncSimulatorConfig } from '@aws-amplify/amplify-appsync-simulator'; -import { - registerAppSyncResourceProcessor, - registerIAMResourceProcessor, - registerLambdaResourceProcessor, - registerOpenSearchResourceProcessor, -} from './resource-processors'; -import { AppSyncAPIKeyProcessedResource, AppSyncAPIProcessedResource } from './resource-processors/appsync'; -import { processCloudFormationStack } from './stack/index'; -import { CloudFormationTemplateFetcher, CloudFormationTemplate } from './stack/types'; - -const CFN_DEFAULT_PARAMS = { - 'AWS::Region': 'us-east-1-fake', - 'AWS::AccountId': '12345678910', - 'AWS::StackId': 'fake-stackId', - 'AWS::StackName': 'local-testing', - 'AWS::URLSuffix': 'amazonaws.com', -}; - -const RESOLVER_TEMPLATE_LOCATION_PREFIX = 's3://${S3DeploymentBucket}/${S3DeploymentRootKey}/'; - -export function processApiResources( - resources: Record, - transformResult: any, - appSyncConfig: AmplifyAppSyncSimulatorConfig, -): void { - Object.values(resources).forEach((resource) => { - const { Type: resourceType } = resource; - const result: any = resource.result; - - switch (resourceType) { - case 'AWS::AppSync::DataSource': - appSyncConfig.dataSources.push(result); - break; - case 'AWS::AppSync::Resolver': - appSyncConfig.resolvers.push({ - ...result, - requestMappingTemplateLocation: - result.requestMappingTemplateLocation && result.requestMappingTemplateLocation.replace(RESOLVER_TEMPLATE_LOCATION_PREFIX, ''), - responseMappingTemplateLocation: - result.responseMappingTemplateLocation && result.responseMappingTemplateLocation.replace(RESOLVER_TEMPLATE_LOCATION_PREFIX, ''), - }); - break; - case 'AWS::DynamoDB::Table': - appSyncConfig.tables.push(result); - break; - case 'AWS::AppSync::FunctionConfiguration': - appSyncConfig.functions.push({ - ...result, - requestMappingTemplateLocation: - result.requestMappingTemplateLocation && result.requestMappingTemplateLocation.replace(RESOLVER_TEMPLATE_LOCATION_PREFIX, ''), - responseMappingTemplateLocation: - result.responseMappingTemplateLocation && result.responseMappingTemplateLocation.replace(RESOLVER_TEMPLATE_LOCATION_PREFIX, ''), - }); - break; - case 'AWS::AppSync::GraphQLSchema': - if (result.definition) { - appSyncConfig.schema = { content: result.definition }; - } else { - appSyncConfig.schema = { path: 'schema.graphql', content: transformResult.schema }; - } - - break; - case 'AWS::AppSync::GraphQLApi': { - const resource = result as AppSyncAPIProcessedResource; - appSyncConfig.appSync.name = resource.name; - appSyncConfig.appSync.defaultAuthenticationType = resource.defaultAuthenticationType; - appSyncConfig.appSync.additionalAuthenticationProviders = resource.additionalAuthenticationProviders || []; - break; - } - case 'AWS::AppSync::ApiKey': - appSyncConfig.appSync.apiKey = (result as AppSyncAPIKeyProcessedResource).ApiKey; - break; - case 'AWS::CloudFormation::Stack': - processApiResources(result.resources, transformResult, appSyncConfig); - break; - } - }); -} -export function processCloudFormationResults(resources, transformResult) { - const processedResources: AmplifyAppSyncSimulatorConfig = { - schema: { - content: '', - }, - resolvers: [], - functions: [], - dataSources: [], - mappingTemplates: [], - tables: [], - appSync: { - name: '', - defaultAuthenticationType: { - authenticationType: AmplifyAppSyncSimulatorAuthenticationType.API_KEY, - }, - apiKey: null, - additionalAuthenticationProviders: [], - }, - }; - - processApiResources(resources, transformResult, processedResources); - Object.entries(transformResult.resolvers).forEach(([path, content]) => { - processedResources.mappingTemplates.push({ - path: `resolvers/${path}`, - content: content as string, - }); - }); - Object.entries(transformResult.pipelineFunctions).forEach(([path, content]) => { - processedResources.mappingTemplates.push({ - path: `pipelineFunctions/${path}`, - content: content as string, - }); - }); - - return processedResources; -} -export function processTransformerStacks(transformResult, params = {}): AmplifyAppSyncSimulatorConfig { - registerAppSyncResourceProcessor(); - registerIAMResourceProcessor(); - registerLambdaResourceProcessor(); - registerOpenSearchResourceProcessor(); - - const rootStack = JSON.parse(JSON.stringify(transformResult.rootStack)); // rootstack is not - const cfnParams = { - ...CFN_DEFAULT_PARAMS, - env: '${env}', - S3DeploymentBucket: '${S3DeploymentBucket}', - S3DeploymentRootKey: '${S3DeploymentRootKey}', - CreateAPIKey: 1, - ...params, - }; - - const cfnTemplateFetcher: CloudFormationTemplateFetcher = { - getCloudFormationStackTemplate: (templateName: string): CloudFormationTemplate => { - const templateRegex = new RegExp('^https://s3.(.+\\.)?amazonaws.com/\\${S3DeploymentBucket}/\\${S3DeploymentRootKey}/stacks/'); - const template = templateName.replace(templateRegex, ''); - const stackTemplate = Object.keys(transformResult.stacks).includes(template) - ? transformResult.stacks[template] - : transformResult.stacks[template.replace('.json', '')]; - if (stackTemplate && typeof stackTemplate === 'undefined') { - throw new Error(`Invalid cloud formation template ${templateName}`); - } - return stackTemplate; - }, - }; - - const processedStacks = processCloudFormationStack( - rootStack, - { authRoleName: 'authRole', unauthRoleName: 'unAuthRole', ...cfnParams }, - {}, - cfnTemplateFetcher, - ); - return processCloudFormationResults(processedStacks.resources, transformResult); -} diff --git a/packages/amplify-util-mock/src/CFNParser/field-parser.ts b/packages/amplify-util-mock/src/CFNParser/field-parser.ts deleted file mode 100644 index 8da10189ad..0000000000 --- a/packages/amplify-util-mock/src/CFNParser/field-parser.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { isPlainObject } from 'lodash'; -import { CloudFormationParseContext } from './types'; - -import { - cfnAnd, - cfnCondition, - cfnEquals, - cfnGetAtt, - cfnIf, - cfnJoin, - cfnNot, - cfnOr, - cfnRef, - cfnSelect, - cfnSplit, - cfnSub, - cfnImportValue, -} from './intrinsic-functions'; - -const intrinsicFunctionMap = { - 'Fn::Join': cfnJoin, - 'Fn::Sub': cfnSub, - 'Fn::GetAtt': cfnGetAtt, - 'Fn::Split': cfnSplit, - Ref: cfnRef, - 'Fn::Select': cfnSelect, - 'Fn::If': cfnIf, - 'Fn::Equals': cfnEquals, - 'Fn::And': cfnAnd, - 'Fn::Or': cfnOr, - 'Fn::Not': cfnNot, - Condition: cfnCondition, - 'Fn::ImportValue': cfnImportValue, -}; - -export function parseValue(node, context: CloudFormationParseContext) { - if (['string', 'number'].includes(typeof node)) return node; - - // convert object to plain object - node = JSON.parse(JSON.stringify(node)); - if (isPlainObject(node) && Object.keys(node).length === 1 && Object.keys(intrinsicFunctionMap).includes(Object.keys(node)[0])) { - const op = Object.keys(node)[0]; - const valNode = node[op]; - return intrinsicFunctionMap[op](valNode, context, parseValue); - } - throw new Error(`Could not process value node ${JSON.stringify(node)}`); -} diff --git a/packages/amplify-util-mock/src/CFNParser/import-model-table-resolver.ts b/packages/amplify-util-mock/src/CFNParser/import-model-table-resolver.ts deleted file mode 100644 index aefac34fad..0000000000 --- a/packages/amplify-util-mock/src/CFNParser/import-model-table-resolver.ts +++ /dev/null @@ -1,19 +0,0 @@ -const matcher = new RegExp('(?.+):GetAtt:(?.+)Table:Name'); - -/** - * Resolves Fn::ImportValue instances that reference a table generated by @model - * - * This is a bit of a hack. The "right" way to do it would be to load the physical ids of the tables as exports - * and pass that context in when parsing the stacks but we don't currently have a good way to resolve those physical ids - * before processing the stacks - * @param val The input to Fn::ImportValue - * @param env The current environment - * @returns if val matches the expected pattern, the expected export value of the table; otherwise val - */ -export const importModelTableResolver = (val: string, env: string): string => { - const match = matcher.exec(val); - if (!match) { - return val; - } - return [match.groups.modelName, match.groups.apiId, env].join('-'); -}; diff --git a/packages/amplify-util-mock/src/CFNParser/index.ts b/packages/amplify-util-mock/src/CFNParser/index.ts deleted file mode 100644 index d7f0ecf98c..0000000000 --- a/packages/amplify-util-mock/src/CFNParser/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { processTransformerStacks as processAppSyncResources } from './appsync-resource-processor'; diff --git a/packages/amplify-util-mock/src/CFNParser/intrinsic-functions.ts b/packages/amplify-util-mock/src/CFNParser/intrinsic-functions.ts deleted file mode 100644 index 59fe16dda1..0000000000 --- a/packages/amplify-util-mock/src/CFNParser/intrinsic-functions.ts +++ /dev/null @@ -1,210 +0,0 @@ -import { isPlainObject } from 'lodash'; -import { CloudFormationParseContext } from './types'; -import { importModelTableResolver } from './import-model-table-resolver'; - -export function cfnJoin(valNode: [string, string[]], { params, conditions, resources, exports }: CloudFormationParseContext, processValue) { - if (!(Array.isArray(valNode) && valNode.length === 2 && Array.isArray(valNode[1]))) { - throw new Error(`FN::Join expects an array with 2 elements instead got ${JSON.stringify(valNode)}`); - } - const delimiter = valNode[0]; - const items = valNode[1].map((item) => processValue(item, { params, conditions, resources, exports })); - return items.join(delimiter); -} - -export function cfnSub(valNode, { params, conditions, resources, exports }: CloudFormationParseContext, processValue) { - if (typeof valNode === 'string') { - return templateReplace(valNode, params); - } - if (!Array.isArray(valNode) && valNode.length !== 2) { - throw new Error(`FN::Sub expects an array with 2 elements instead got ${JSON.stringify(valNode)}`); - } - const strTemplate = valNode[0]; - const subs = valNode[1]; - - if (typeof strTemplate !== 'string') { - throw new Error(`FN::Sub expects template to be an a string instead got ${JSON.stringify(strTemplate)}`); - } - if (!isPlainObject(subs)) { - throw new Error(`FN::Sub expects substitution to be an object instead got ${JSON.stringify(subs)}`); - } - const subValues = {}; - Object.entries(subs).forEach(([key, value]) => { - subValues[key] = processValue(value, { - params, - conditions, - resources, - exports, - }); - }); - - const result = Object.entries(subValues).reduce((template, entry: any) => { - const regExp = new RegExp(`\\$\\{${entry[0]}\\}`, 'g'); - return template.replace(regExp, entry[1]); - }, strTemplate); - return result; -} - -function templateReplace(template: string, args: any = {}) { - return template.replace(/\${(\w+)}/g, (a, v) => { - if (v in args) return args[v]; - return a; - }); -} - -export function cfnGetAtt(valNode, { resources }: CloudFormationParseContext, processValue) { - if (!Array.isArray(valNode) && valNode.length !== 2) { - throw new Error(`FN::GetAtt expects an array with 2 elements instead got ${JSON.stringify(valNode)}`); - } - const resourceName = valNode[0]; - if (!Object.keys(resources).includes(resourceName)) { - throw new Error(`Could not get resource ${valNode[0]}`); - } - const selectedResource = resources[resourceName]; - const attributeName = valNode[1]; - if (selectedResource.Type === 'AWS::CloudFormation::Stack') { - const attrSplit = attributeName.split('.'); - - if (attrSplit.length === 2 && attrSplit[0] === 'Outputs' && Object.keys(selectedResource.result.outputs).includes(attrSplit[1])) { - return selectedResource.result.outputs[attrSplit[1]]; - } else { - // todo: investigate handling more cases when ref is directly the resource name etx - throw new Error(`Could not get attribute ${attributeName} from resource ${resourceName}`); - } - } else if (!selectedResource.result.cfnExposedAttributes) { - throw new Error(`No attributes are exposed to Fn::GetAtt on resource type ${selectedResource.Type}`); - } - if (!Object.keys(selectedResource.result.cfnExposedAttributes).includes(attributeName)) { - throw new Error(`Attribute ${attributeName} is not exposed to Fn::GetAtt on resource ${selectedResource.Type}`); - } - const effectiveAttrKey = selectedResource.result.cfnExposedAttributes[attributeName]; - if (!Object.keys(selectedResource.result).includes(effectiveAttrKey)) { - throw new Error(`Could not get attribute ${attributeName} on resource ${resourceName}`); - } - return selectedResource.result[effectiveAttrKey]; -} - -export function cfnSplit(valNode, { params, conditions, resources, exports }: CloudFormationParseContext, processValue) { - if (!Array.isArray(valNode) && valNode.length !== 2) { - throw new Error(`FN::Split expects an array with 2 elements instead got ${JSON.stringify(valNode)}`); - } - const delim: string = valNode[0]; - const str: string = processValue(valNode[1], { - params, - conditions, - resources, - exports, - }); - return str.split(delim); -} - -export function cfnRef(valNode, { params, resources }: CloudFormationParseContext, processValue) { - let key; - if (typeof valNode === 'string') { - key = valNode; - } else if (Array.isArray(valNode) && valNode.length === 1) { - key = processValue(valNode[0]); - } else { - throw new Error(`Ref expects a string or an array with 1 item. Instead got ${JSON.stringify(valNode)}`); - } - - if (params.hasOwnProperty(key)) { - return params[key]; - } - - if (Object.keys(resources).includes(key)) { - const result = resources[key]?.result ?? {}; - const refKey = Object.keys(result).find((k) => k.toLowerCase() === 'ref'); - if (!refKey) { - throw new Error(`Ref is missing in resource ${key}`); - } - return result[refKey]; - } - console.warn(`Could not find ref for ${JSON.stringify(valNode)}. Using unsubstituted value.`); - return key; -} - -export function cfnSelect(valNode, parseContext: CloudFormationParseContext, processValue) { - if (!Array.isArray(valNode) && valNode.length !== 2) { - throw new Error(`FN::Select expects an array with 2 elements instead got ${JSON.stringify(valNode)}`); - } - - const index = parseInt(valNode[0], 10); - const selectionList = Array.isArray[valNode[1]] ? valNode[1] : processValue(valNode[1], parseContext); - if (!Array.isArray(selectionList)) { - throw new Error(`FN::Select expects list item to be an array instead got ${JSON.stringify(selectionList)}`); - } - if (index >= selectionList.length) { - throw new Error(`FN::Select expects index to be less than or equal to the length of list: ${JSON.stringify(selectionList)}`); - } - return processValue(selectionList[index]); -} - -export function cfnIf(valNode, { params, conditions, resources, exports }: CloudFormationParseContext, processValue) { - if (!Array.isArray(valNode) && valNode.length !== 3) { - throw new Error(`FN::If expects an array with 3 elements instead got ${JSON.stringify(valNode)}`); - } - const condition = conditions[valNode[0]]; - const result = condition ? valNode[1] : valNode[2]; - if (result.Ref && result.Ref === 'AWS::NoValue') { - return undefined; - } - return processValue(result, { params, condition, resources, exports }); -} - -export function cfnEquals(valNode, { params, conditions, resources, exports }: CloudFormationParseContext, processValue) { - if (!Array.isArray(valNode) && valNode.length !== 2) { - throw new Error(`FN::Equal expects an array with 2 elements instead got ${JSON.stringify(valNode)}`); - } - const lhs = processValue(valNode[0], { - params, - conditions, - resources, - exports, - }); - const rhs = processValue(valNode[1], { - params, - conditions, - resources, - exports, - }); - return lhs == rhs; -} - -export function cfnNot(valNode, { params, conditions, resources, exports }: CloudFormationParseContext, processValue) { - if (!Array.isArray(valNode) && valNode.length !== 1) { - throw new Error(`FN::Not expects an array with 1 element instead got ${JSON.stringify(valNode)}`); - } - return !processValue(valNode[0], { params, conditions, resources, exports }); -} - -export function cfnAnd(valNode, { params, conditions, resources, exports }: CloudFormationParseContext, processValue) { - if (!Array.isArray(valNode) && !(valNode.length >= 2 && valNode.length <= 10)) { - throw new Error(`FN::And expects an array with 2-10 elements instead got ${JSON.stringify(valNode)}`); - } - return valNode.map((val) => processValue(val, { params, conditions, resources, exports })).every((val) => !!val); -} - -export function cfnOr(valNode, { params, conditions, resources, exports }: CloudFormationParseContext, processValue) { - if (!Array.isArray(valNode) && !(valNode.length >= 2 && valNode.length <= 10)) { - throw new Error(`FN::And expects an array with 2-10 elements instead got ${JSON.stringify(valNode)}`); - } - return valNode.map((val) => processValue(val, { params, conditions, resources, exports })).some((val) => !!val); -} - -export function cfnImportValue(valNode, { params, conditions, resources, exports }: CloudFormationParseContext, processValue) { - if (!(isPlainObject(valNode) || typeof valNode === 'string')) { - throw new Error(`FN::ImportValue expects an array with 1 elements instead got ${JSON.stringify(valNode)}`); - } - const key = processValue(valNode, { params, conditions, resources, exports }); - return exports[key] ?? importModelTableResolver(key, params.env); -} - -export function cfnCondition(valNode, { conditions }: CloudFormationParseContext, processValue) { - if (typeof valNode !== 'string') { - throw new Error(`Condition should be a string value, instead got ${JSON.stringify(valNode)}`); - } - if (!(valNode in conditions)) { - throw new Error(`Condition ${valNode} not present in conditions`); - } - return conditions[valNode]; -} diff --git a/packages/amplify-util-mock/src/CFNParser/resource-processors/appsync.ts b/packages/amplify-util-mock/src/CFNParser/resource-processors/appsync.ts deleted file mode 100644 index cc7b1f8225..0000000000 --- a/packages/amplify-util-mock/src/CFNParser/resource-processors/appsync.ts +++ /dev/null @@ -1,265 +0,0 @@ -import { parseValue } from '../field-parser'; -import { CloudFormationProcessedResourceResult } from '../stack/types'; -import { CloudFormationParseContext } from '../types'; - -export function dynamoDBResourceHandler(resourceName, resource, cfnContext: CloudFormationParseContext) { - const tableName = resourceName; - const gsis = (resource.Properties.GlobalSecondaryIndexes || []).map((gsi) => { - const p = { ...gsi }; - delete p.ProvisionedThroughput; - return p; - }); - const processedResource: any = { - cfnExposedAttributes: { Arn: 'Arn', StreamArn: 'StreamArn' }, - Arn: `arn:aws:dynamodb:us-east-2:123456789012:table/${tableName}`, - Ref: tableName, - StreamArn: `arn:aws:dynamodb:{aws-region}:{aws-account-number}:table/${tableName}/stream/${new Date().toISOString()}`, - Properties: { - TableName: tableName, - BillingMode: 'PAY_PER_REQUEST', - KeySchema: resource.Properties.KeySchema, - AttributeDefinitions: resource.Properties.AttributeDefinitions, - }, - }; - - if (resource.Properties.LocalSecondaryIndexes) { - processedResource.Properties.LocalSecondaryIndexes = resource.Properties.LocalSecondaryIndexes; - } - - if (gsis.length) { - processedResource.Properties.GlobalSecondaryIndexes = gsis; - } - return processedResource; -} - -export type AppSyncDataSourceProcessedResource = CloudFormationProcessedResourceResult & { - name: string; - type: 'AMAZON_DYNAMODB' | 'AWS_LAMBDA' | 'AMAZON_ELASTICSEARCH' | 'NONE'; - LambdaFunctionArn?: string; - config?: { - tableName: string; - }; -}; -export function appSyncDataSourceHandler( - resourceName, - resource, - cfnContext: CloudFormationParseContext, -): AppSyncDataSourceProcessedResource { - const tableName = resource.Properties?.DynamoDBConfig?.TableName?.Ref || resource.Properties.Name; - const typeName = resource.Properties.Type; - const commonProps = { - cfnExposedAttributes: { DataSourceArn: 'Arn', Name: 'name' }, - Arn: `arn:aws:appsync:us-fake-1:123456789012:apis/graphqlapiid/datasources/${resource.Properties.Name}`, - }; - if (typeName === 'AMAZON_DYNAMODB') { - return { - ...commonProps, - name: tableName, - type: 'AMAZON_DYNAMODB', - config: { - tableName, - }, - }; - } - if (typeName === 'NONE') { - return { - ...commonProps, - name: resource.Properties.Name, - type: 'NONE', - }; - } - - if (typeName === 'AWS_LAMBDA') { - const lambdaArn = parseValue(resource.Properties.LambdaConfig.LambdaFunctionArn, cfnContext); - return { - ...commonProps, - type: 'AWS_LAMBDA', - name: resource.Properties.Name, - LambdaFunctionArn: lambdaArn, - }; - } - - if (typeName === 'AMAZON_ELASTICSEARCH') { - console.log(`@searchable mocking is not supported. Search queries will not work as expected.`); - - return { - ...commonProps, - type: 'AMAZON_ELASTICSEARCH', - name: resource.Properties.Name, - }; - } - - console.log(`Data source of type ${typeName} is not supported by local mocking. A NONE data source will be used.`); - return { - ...commonProps, - name: resourceName, - type: 'NONE', - }; -} - -export type AppSyncAPIProcessedResource = CloudFormationProcessedResourceResult & { - name: string; - Ref: string; - Arn: string; - defaultAuthenticationType: any; - ApiId: string; - GraphQLUrl: string; - additionalAuthenticationProviders: any; -}; -export function appSyncAPIResourceHandler(resourceName, resource, cfnContext: CloudFormationParseContext): AppSyncAPIProcessedResource { - const apiId = 'amplify-test-api-id'; - const processedResource = { - cfnExposedAttributes: { ApiId: 'ApiId', Arn: 'Arn', GraphQLUrl: 'GraphQLUrl' }, - name: cfnContext.params.AppSyncApiName || 'AppSyncTransformer', - defaultAuthenticationType: { - authenticationType: resource.Properties.AuthenticationType, - ...(resource.Properties.OpenIDConnectConfig ? { openIDConnectConfig: resource.Properties.OpenIDConnectConfig } : {}), - ...(resource.Properties.UserPoolConfig ? { cognitoUserPoolConfig: resource.Properties.UserPoolConfig } : {}), - }, - Ref: `arn:aws:appsync:us-east-1:123456789012:apis/${apiId}`, - Arn: `arn:aws:appsync:us-east-1:123456789012:apis/${apiId}`, - ApiId: apiId, - GraphQLUrl: 'http://localhost:20002/', - ...(resource.Properties.AdditionalAuthenticationProviders - ? { - additionalAuthenticationProviders: resource.Properties.AdditionalAuthenticationProviders.map((p) => { - return { - authenticationType: p.AuthenticationType, - ...(p.OpenIDConnectConfig ? { openIDConnectConfig: p.OpenIDConnectConfig } : {}), - ...(p.CognitoUserPoolConfig ? { cognitoUserPoolConfig: p.CognitoUserPoolConfig } : {}), - }; - }), - } - : { - additionalAuthenticationProviders: [], - }), - }; - return processedResource; -} - -export type AppSyncAPIKeyProcessedResource = CloudFormationProcessedResourceResult & { - ApiKey: string; - Ref: string; -}; -export function appSyncAPIKeyResourceHandler( - resourceName, - resource, - cfnContext: CloudFormationParseContext, -): AppSyncAPIKeyProcessedResource { - const value = 'da2-fakeApiId123456'; // TODO: Generate - const arn = `arn:aws:appsync:us-east-1:123456789012:apis/graphqlapiid/apikey/apikeya1bzhi${value}`; - const processedResource = { - cfnExposedAttributes: { ApiKey: 'ApiKey', Arn: 'ref' }, - ApiKey: value, - Ref: arn, - Arn: arn, - }; - return processedResource; -} - -export type AppSyncSchemaProcessedResource = CloudFormationProcessedResourceResult & { - definitionS3Location?: string; - definition?: string; -}; -export function appSyncSchemaHandler(resourceName, resource, cfnContext: CloudFormationParseContext): AppSyncSchemaProcessedResource { - const result: AppSyncSchemaProcessedResource = { cfnExposedAttributes: {} }; - if (resource && resource.Properties && resource.Properties.Definition) { - result.definition = parseValue(resource.Properties.Definition, cfnContext); - } else if (resource && resource.Properties && resource.Properties.DefinitionS3Location) { - result.definitionS3Location = parseValue(resource.Properties.DefinitionS3Location, cfnContext); - } else { - throw new Error( - 'Invalid configuration for AWS::AppSync::GraphQLSchema. Missing one of the required property (DefinitionS3Location or Definition)', - ); - } - return result; -} - -export type AppSyncResolverProcessedResource = CloudFormationProcessedResourceResult & { - dataSourceName?: string; - functions: string[]; - typeName: string; - fieldName: string; - requestMappingTemplateLocation?: string; - responseMappingTemplateLocation?: string; - requestMappingTemplate?: string; - responseMappingTemplate?: string; - ResolverArn: string; - kind: 'UNIT' | 'PIPELINE'; -}; - -export function appSyncResolverHandler(resourceName, resource, cfnContext: CloudFormationParseContext): AppSyncResolverProcessedResource { - const { Properties: properties } = resource; - const requestMappingTemplateLocation = properties.RequestMappingTemplateS3Location - ? parseValue(properties.RequestMappingTemplateS3Location, cfnContext) - : undefined; - const responseMappingTemplateLocation = properties.ResponseMappingTemplateS3Location - ? parseValue(properties.ResponseMappingTemplateS3Location, cfnContext) - : undefined; - const requestMappingTemplate = properties.RequestMappingTemplate ? parseValue(properties.RequestMappingTemplate, cfnContext) : undefined; - const responseMappingTemplate = properties.ResponseMappingTemplate - ? parseValue(properties.ResponseMappingTemplate, cfnContext) - : undefined; - - let dataSourceName; - let functions; - - if (properties.Kind === 'PIPELINE') { - if (typeof properties.PipelineConfig === 'undefined') { - throw new Error('Pipeline DataSource config is missing required property PipelineConfig'); - } - functions = (properties.PipelineConfig.Functions || []).map((f) => parseValue(f, cfnContext)); - } else { - dataSourceName = parseValue(properties.DataSourceName, cfnContext); - } - - return { - cfnExposedAttributes: { FieldName: 'fieldName', ResolverArn: 'ResolverArn', TypeName: 'typeName' }, - dataSourceName, - typeName: properties.TypeName, - functions, - fieldName: properties.FieldName, - requestMappingTemplateLocation: requestMappingTemplateLocation, - responseMappingTemplateLocation: responseMappingTemplateLocation, - requestMappingTemplate, - responseMappingTemplate, - kind: properties.Kind || 'UNIT', - ResolverArn: `arn:aws:appsync:us-east-1:123456789012:apis/graphqlapiid/types/${properties.TypeName}/resolvers/${properties.FieldName}`, - }; -} - -export type AppSyncFunctionProcessedResource = CloudFormationProcessedResourceResult & { - dataSourceName: string; - ref: string; - name: string; - requestMappingTemplateLocation?: string; - responseMappingTemplateLocation?: string; - requestMappingTemplate?: string; - responseMappingTemplate?: string; -}; - -export function appSyncFunctionHandler(resourceName, resource, cfnContext: CloudFormationParseContext): AppSyncFunctionProcessedResource { - const { Properties: properties } = resource; - const requestMappingTemplateLocation = properties.RequestMappingTemplateS3Location - ? parseValue(properties.RequestMappingTemplateS3Location, cfnContext) - : undefined; - const responseMappingTemplateLocation = properties.ResponseMappingTemplateS3Location - ? parseValue(properties.ResponseMappingTemplateS3Location, cfnContext) - : undefined; - const requestMappingTemplate = properties.RequestMappingTemplate ? parseValue(properties.RequestMappingTemplate, cfnContext) : undefined; - const responseMappingTemplate = properties.ResponseMappingTemplate - ? parseValue(properties.ResponseMappingTemplate, cfnContext) - : undefined; - - const dataSourceName = parseValue(properties.DataSourceName, cfnContext); - return { - ref: `arn:aws:appsync:us-east-1:123456789012:apis/graphqlapiid/functions/${resource.Properties.Name}`, - cfnExposedAttributes: { DataSourceName: 'dataSourceName', FunctionArn: 'ref', FunctionId: 'name', Name: 'name' }, - name: resource.Properties.Name, - dataSourceName, - requestMappingTemplateLocation: requestMappingTemplateLocation, - responseMappingTemplateLocation: responseMappingTemplateLocation, - requestMappingTemplate, - responseMappingTemplate, - }; -} diff --git a/packages/amplify-util-mock/src/CFNParser/resource-processors/iam.ts b/packages/amplify-util-mock/src/CFNParser/resource-processors/iam.ts deleted file mode 100644 index 2643262e52..0000000000 --- a/packages/amplify-util-mock/src/CFNParser/resource-processors/iam.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { CloudFormationParseContext } from '../types'; - -export function iamPolicyResourceHandler(resourceName, resource, cfnContext: CloudFormationParseContext) { - const processedResource = { - cfnExposedAttributes: {}, - ref: `IAMPolicy${resource.Properties.PolicyName}`, - }; - return processedResource; -} - -export function iamRoleResourceHandler(resourceName, resource, cfnContext: CloudFormationParseContext) { - const processedResource = { - cfnExposedAttributes: { Arn: 'Arn', RoleId: 'RoleId' }, - ref: `IAMRole${resource.Properties.RoleName}`, - Arn: 'IAM-ARN', - RoleId: `AIDAJQABLZS4A3QD${Math.floor(Math.random() * 100)}Q`, - }; - return processedResource; -} diff --git a/packages/amplify-util-mock/src/CFNParser/resource-processors/index.ts b/packages/amplify-util-mock/src/CFNParser/resource-processors/index.ts deleted file mode 100644 index 69851a367e..0000000000 --- a/packages/amplify-util-mock/src/CFNParser/resource-processors/index.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { CloudFormationResource, ProcessedLambdaFunction } from '../stack/types'; -import { CloudFormationParseContext } from '../types'; -import { lambdaEventSourceHandler, lambdaFunctionHandler } from './lambda'; -import { - appSyncAPIKeyResourceHandler, - appSyncAPIResourceHandler, - appSyncDataSourceHandler, - appSyncFunctionHandler, - appSyncResolverHandler, - appSyncSchemaHandler, - dynamoDBResourceHandler, -} from './appsync'; -import { iamPolicyResourceHandler, iamRoleResourceHandler } from './iam'; -import { openSearchDomainHandler } from './opensearch'; - -export type CloudFormationResourceProcessorFn = ( - resourceName: string, - resource: CloudFormationResource, - cfnContext: CloudFormationParseContext, -) => ProcessedLambdaFunction | any; // TODO should type the rest of the handler responses - -const resourceProcessorMapping: Record = {}; -export function getResourceProcessorFor(resourceType: string): CloudFormationResourceProcessorFn { - if (resourceType in resourceProcessorMapping) { - return resourceProcessorMapping[resourceType]; - } - throw new Error(`No resource handler found for the CloudFormation resource type ${resourceType}`); -} - -export function registerResourceProcessors(resourceType: string, resourceProcessor: CloudFormationResourceProcessorFn): void { - resourceProcessorMapping[resourceType] = resourceProcessor; -} - -export function registerAppSyncResourceProcessor(): void { - registerResourceProcessors('AWS::AppSync::GraphQLApi', appSyncAPIResourceHandler); - registerResourceProcessors('AWS::AppSync::ApiKey', appSyncAPIKeyResourceHandler); - registerResourceProcessors('AWS::AppSync::GraphQLSchema', appSyncSchemaHandler); - registerResourceProcessors('AWS::DynamoDB::Table', dynamoDBResourceHandler); - registerResourceProcessors('AWS::AppSync::Resolver', appSyncResolverHandler); - registerResourceProcessors('AWS::AppSync::DataSource', appSyncDataSourceHandler); - registerResourceProcessors('AWS::AppSync::FunctionConfiguration', appSyncFunctionHandler); -} - -export function registerIAMResourceProcessor(): void { - registerResourceProcessors('AWS::IAM::Policy', iamPolicyResourceHandler); - registerResourceProcessors('AWS::IAM::Role', iamRoleResourceHandler); -} - -export function registerLambdaResourceProcessor(): void { - registerResourceProcessors('AWS::Lambda::Function', lambdaFunctionHandler); - registerResourceProcessors('AWS::Lambda::EventSourceMapping', lambdaEventSourceHandler); -} - -export function registerOpenSearchResourceProcessor(): void { - registerResourceProcessors('AWS::Elasticsearch::Domain', openSearchDomainHandler); -} diff --git a/packages/amplify-util-mock/src/CFNParser/resource-processors/lambda.ts b/packages/amplify-util-mock/src/CFNParser/resource-processors/lambda.ts deleted file mode 100644 index 05d912804f..0000000000 --- a/packages/amplify-util-mock/src/CFNParser/resource-processors/lambda.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { CloudFormationParseContext } from '../types'; -import { parseValue } from '../field-parser'; -import { - CloudFormationResource, - CloudFormationResourceProperty, - ProcessedLambdaEventSource, - ProcessedLambdaFunction, -} from '../stack/types'; - -/** - * Handles the parsing of a lambda CFN resource into relevant bits of information - * @param _ (resourceName) not used, but required to satisfy the CloudFormationResourceProcessorFn interface - * @param resource The CFN resource as a JSON object - * @param cfnContext The parameters, exports and other context required to parse the CFN - */ -export const lambdaFunctionHandler = ( - resourceName, - resource: CloudFormationResource, - cfnContext: CloudFormationParseContext, -): ProcessedLambdaFunction => { - // Use the resource name as a fallback in case the optional functionName is not present in CFN. - const name: string = parseValue(resource.Properties.FunctionName ?? resourceName, cfnContext); - const handler = parseValue(resource.Properties.Handler, cfnContext); - const cfnEnvVars = (resource?.Properties?.Environment as CloudFormationResourceProperty)?.Variables || {}; - const environment = Object.entries(cfnEnvVars).reduce( - (acc, [varName, varVal]) => ({ - ...acc, - [varName]: parseValue(varVal, cfnContext), - }), - {} as Record, - ); - return { - cfnExposedAttributes: { Arn: 'arn' }, - arn: `arn:aws:lambda:{aws-region}:{aws-account-number}:function/${name}/LATEST`, - ref: `arn:aws:lambda:{aws-region}:{aws-account-number}:function/${name}/LATEST`, - name, - handler, - environment, - }; -}; - -export const lambdaEventSourceHandler = ( - resourceName: string, - resource: CloudFormationResource, - cfnContext: CloudFormationParseContext, -): ProcessedLambdaEventSource => { - const batchSize: number = parseValue(resource.Properties.BatchSize, cfnContext); - const eventSourceArn: string = parseValue(resource.Properties.EventSourceArn, cfnContext); - const functionName: string = parseValue(resource.Properties.FunctionName, cfnContext); - const startingPosition: string = parseValue(resource.Properties.StartingPosition, cfnContext); - - return { - cfnExposedAttributes: {}, - batchSize, - eventSourceArn, - functionName, - startingPosition, - }; -}; diff --git a/packages/amplify-util-mock/src/CFNParser/resource-processors/opensearch.ts b/packages/amplify-util-mock/src/CFNParser/resource-processors/opensearch.ts deleted file mode 100644 index ece9d6b00c..0000000000 --- a/packages/amplify-util-mock/src/CFNParser/resource-processors/opensearch.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { CloudFormationParseContext } from '../types'; -import { CloudFormationResource, ProcessedOpenSearchDomain } from '../stack/types'; - -export const openSearchDomainHandler = ( - resourceName: string, - resource: CloudFormationResource, - cfnContext: CloudFormationParseContext, -): ProcessedOpenSearchDomain => { - return { - cfnExposedAttributes: { Arn: 'arn', DomainArn: 'arn', DomainEndpoint: 'endpoint' }, - arn: `arn:aws:es:{aws-region}:{aws-account-number}:domain/${resourceName}`, - ref: resourceName, - endpoint: 'localhost:9200', - }; -}; diff --git a/packages/amplify-util-mock/src/CFNParser/stack/index.ts b/packages/amplify-util-mock/src/CFNParser/stack/index.ts deleted file mode 100644 index 1fd33523d6..0000000000 --- a/packages/amplify-util-mock/src/CFNParser/stack/index.ts +++ /dev/null @@ -1,297 +0,0 @@ -import { Sorter } from '@hapi/topo'; -import { isPlainObject } from 'lodash'; -import '../../CFNParser'; -import { parseValue } from '../field-parser'; -import { getResourceProcessorFor } from '../resource-processors'; -import { CloudFormationParseContext } from '../types'; -import { - CloudFormationConditions, - CloudFormationOutputs, - CloudFormationParameters, - CloudFormationResource, - CloudFormationResources, - CloudFormationTemplate, - CloudFormationTemplateFetcher, -} from './types'; - -export const CFN_PSEUDO_PARAMS = { - 'AWS::Region': 'us-east-1-fake', - 'AWS::AccountId': '12345678910', - 'AWS::StackId': 'fake-stackId', - 'AWS::StackName': 'local-testing', - 'AWS::URLSuffix': 'amazonaws.com', -}; - -export function nestedStackHandler( - resourceName: string, - resource: CloudFormationResource, - cfnContext: CloudFormationParseContext, - cfnTemplateFetcher: CloudFormationTemplateFetcher, -) { - if (typeof resource.Properties.TemplateURL === 'undefined') { - throw new Error(`Error in parsing Nested stack ${resourceName}. Stack is missing required property TemplateURL`); - } - const parameters = resource.Properties.Parameters || {}; - - // process all the parameters - const processedParameters = Object.entries(parameters).reduce((acc, [parameterName, parameterValue]) => { - return { - ...acc, - [parameterName]: parseValue(parameterValue, cfnContext), - }; - }, {}); - - // get the template - const templatePath = parseValue(resource.Properties.TemplateURL, cfnContext); - - // custom templates have .json extension and Transformer generated ones don't. - const stackTemplate = cfnTemplateFetcher.getCloudFormationStackTemplate(templatePath); - - if (typeof stackTemplate === 'undefined') { - throw new Error(`Could not find the CloudFormation template ${templatePath} for resource ${resourceName}`); - } - - return processCloudFormationStack(stackTemplate, processedParameters, cfnContext.exports, cfnTemplateFetcher); -} -export function mergeParameters(templateParameters: CloudFormationParameters, inputParameters): Record { - const processedParams: Record = {}; - Object.keys(templateParameters).forEach((paramName: string) => { - if (paramName in inputParameters) { - processedParams[paramName] = inputParameters[paramName]; - } else if (typeof templateParameters[paramName].Default === 'undefined') { - throw new Error(`CloudFormation stack parameter ${paramName} is missing default value`); - } else { - processedParams[paramName] = templateParameters[paramName].Default; - } - }); - return { ...CFN_PSEUDO_PARAMS, ...processedParams }; -} - -export function processConditions(conditions: CloudFormationConditions, processedParams: Record): Record { - const processedConditions: Record = {}; - Object.keys(conditions).forEach((conditionName) => { - const condition = conditions[conditionName]; - processedConditions[conditionName] = parseValue(condition, { - params: processedParams, - conditions: { ...conditions }, - resources: {}, - exports: {}, - }); - }); - return processedConditions; -} - -export function getDependencyResources(node: object | any[], params: Record = {}): string[] { - let result: string[] = []; - if (typeof node === 'string') { - return []; - } - - if (isPlainObject(node) && Object.keys(node).length === 1) { - const fnName = Object.keys(node)[0]; - const fnArgs = node[fnName]; - if (fnName === 'Ref') { - const resourceName = fnArgs; - if (!Object.keys(params).includes(resourceName)) { - result.push(resourceName); - } - } else if (fnName === 'Fn::GetAtt') { - const resourceName = fnArgs[0]; - result.push(resourceName); - } else if (typeof fnArgs !== 'string') { - for (let i = 0; i < fnArgs.length; i++) { - result = [...result, ...getDependencyResources(fnArgs[i], params)]; - } - } - } else if (Array.isArray(node)) { - return node.reduce((acc, item) => [...acc, ...getDependencyResources(item, params)], []); - } - return result; -} - -export function sortResources(resources: CloudFormationResources, params: Record): string[] { - const resourceSorter: Sorter = new Sorter(); - Object.keys(resources).forEach((resourceName) => { - const resource = resources[resourceName]; - let dependsOn: string[] = []; - // intrinsic dependency - const intrinsicDependency = Object.values(resource.Properties) - .map((propValue) => getDependencyResources(propValue, params)) - .reduce((sum, val) => [...sum, ...val], []); - - // Todo: enable this once e2e test invoke transformer the same way as - // mock - // throw error if one of the intrinsic resource - // const missingIntrinsicDeps = intrinsicDependency.filter(res => !(res in resources)); - // if (missingIntrinsicDeps.length) { - // throw new Error( - // `Resource ${resourceName} has missing intrinsic dependency ${ - // missingIntrinsicDeps.length === 1 ? 'resource' : 'resources' - // } ${missingIntrinsicDeps.join(', ')}`, - // ); - // } - - if (resource.DependsOn) { - if (Array.isArray(resource.DependsOn) || typeof resource.DependsOn === 'string') { - dependsOn = typeof resource.DependsOn === 'string' ? [resource.DependsOn] : resource.DependsOn; - if (dependsOn.some((dependsOnResource) => !(dependsOnResource in resources))) { - throw new Error(`Resource ${resourceName} DependsOn a non-existent resource`); - } - } else { - throw new Error(`DependsOn block should be an array or a string for resource ${resourceName}`); - } - } - try { - resourceSorter.add(resourceName, { group: resourceName, after: [...dependsOn, ...intrinsicDependency] }); - } catch (e) { - if (e.message.indexOf('Item cannot come after itself') !== -1) { - throw new Error(`Resource ${resourceName} can not depend on itself`); - } - if (e.message.indexOf('created a dependencies error') !== -1) { - throw new Error('Cyclic dependency detected in the Resources'); - } - throw e; - } - }); - return resourceSorter.nodes; -} - -export function filterResourcesBasedOnConditions( - resources: CloudFormationResources, - conditions: Record, -): CloudFormationResources { - const filteredResources: CloudFormationResources = {}; - Object.entries(resources) - .filter(([resourceName, resource]) => { - if (resource.Condition) { - const condition = conditions[resource.Condition]; - if (typeof condition === 'undefined') { - throw new Error(`Condition ${resource.Condition} used by resource ${resourceName} is not defined in Condition block`); - } - return condition; - } - return true; - }) - .forEach(([resourceName, resource]) => { - filteredResources[resourceName] = resource; - }); - return filteredResources; -} - -export function processResources( - parameters: Record, - conditions: Record, - resources: CloudFormationResources, - cfnExports: Record, - cfnTemplateFetcher: CloudFormationTemplateFetcher, -): { resources: Record; stackExports: Record } { - const filteredResources = filterResourcesBasedOnConditions(resources, conditions); - const sortedResourceNames = sortResources(filteredResources, parameters); - const processedResources = {}; - sortedResourceNames.forEach((resourceName) => { - const resource = filteredResources[resourceName]; - const resourceType = resource.Type; - const cfnContext: CloudFormationParseContext = { - params: { ...parameters }, - conditions: { ...conditions }, - resources: { ...processedResources }, - exports: { ...cfnExports }, - }; - - if (resourceType === 'AWS::CloudFormation::Stack') { - const nestedStack = nestedStackHandler(resourceName, resource, cfnContext, cfnTemplateFetcher); - processedResources[resourceName] = { result: nestedStack, Type: 'AWS::CloudFormation::Stack' }; - cfnExports = { ...cfnExports, ...nestedStack.stackExports }; - } else { - try { - const resourceProcessor = getResourceProcessorFor(resourceType); - const processedResource = resourceProcessor(resourceName, resource, cfnContext); - processedResources[resourceName] = { result: processedResource, Type: resourceType }; - } catch (e) { - if (e.message.indexOf('No resource handler found') === -1) { - // ignore errors when we don't know how to process the resource - throw e; - } else { - console.log( - `Mock does not handle CloudFormation resource of type ${resourceType}. Skipping processing resource ${resourceName}.`, - ); - } - } - } - }); - return { resources: processedResources, stackExports: cfnExports }; -} - -export function processExports( - output: CloudFormationOutputs, - parameters: Record, - conditions: Record, - resources: Record, - cfnExports: Record = {}, -): Record { - const stackExports = {}; - const cfnContext = { params: parameters, conditions, resources, exports: cfnExports }; - Object.values(output).forEach((output) => { - if (output.Export && output.Export.Name) { - const exportName = parseValue(output.Export.Name, cfnContext); - let exportValue; - try { - exportValue = parseValue(output.Value, cfnContext); - } catch (e) { - // when export section has conditional resource which is not provisioned, skip the export value - return; - } - - if (exportName in cfnExports) { - throw new Error(`export ${exportName} is already exported in a different stack.`); - } - stackExports[exportName] = exportValue; - } - }); - return stackExports; -} - -export function processOutputs( - output: CloudFormationOutputs, - parameters: Record, - conditions: Record, - resources: Record, - cfnExports: Record = {}, -): Record { - const outputs = {}; - const cfnContext = { params: parameters, conditions, resources, exports: cfnExports }; - Object.entries(output).forEach(([name, res]) => { - outputs[name] = parseValue(res.Value, cfnContext); - }); - return outputs; -} - -export function processCloudFormationStack( - template: CloudFormationTemplate, - parameters: Record, - cfnExports: Record, - cfnTemplateFetcher: CloudFormationTemplateFetcher, -): { resources: Record; stackExports: Record; outputs: Record } { - const mergedParameters = mergeParameters(template.Parameters || {}, parameters || {}); - const processedConditions = processConditions(template.Conditions || {}, mergedParameters); - const processedResources = processResources(mergedParameters, processedConditions, template.Resources, cfnExports, cfnTemplateFetcher); - const processedOutput = processOutputs( - template.Outputs || {}, - mergedParameters, - processedConditions, - processedResources.resources, - processedResources.stackExports, - ); - const processedExports = processExports( - template.Outputs || {}, - mergedParameters, - processedConditions, - processedResources.resources, - processedResources.stackExports, - ); - return { - resources: processedResources.resources, - stackExports: processedExports, - outputs: processedOutput, - }; -} diff --git a/packages/amplify-util-mock/src/CFNParser/stack/types.ts b/packages/amplify-util-mock/src/CFNParser/stack/types.ts deleted file mode 100644 index 17b17babba..0000000000 --- a/packages/amplify-util-mock/src/CFNParser/stack/types.ts +++ /dev/null @@ -1,123 +0,0 @@ -export type CloudFormationParameter = { - Type: string; - Description?: string; - Default?: String | Number; -}; -export type CloudFormationFnIf = { - 'Fn::If': [string, CloudFormationIntrinsicFunction, CloudFormationIntrinsicFunction]; -}; -export type CloudFormationFnAnd = { - 'Fn::And': CloudFormationIntrinsicFunction[]; -}; -export type CloudFormationFnEqual = { - 'Fn::Equals': [CloudFormationIntrinsicFunction, CloudFormationIntrinsicFunction]; -}; -export type CloudFormationFnNot = { - 'Fn::Not': [CloudFormationIntrinsicFunction]; -}; -export type CloudFormationFnOr = { - 'Fn::Or': CloudFormationIntrinsicFunction[]; -}; -export type CloudFormationFnFindInMap = { - 'Fn::FindInMap': [string, CloudFormationIntrinsicFunction, CloudFormationIntrinsicFunction]; -}; -export type CloudFormationRef = { - Ref: string; -}; -export type CloudFormationFnGetAtt = { - 'Fn::GetAtt': [string, CloudFormationRef | string]; -}; -export type CloudFormationFnBase64 = { - 'Fn::Base64': string; -}; -export type CloudFormationFnImportValue = { - 'Fn::ImportValue': CloudFormationIntrinsicFunction; // limit to subset (Fn::Base64, Fn::FindInMap, Fn::If, Fn::Join, Fn::Select, Fn::Split, Fn::Sub, Ref) -}; -export type CloudFormationFnJoin = { - 'Fn::Join': [string, CloudFormationIntrinsicFunction[]]; -}; -export type CloudFormationFnSelect = { - 'Fn::Select': [number, ...CloudFormationIntrinsicFunction[]]; // limit subset(Fn::FindInMap,Fn::GetAtt,Fn::GetAZs,Fn::If,Fn::Split,Ref) -}; -export type CloudFormationFnSplit = { - 'Fn::Split': [string, ...CloudFormationIntrinsicFunction[]]; // limit subset (Fn::Base64,Fn::FindInMap,Fn::GetAtt,Fn::GetAZs,Fn::If,Fn::ImportValue,Fn::Join,Fn::Select,Fn::Sub,Ref) -}; -export type CloudFormationFnSub = { - 'Fn::Sub': [string, ...CloudFormationIntrinsicFunction[]]; // Fn::Base64,Fn::FindInMap,Fn::GetAtt,Fn::GetAZs,Fn::If,Fn::ImportValue,Fn::Join,Fn::Select,Ref -}; -export type CloudFormationIntrinsicConditionFunction = - | CloudFormationFnIf - | CloudFormationFnAnd - | CloudFormationFnEqual - | CloudFormationFnNot - | CloudFormationFnOr; -export type CloudFormationIntrinsicFunction = - | String - | CloudFormationIntrinsicConditionFunction - | CloudFormationFnFindInMap - | CloudFormationRef - | CloudFormationFnGetAtt - | CloudFormationFnImportValue - | CloudFormationFnJoin - | CloudFormationFnSelect - | CloudFormationFnSplit - | CloudFormationFnSub; -export type CloudFormationProperty = string | CloudFormationIntrinsicFunction; -export interface CloudFormationResourceProperty { - [name: string]: CloudFormationIntrinsicFunction | CloudFormationResourceProperty; -} -export type CloudFormationResource = { - Type: string; - Properties: CloudFormationResourceProperty; - DependsOn?: string[]; - Condition?: string; -}; -export type CloudFormationResources = Record; -export type CloudFormationOutput = { - Value: CloudFormationIntrinsicFunction; - Description?: string; - Export?: { - Name: string | CloudFormationIntrinsicFunction; - }; -}; -export type CloudFormationOutputs = Record; -export type CloudFormationConditions = Record; -export type CloudFormationParameters = Record; -export type CloudFormationTemplate = { - Parameters?: CloudFormationParameters; - Resources: CloudFormationResources; - Conditions?: CloudFormationConditions; - Outputs?: CloudFormationOutputs; -}; - -export type CloudFormationProcessedResourceResult = { - cfnExposedAttributes: Record; - arn?: string; - ref?: String; -}; - -export type CloudFormationProcessedResource = { - Type: String; - result: CloudFormationProcessedResourceResult; -}; - -export type CloudFormationTemplateFetcher = { - getCloudFormationStackTemplate: (templateName: string) => CloudFormationTemplate; -}; - -export type ProcessedLambdaFunction = CloudFormationProcessedResourceResult & { - name: string; - handler: string; - environment: Record; -}; - -export type ProcessedLambdaEventSource = CloudFormationProcessedResourceResult & { - batchSize: number; - eventSourceArn: string; - functionName: string; - startingPosition: string; -}; - -export type ProcessedOpenSearchDomain = CloudFormationProcessedResourceResult & { - endpoint: string; -}; diff --git a/packages/amplify-util-mock/src/CFNParser/types.ts b/packages/amplify-util-mock/src/CFNParser/types.ts deleted file mode 100644 index 1029adfb3b..0000000000 --- a/packages/amplify-util-mock/src/CFNParser/types.ts +++ /dev/null @@ -1,29 +0,0 @@ -export type CloudFormationParsedResource = { - Type: string; - result: { - [key: string]: any; - }; -}; - -export type CloudFormationParseContext = { - params: Record; - conditions: object; - resources: Record; - exports: Record; -}; - -export type CloudFormationWalkContext = CloudFormationParseContext & { - walkFn: Function; - parent: Object; - path: string[]; -}; - -export type AWSCloudFormationParameterDefinition = { - Type: string; - Default?: string; - Description?: string; -}; - -export type AWSCloudFormationParametersBlock = { - [key: string]: AWSCloudFormationParameterDefinition; -}; diff --git a/packages/amplify-util-mock/src/__e2e__/connections-with-auth-tests.e2e.test.ts b/packages/amplify-util-mock/src/__e2e__/connections-with-auth-tests.e2e.test.ts deleted file mode 100644 index 5984993ed3..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/connections-with-auth-tests.e2e.test.ts +++ /dev/null @@ -1,547 +0,0 @@ -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { FeatureFlagProvider, GraphQLTransform } from 'graphql-transformer-core'; -import { signUpAddToGroupAndGetJwtToken } from './utils/cognito-utils'; -import { GraphQLClient } from './utils/graphql-client'; -import { deploy, launchDDBLocal, logDebug, terminateDDB } from './utils/index'; -import 'isomorphic-fetch'; - -jest.setTimeout(2000000); - -let GRAPHQL_ENDPOINT = undefined; - -/** - * Client 1 is logged in and is a member of the Admin group. - */ -let GRAPHQL_CLIENT_1 = undefined; - -/** - * Client 2 is logged in and is a member of the Devs group. - */ -let GRAPHQL_CLIENT_2 = undefined; - -/** - * Client 3 is logged in and has no group memberships. - */ -let GRAPHQL_CLIENT_3 = undefined; - -let USER_POOL_ID = 'y9CqgkEJe'; - -const USERNAME1 = 'user1@test.com'; -const USERNAME2 = 'user2@test.com'; -const USERNAME3 = 'user3@test.com'; - -const ADMIN_GROUP_NAME = 'Admin'; -const DEVS_GROUP_NAME = 'Devs'; -const PARTICIPANT_GROUP_NAME = 'Participant'; -const WATCHER_GROUP_NAME = 'Watcher'; - -let ddbEmulator = null; -let dbPath = null; -let server; - -beforeAll(async () => { - const validSchema = `type Post @model( - subscriptions: { - level: public -})@auth(rules: [{ allow: owner }]) { - id: ID! - title: String! - author: User @connection(name: "UserPosts", keyField: "owner") - owner: String -} -type User @model( - subscriptions: { - level: public - }) @auth(rules: [{ allow: owner }]) { - id: ID! - posts: [Post!]! @connection(name: "UserPosts", keyField: "owner") -} -type FieldProtected @model( - subscriptions: { - level: public -}){ - id: ID! - owner: String - ownerOnly: String @auth(rules: [{ allow: owner }]) -} -type OpenTopLevel @model( - subscriptions: { - level: public -}) { - id: ID! - name: String - owner: String - protected: [ConnectionProtected] @connection(name: "ProtectedConnection") -} -type ConnectionProtected @model( - subscriptions: { - level: public - } - queries: null -)@auth(rules: [{ allow: owner }]) { - id: ID! - name: String - owner: String - topLevel: OpenTopLevel @connection(name: "ProtectedConnection") -} -type Performance @model @auth(rules: [{ allow: groups, groups: ["Admin"]}]) { - id: ID - performer: String! - description: String! - time: AWSDateTime - stage: Stage @connection -} -type Stage @model @auth(rules: [{ allow: groups, groups: ["Admin"]}]) { - id: ID! - name: String! -} - `; - const transformer = new GraphQLTransform({ - transformers: [ - new DynamoDBModelTransformer(), - new ModelConnectionTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - featureFlags: { - getBoolean: (name) => name === 'improvePluralization', - } as FeatureFlagProvider, - }); - - try { - const out = transformer.transform(validSchema); - - let ddbClient; - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - - const result = await deploy(out, ddbClient); - server = result.simulator; - - GRAPHQL_ENDPOINT = server.url + '/graphql'; - logDebug(`Using graphql url: ${GRAPHQL_ENDPOINT}`); - - const apiKey = result.config.appSync.apiKey; - - // Verify we have all the details - expect(GRAPHQL_ENDPOINT).toBeTruthy(); - - const idToken = signUpAddToGroupAndGetJwtToken(USER_POOL_ID, USERNAME1, USERNAME1, [ - ADMIN_GROUP_NAME, - WATCHER_GROUP_NAME, - PARTICIPANT_GROUP_NAME, - ]); - GRAPHQL_CLIENT_1 = new GraphQLClient(GRAPHQL_ENDPOINT, { - Authorization: idToken, - }); - - const idToken2 = signUpAddToGroupAndGetJwtToken(USER_POOL_ID, USERNAME2, USERNAME2, [DEVS_GROUP_NAME]); - GRAPHQL_CLIENT_2 = new GraphQLClient(GRAPHQL_ENDPOINT, { - Authorization: idToken2, - }); - - const idToken3 = signUpAddToGroupAndGetJwtToken(USER_POOL_ID, USERNAME3, USERNAME3, []); - GRAPHQL_CLIENT_3 = new GraphQLClient(GRAPHQL_ENDPOINT, { - Authorization: idToken3, - }); - - // Wait for any propagation to avoid random - // "The security token included in the request is invalid" errors - await new Promise((res) => setTimeout(() => res(), 5000)); - } catch (e) { - console.error(e); - throw e; - } -}); - -afterAll(async () => { - try { - if (server) { - await server.stop(); - } - - await terminateDDB(ddbEmulator, dbPath); - } catch (e) { - console.error(e); - throw e; - } -}); - -/** - * Tests - */ -test('creating a post and immediately view it via the User.posts connection.', async () => { - const createUser1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createUser(input: { id: "user1@test.com" }) { - id - } - }`, - {}, - ); - logDebug(createUser1); - expect(createUser1.data.createUser.id).toEqual('user1@test.com'); - - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - owner - } - }`, - {}, - ); - logDebug(response); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.owner).toBeDefined(); - - const getResponse = await GRAPHQL_CLIENT_1.query( - `query { - getUser(id: "user1@test.com") { - posts { - items { - id - title - owner - author { - id - } - } - } - } - }`, - {}, - ); - logDebug(JSON.stringify(getResponse, null, 4)); - expect(getResponse.data.getUser.posts.items[0].id).toBeDefined(); - expect(getResponse.data.getUser.posts.items[0].title).toEqual('Hello, World!'); - expect(getResponse.data.getUser.posts.items[0].owner).toEqual('user1@test.com'); - expect(getResponse.data.getUser.posts.items[0].author.id).toEqual('user1@test.com'); -}); - -test('Testing reading an owner protected field as a non owner', async () => { - const response1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createFieldProtected(input: { id: "1", owner: "${USERNAME1}", ownerOnly: "owner-protected" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - logDebug(response1); - expect(response1.data.createFieldProtected.id).toEqual('1'); - expect(response1.data.createFieldProtected.owner).toEqual(USERNAME1); - expect(response1.data.createFieldProtected.ownerOnly).toEqual('owner-protected'); - - const response2 = await GRAPHQL_CLIENT_2.query( - `query { - getFieldProtected(id: "1") { - id - owner - ownerOnly - } - }`, - {}, - ); - logDebug(response2); - expect(response2.data.getFieldProtected.ownerOnly).toBeNull(); - expect(response2.errors).toHaveLength(1); - - const response3 = await GRAPHQL_CLIENT_1.query( - `query { - getFieldProtected(id: "1") { - id - owner - ownerOnly - } - }`, - {}, - ); - logDebug(response3); - expect(response3.data.getFieldProtected.id).toEqual('1'); - expect(response3.data.getFieldProtected.owner).toEqual(USERNAME1); - expect(response3.data.getFieldProtected.ownerOnly).toEqual('owner-protected'); -}); - -test('that @connection resolvers respect @model read operations.', async () => { - const response1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createOpenTopLevel(input: { id: "1", owner: "${USERNAME1}", name: "open" }) { - id - owner - name - } - }`, - {}, - ); - logDebug(response1); - expect(response1.data.createOpenTopLevel.id).toEqual('1'); - expect(response1.data.createOpenTopLevel.owner).toEqual(USERNAME1); - expect(response1.data.createOpenTopLevel.name).toEqual('open'); - - const response2 = await GRAPHQL_CLIENT_2.query( - `mutation { - createConnectionProtected(input: { id: "1", owner: "${USERNAME2}", name: "closed", connectionProtectedTopLevelId: "1" }) { - id - owner - name - } - }`, - {}, - ); - logDebug(response2); - expect(response2.data.createConnectionProtected.id).toEqual('1'); - expect(response2.data.createConnectionProtected.owner).toEqual(USERNAME2); - expect(response2.data.createConnectionProtected.name).toEqual('closed'); - - const response3 = await GRAPHQL_CLIENT_1.query( - `query { - getOpenTopLevel(id: "1") { - id - protected { - items { - id - name - owner - } - } - } - }`, - {}, - ); - logDebug(response3); - expect(response3.data.getOpenTopLevel.id).toEqual('1'); - expect(response3.data.getOpenTopLevel.protected.items).toHaveLength(0); - - const response4 = await GRAPHQL_CLIENT_2.query( - `query { - getOpenTopLevel(id: "1") { - id - protected { - items { - id - name - owner - } - } - } - }`, - {}, - ); - logDebug(response4); - expect(response4.data.getOpenTopLevel.id).toEqual('1'); - expect(response4.data.getOpenTopLevel.protected.items).toHaveLength(1); -}); - -// Per field auth in mutations -test('that owners cannot set the field of a FieldProtected object unless authorized.', async () => { - const response1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createFieldProtected(input: { id: "2", owner: "${USERNAME1}", ownerOnly: "owner-protected" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - logDebug(JSON.stringify(response1)); - expect(response1.data.createFieldProtected.id).toEqual('2'); - expect(response1.data.createFieldProtected.owner).toEqual(USERNAME1); - expect(response1.data.createFieldProtected.ownerOnly).toEqual('owner-protected'); - - const response2 = await GRAPHQL_CLIENT_1.query( - `mutation { - createFieldProtected(input: { id: "3", owner: "${USERNAME2}", ownerOnly: "owner-protected" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - logDebug(response2); - expect(response2.data.createFieldProtected).toBeNull(); - expect(response2.errors).toHaveLength(1); - - // The auth rule is on ownerOnly. Omitting the "ownerOnly" field will - // not trigger the @auth check - const response3 = await GRAPHQL_CLIENT_1.query( - `mutation { - createFieldProtected(input: { id: "4", owner: "${USERNAME2}" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - logDebug(response3); - expect(response3.data.createFieldProtected.id).toEqual('4'); - expect(response3.data.createFieldProtected.owner).toEqual(USERNAME2); - // The length is one because the 'ownerOnly' field is protected on reads. - // Since the caller is not the owner this will throw after the mutation succeeds - // and return partial results. - expect(response3.errors).toHaveLength(1); -}); - -test('authorized user can get Performance with no created stage', async () => { - const createPerf = `mutation { - create: createPerformance(input: { - id: "P3" - performer: "Perf #3" - description: "desc" - time: "2021-11-11T00:00:00Z" - }) { - id - performer - description - time - createdAt - updatedAt - } - }`; - - const getPerf = `query { - g1: getPerformance(id: "P3") { - id - performer - description - time - stage { - id - name - createdAt - updatedAt - } - createdAt - updatedAt - } - } - `; - - const createStage = `mutation { - createStage(input: {name: "stage3", id: "003"}) { - createdAt - id - name - updatedAt - } - }`; - - const updatePerf = `mutation { - u1: updatePerformance(input: {id: "P3", performanceStageId: "003"}) { - createdAt - description - id - performer - time - updatedAt - stage { - id - name - } - } - }`; - - // first make a query to the record 'P3' - const response1 = await GRAPHQL_CLIENT_1.query(getPerf, {}); - expect(response1).toBeDefined(); - expect(response1.data.g1).toBeNull(); - - // create performance and expect stage to be null - const c_response = await GRAPHQL_CLIENT_1.query(createPerf, {}); - console.log(c_response); - const response2 = await GRAPHQL_CLIENT_1.query(getPerf, {}); - expect(response2).toBeDefined(); - expect(response2.data.g1).toBeDefined(); - expect(response2.data.g1.id).toEqual('P3'); - expect(response2.data.g1.description).toEqual('desc'); - expect(response2.data.g1.stage).toBeNull(); - - // create stage and then add it to perf should show stage in perf - await GRAPHQL_CLIENT_1.query(createStage, {}); - const response3 = await GRAPHQL_CLIENT_1.query(updatePerf, {}); - expect(response3).toBeDefined(); - expect(response3.data.u1).toBeDefined(); - expect(response3.data.u1.id).toEqual('P3'); - expect(response3.data.u1.stage).toMatchObject({ - id: '003', - name: 'stage3', - }); -}); - -test('that owners cannot update the field of a FieldProtected object unless authorized.', async () => { - const response1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createFieldProtected(input: { owner: "${USERNAME1}", ownerOnly: "owner-protected" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - logDebug(JSON.stringify(response1)); - expect(response1.data.createFieldProtected.id).not.toBeNull(); - expect(response1.data.createFieldProtected.owner).toEqual(USERNAME1); - expect(response1.data.createFieldProtected.ownerOnly).toEqual('owner-protected'); - - const response2 = await GRAPHQL_CLIENT_2.query( - `mutation { - updateFieldProtected(input: { id: "${response1.data.createFieldProtected.id}", ownerOnly: "owner2-protected" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - logDebug(response2); - expect(response2.data.updateFieldProtected).toBeNull(); - expect(response2.errors).toHaveLength(1); - - // The auth rule is on ownerOnly. Omitting the "ownerOnly" field will - // not trigger the @auth check - const response3 = await GRAPHQL_CLIENT_1.query( - `mutation { - updateFieldProtected(input: { id: "${response1.data.createFieldProtected.id}", ownerOnly: "updated" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - logDebug(response3); - expect(response3.data.updateFieldProtected.id).toEqual(response1.data.createFieldProtected.id); - expect(response3.data.updateFieldProtected.owner).toEqual(USERNAME1); - expect(response3.data.updateFieldProtected.ownerOnly).toEqual('updated'); - - // This request should succeed since we are not updating the protected field. - const response4 = await GRAPHQL_CLIENT_3.query( - `mutation { - updateFieldProtected(input: { id: "${response1.data.createFieldProtected.id}", owner: "${USERNAME3}" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - logDebug(response4); - expect(response4.data.updateFieldProtected.id).toEqual(response1.data.createFieldProtected.id); - expect(response4.data.updateFieldProtected.owner).toEqual(USERNAME3); - expect(response4.data.updateFieldProtected.ownerOnly).toEqual('updated'); -}); diff --git a/packages/amplify-util-mock/src/__e2e__/dynamo-db-model-transformer.e2e.test.ts b/packages/amplify-util-mock/src/__e2e__/dynamo-db-model-transformer.e2e.test.ts deleted file mode 100644 index e748fdfef6..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/dynamo-db-model-transformer.e2e.test.ts +++ /dev/null @@ -1,767 +0,0 @@ -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { FeatureFlagProvider, GraphQLTransform } from 'graphql-transformer-core'; -import { GraphQLClient } from './utils/graphql-client'; -import { deploy, launchDDBLocal, terminateDDB, logDebug } from './utils/index'; - -let GRAPHQL_ENDPOINT = undefined; -let GRAPHQL_CLIENT = undefined; -let ddbEmulator = null; -let dbPath = null; -let server; -jest.setTimeout(2000000); - -beforeAll(async () => { - process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; - const validSchema = ` - type Post @model { - id: ID! - title: String! - createdAt: AWSDateTime - updatedAt: AWSDateTime - metadata: PostMetadata - entityMetadata: EntityMetadata - appearsIn: [Episode!] - episode: Episode - } - type Author @model { - id: ID! - name: String! - postMetadata: PostMetadata - entityMetadata: EntityMetadata - } - type EntityMetadata { - isActive: Boolean - } - type PostMetadata { - tags: Tag - } - type Tag { - published: Boolean - metadata: PostMetadata - } - enum Episode { - NEWHOPE - EMPIRE - JEDI - } - `; - try { - const transformer = new GraphQLTransform({ - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - featureFlags: { - getBoolean: (name) => name === 'improvePluralization', - } as FeatureFlagProvider, - }); - const out = await transformer.transform(validSchema); - let ddbClient; - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - const result = await deploy(out, ddbClient); - server = result.simulator; - - GRAPHQL_ENDPOINT = server.url + '/graphql'; - logDebug(`Using graphql url: ${GRAPHQL_ENDPOINT}`); - - const apiKey = result.config.appSync.apiKey; - logDebug(apiKey); - GRAPHQL_CLIENT = new GraphQLClient(GRAPHQL_ENDPOINT, { - 'x-api-key': apiKey, - }); - } catch (e) { - logDebug('error when setting up test'); - logDebug(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - if (server) { - await server.stop(); - } - await terminateDDB(ddbEmulator, dbPath); -}); - -afterEach(async () => { - try { - // delete all the records - logDebug('deleting posts'); - const response = await GRAPHQL_CLIENT.query( - ` - query { - listPosts { - items { - id - } - } - }`, - {}, - ); - const rows = response.data.listPosts.items || []; - const deletePromises = []; - rows.forEach((row) => { - deletePromises.push( - GRAPHQL_CLIENT.query(`mutation delete{ - deletePost(input: {id: "${row.id}"}) { id } - }`), - ); - }); - await Promise.all(deletePromises); - } catch (e) { - logDebug(e); - } -}); - -/** - * Test queries below - */ -test('createAuthor mutation', async () => { - try { - const response = await GRAPHQL_CLIENT.query( - `mutation($input: CreateAuthorInput!) { - createAuthor(input: $input) { - id - name - entityMetadata { - isActive - } - } - }`, - { - input: { - name: 'Jeff B', - entityMetadata: { - isActive: true, - }, - }, - }, - ); - logDebug(response); - expect(response.data.createAuthor.id).toBeDefined(); - expect(response.data.createAuthor.name).toEqual('Jeff B'); - expect(response.data.createAuthor.entityMetadata).toBeDefined(); - expect(response.data.createAuthor.entityMetadata.isActive).toEqual(true); - } catch (e) { - logDebug(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('createPost mutation', async () => { - try { - const response = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - } catch (e) { - logDebug(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('query on get query with null field', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - ` - mutation { - createPost(input: { title: "Cool Post" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Cool Post'); - const postID = createResponse.data.createPost.id; - try { - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query { - getPost(id: "${postID}") { - id - title - episode - } - }`, - {}, - ); - expect(queryResponse.data.getPost.id).toEqual(postID); - expect(queryResponse.data.getPost.episode).toBeNull(); - } catch (err) { - logDebug(err); - expect(err).toBeUndefined(); - } -}); - -test('updatePost mutation', async () => { - try { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Update" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - logDebug(JSON.stringify(createResponse, null, 4)); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Update'); - const updateResponse = await GRAPHQL_CLIENT.query( - `mutation { - updatePost(input: { id: "${createResponse.data.createPost.id}", title: "Bye, World!" }) { - id - title - } - }`, - {}, - ); - logDebug(JSON.stringify(updateResponse, null, 4)); - expect(updateResponse.data.updatePost.title).toEqual('Bye, World!'); - } catch (e) { - logDebug(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('createPost and updatePost mutation with a client generated id.', async () => { - try { - const clientId = 'a-client-side-generated-id'; - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { id: "${clientId}" title: "Test Update" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - logDebug(JSON.stringify(createResponse, null, 4)); - expect(createResponse.data.createPost.id).toEqual(clientId); - expect(createResponse.data.createPost.title).toEqual('Test Update'); - const updateResponse = await GRAPHQL_CLIENT.query( - `mutation { - updatePost(input: { id: "${clientId}", title: "Bye, World!" }) { - id - title - } - }`, - {}, - ); - logDebug(JSON.stringify(updateResponse, null, 4)); - expect(updateResponse.data.updatePost.id).toEqual(clientId); - expect(updateResponse.data.updatePost.title).toEqual('Bye, World!'); - const getResponse = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${clientId}") { - id - title - } - }`, - {}, - ); - logDebug(JSON.stringify(getResponse, null, 4)); - expect(getResponse.data.getPost.id).toEqual(clientId); - expect(getResponse.data.getPost.title).toEqual('Bye, World!'); - - const deleteResponse = await GRAPHQL_CLIENT.query( - `mutation { - deletePost(input: { id: "${clientId}" }) { - id - title - } - }`, - {}, - ); - logDebug(JSON.stringify(deleteResponse, null, 4)); - expect(deleteResponse.data.deletePost.id).toEqual(clientId); - expect(deleteResponse.data.deletePost.title).toEqual('Bye, World!'); - - const getResponse2 = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${clientId}") { - id - title - } - }`, - {}, - ); - logDebug(JSON.stringify(getResponse2, null, 4)); - expect(getResponse2.data.getPost).toBeNull(); - } catch (e) { - logDebug(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('deletePost mutation', async () => { - try { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Delete" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - logDebug(JSON.stringify(createResponse, null, 4)); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Delete'); - const deleteResponse = await GRAPHQL_CLIENT.query( - `mutation { - deletePost(input: { id: "${createResponse.data.createPost.id}" }) { - id - title - } - }`, - {}, - ); - logDebug(JSON.stringify(deleteResponse, null, 4)); - expect(deleteResponse.data.deletePost.title).toEqual('Test Delete'); - const getResponse = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - } - }`, - {}, - ); - logDebug(JSON.stringify(getResponse, null, 4)); - expect(getResponse.data.getPost).toBeNull(); - } catch (e) { - logDebug(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('getPost query', async () => { - try { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Get" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeTruthy(); - expect(createResponse.data.createPost.title).toEqual('Test Get'); - const getResponse = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - } - }`, - {}, - ); - expect(getResponse.data.getPost.title).toEqual('Test Get'); - } catch (e) { - logDebug(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('listPosts query', async () => { - try { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test List" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test List'); - const listResponse = await GRAPHQL_CLIENT.query( - `query { - listPosts { - items { - id - title - } - } - }`, - {}, - ); - expect(listResponse.data.listPosts.items).toBeDefined(); - const items = listResponse.data.listPosts.items; - expect(items.length).toBeGreaterThan(0); - } catch (e) { - logDebug(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('listPosts query with filter', async () => { - try { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test List with filter" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test List with filter'); - const listWithFilterResponse = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { - title: { - contains: "List with filter" - } - }) { - items { - id - title - } - } - }`, - {}, - ); - logDebug(JSON.stringify(listWithFilterResponse, null, 4)); - expect(listWithFilterResponse.data.listPosts.items).toBeDefined(); - const items = listWithFilterResponse.data.listPosts.items; - expect(items.length).toEqual(1); - expect(items[0].title).toEqual('Test List with filter'); - } catch (e) { - logDebug(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('enum filters List', async () => { - try { - await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Appears in New Hope", appearsIn: [NEWHOPE], episode: NEWHOPE }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Appears in Jedi", appearsIn: [JEDI], episode: JEDI }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Appears in Empire", appearsIn: [EMPIRE], episode: EMPIRE }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - - await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Appears in Empire & JEDI", appearsIn: [EMPIRE, JEDI] }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - - // filter list of enums - const appearsInWithFilterResponseJedi = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { appearsIn: {eq: [JEDI]}}) { - items { - title - id - } - } - } - `, - {}, - ); - expect(appearsInWithFilterResponseJedi.data.listPosts.items).toBeDefined(); - const items = appearsInWithFilterResponseJedi.data.listPosts.items; - logDebug(items); - expect(items.length).toEqual(1); - expect(items[0].title).toEqual('Appears in Jedi'); - - const appearsInWithFilterResponseNonJedi = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { appearsIn: {ne: [JEDI]}}) { - items { - title - id - } - } - } - `, - {}, - ); - logDebug(JSON.stringify(appearsInWithFilterResponseNonJedi)); - expect(appearsInWithFilterResponseNonJedi.data.listPosts.items).toBeDefined(); - const appearsInNonJediItems = appearsInWithFilterResponseNonJedi.data.listPosts.items; - expect(appearsInNonJediItems.length).toEqual(3); - appearsInNonJediItems.forEach((item) => { - expect(['Appears in Empire & JEDI', 'Appears in New Hope', 'Appears in Empire'].includes(item.title)).toBeTruthy(); - }); - - const appearsInContainingJedi = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { appearsIn: {contains: JEDI }}) { - items { - title - id - } - } - } - `, - {}, - ); - expect(appearsInContainingJedi.data.listPosts.items).toBeDefined(); - const appearsInWithJediItems = appearsInContainingJedi.data.listPosts.items; - expect(appearsInWithJediItems.length).toEqual(2); - appearsInWithJediItems.forEach((item) => { - expect(['Appears in Empire & JEDI', 'Appears in Jedi'].includes(item.title)).toBeTruthy(); - }); - - const appearsInNotContainingJedi = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { appearsIn: {notContains: JEDI }}) { - items { - title - id - } - } - } - `, - {}, - ); - expect(appearsInNotContainingJedi.data.listPosts.items).toBeDefined(); - const appearsInWithNonJediItems = appearsInNotContainingJedi.data.listPosts.items; - expect(appearsInWithNonJediItems.length).toEqual(2); - appearsInWithNonJediItems.forEach((item) => { - expect(['Appears in New Hope', 'Appears in Empire'].includes(item.title)).toBeTruthy(); - }); - - // enum filter - const jediEpisode = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { episode: {eq: JEDI }}) { - items { - title - id - } - } - } - `, - {}, - ); - expect(jediEpisode.data.listPosts.items).toBeDefined(); - const jediEpisodeItems = jediEpisode.data.listPosts.items; - expect(jediEpisodeItems.length).toEqual(1); - expect(jediEpisodeItems[0].title).toEqual('Appears in Jedi'); - - const nonJediEpisode = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { episode: {ne: JEDI }}) { - items { - title - id - } - } - } - `, - {}, - ); - expect(nonJediEpisode.data.listPosts.items).toBeDefined(); - const nonJediEpisodeItems = nonJediEpisode.data.listPosts.items; - expect(nonJediEpisodeItems.length).toEqual(3); - nonJediEpisodeItems.forEach((item) => { - expect(['Appears in New Hope', 'Appears in Empire', 'Appears in Empire & JEDI'].includes(item.title)).toBeTruthy(); - }); - } catch (e) { - logDebug(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('createPost mutation with non-model types', async () => { - try { - const response = await GRAPHQL_CLIENT.query( - `mutation CreatePost($input: CreatePostInput!) { - createPost(input: $input) { - id - title - createdAt - updatedAt - metadata { - tags { - published - metadata { - tags { - published - } - } - } - } - appearsIn - } - }`, - { - input: { - title: 'Check that metadata exists', - metadata: { - tags: { - published: true, - metadata: { - tags: { - published: false, - }, - }, - }, - }, - appearsIn: ['NEWHOPE'], - }, - }, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Check that metadata exists'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.metadata).toBeDefined(); - expect(response.data.createPost.metadata.tags.published).toEqual(true); - expect(response.data.createPost.metadata.tags.metadata.tags.published).toEqual(false); - expect(response.data.createPost.appearsIn).toEqual(['NEWHOPE']); - } catch (e) { - logDebug(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('updatePost mutation with non-model types', async () => { - try { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Update" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Update'); - const updateResponse = await GRAPHQL_CLIENT.query( - `mutation UpdatePost($input: UpdatePostInput!) { - updatePost(input: $input) { - id - title - createdAt - updatedAt - metadata { - tags { - published - metadata { - tags { - published - } - } - } - } - appearsIn - } - }`, - { - input: { - id: createResponse.data.createPost.id, - title: 'Add some metadata', - metadata: { - tags: { - published: true, - metadata: { - tags: { - published: false, - }, - }, - }, - }, - appearsIn: ['NEWHOPE', 'EMPIRE'], - }, - }, - ); - expect(updateResponse.data.updatePost.title).toEqual('Add some metadata'); - expect(updateResponse.data.updatePost.metadata).toBeDefined(); - expect(updateResponse.data.updatePost.metadata.tags.published).toEqual(true); - expect(updateResponse.data.updatePost.metadata.tags.metadata.tags.published).toEqual(false); - expect(updateResponse.data.updatePost.appearsIn).toEqual(['NEWHOPE', 'EMPIRE']); - } catch (e) { - logDebug(e); - // fail - expect(e).toBeUndefined(); - } -}); diff --git a/packages/amplify-util-mock/src/__e2e__/function-transformer.e2e.test.ts b/packages/amplify-util-mock/src/__e2e__/function-transformer.e2e.test.ts deleted file mode 100644 index 448b4e127a..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/function-transformer.e2e.test.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { FunctionTransformer } from 'graphql-function-transformer'; -import { FeatureFlagProvider, GraphQLTransform } from 'graphql-transformer-core'; -import { GraphQLClient } from './utils/graphql-client'; -import { deploy, logDebug } from './utils/index'; - -jest.setTimeout(2000000); - -const ECHO_FUNCTION_NAME = `echoFunction`; -const HELLO_FUNCTION_NAME = `hello`; - -let GRAPHQL_CLIENT = undefined; -let server; - -beforeAll(async () => { - const validSchema = ` - type Query { - echo(msg: String!): Context @function(name: "${ECHO_FUNCTION_NAME}") - duplicate(msg: String!): Context @function(name: "${ECHO_FUNCTION_NAME}") - pipeline(msg: String!): String - @function(name: "${ECHO_FUNCTION_NAME}") - @function(name: "${HELLO_FUNCTION_NAME}") - pipelineReverse(msg: String!): Context - @function(name: "${HELLO_FUNCTION_NAME}") - @function(name: "${ECHO_FUNCTION_NAME}") - } - type Context { - arguments: Arguments - typeName: String - fieldName: String - } - type Arguments { - msg: String! - } - `; - try { - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new FunctionTransformer()], - featureFlags: { - getBoolean: (name) => name === 'improvePluralization', - } as FeatureFlagProvider, - }); - const out = transformer.transform(validSchema); - - const result = await deploy(out); - server = result.simulator; - - const endpoint = server.url + '/graphql'; - logDebug(`Using graphql url: ${endpoint}`); - - const apiKey = result.config.appSync.apiKey; - GRAPHQL_CLIENT = new GraphQLClient(endpoint, { 'x-api-key': apiKey }); - } catch (e) { - logDebug(e); - console.warn(`Could not setup function: ${e}`); - } -}); - -afterAll(async () => { - try { - if (server) { - await server.stop(); - } - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -/** - * Test queries below - */ -test('simple echo function', async () => { - const response = await GRAPHQL_CLIENT.query( - `query { - echo(msg: "Hello") { - arguments { - msg - } - typeName - fieldName - } - }`, - {}, - ); - logDebug(JSON.stringify(response, null, 4)); - expect(response.data.echo.arguments.msg).toEqual('Hello'); - expect(response.data.echo.typeName).toEqual('Query'); - expect(response.data.echo.fieldName).toEqual('echo'); -}); - -test('simple duplicate function', async () => { - const response = await GRAPHQL_CLIENT.query( - `query { - duplicate(msg: "Hello") { - arguments { - msg - } - typeName - fieldName - } - }`, - {}, - ); - logDebug(JSON.stringify(response, null, 4)); - expect(response.data.duplicate.arguments.msg).toEqual('Hello'); - expect(response.data.duplicate.typeName).toEqual('Query'); - expect(response.data.duplicate.fieldName).toEqual('duplicate'); -}); - -test('pipeline of @function(s)', async () => { - const response = await GRAPHQL_CLIENT.query( - `query { - pipeline(msg: "IGNORED") - }`, - {}, - ); - logDebug(JSON.stringify(response, null, 4)); - expect(response.data.pipeline).toEqual('Hello, world!'); -}); - -test('pipelineReverse of @function(s)', async () => { - const response = await GRAPHQL_CLIENT.query( - `query { - pipelineReverse(msg: "Hello") { - arguments { - msg - } - typeName - fieldName - } - }`, - {}, - ); - logDebug(JSON.stringify(response, null, 4)); - expect(response.data.pipelineReverse.arguments.msg).toEqual('Hello'); - expect(response.data.pipelineReverse.typeName).toEqual('Query'); - expect(response.data.pipelineReverse.fieldName).toEqual('pipelineReverse'); -}); diff --git a/packages/amplify-util-mock/src/__e2e__/key-transformer.e2e.test.ts b/packages/amplify-util-mock/src/__e2e__/key-transformer.e2e.test.ts deleted file mode 100644 index b3cc5bb590..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/key-transformer.e2e.test.ts +++ /dev/null @@ -1,745 +0,0 @@ -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { FeatureFlagProvider, GraphQLTransform } from 'graphql-transformer-core'; -import { KeyTransformer } from 'graphql-key-transformer'; -import { GraphQLClient } from './utils/graphql-client'; -import { deploy, launchDDBLocal, logDebug, terminateDDB } from './utils/index'; - -jest.setTimeout(2000000); - -let GRAPHQL_ENDPOINT: string = undefined; -let GRAPHQL_CLIENT: GraphQLClient = undefined; -let ddbEmulator = null; -let dbPath = null; -let server; - -beforeAll(async () => { - const validSchema = ` - type Order @model @key(fields: ["customerEmail", "createdAt"]) { - customerEmail: String! - createdAt: String! - orderId: ID! - } - type Customer @model @key(fields: ["email"]) { - email: String! - addresslist: [String] - username: String - } - type Item @model - @key(fields: ["orderId", "status", "createdAt"]) - @key(name: "ByStatus", fields: ["status", "createdAt"], queryField: "itemsByStatus") - @key(name: "ByCreatedAt", fields: ["createdAt", "status"], queryField: "itemsByCreatedAt") - { - orderId: ID! - status: Status! - createdAt: AWSDateTime! - name: String! - } - enum Status { - DELIVERED IN_TRANSIT PENDING UNKNOWN - } - type ShippingUpdate @model - @key(name: "ByOrderItemStatus", fields: ["orderId", "itemId", "status"], queryField: "shippingUpdates") - { - id: ID! - orderId: ID - itemId: ID - status: Status - name: String - } - # Issue #2606 test type to ensure mocking starts successfully with 2 LSIs - type TypeWithLSI @model - @key(fields: ["id", "updatedAt"]) - @key(name: "BySpending", fields: ["id", "totalSpending"]) - @key(name: "ByAttendance", fields: ["id", "totalAttendance"]) - { - id: ID! - totalSpending: Int! - totalAttendance: Int! - createdAt: AWSDateTime - updatedAt: AWSDateTime! - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - featureFlags: { - getBoolean: (name) => name === 'improvePluralization', - } as FeatureFlagProvider, - }); - const out = transformer.transform(validSchema); - let ddbClient; - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - const result = await deploy(out, ddbClient); - server = result.simulator; - - GRAPHQL_ENDPOINT = server.url + '/graphql'; - logDebug(`Using graphql url: ${GRAPHQL_ENDPOINT}`); - - const apiKey = result.config.appSync.apiKey; - logDebug(apiKey); - GRAPHQL_CLIENT = new GraphQLClient(GRAPHQL_ENDPOINT, { 'x-api-key': apiKey }); -}); - -afterAll(async () => { - if (server) { - await server.stop(); - } - await terminateDDB(ddbEmulator, dbPath); -}); - -/** - * Test queries below - */ -test('next token with key', async () => { - const status = 'PENDING'; - const createdAt = '2019-06-06T00:01:01.000Z'; - // createItems - await createItem('order1', status, 'item1', '2019-01-06T00:01:01.000Z'); - await createItem('order2', status, 'item2', '2019-02-06T00:01:01.000Z'); - await createItem('order3', status, 'item3', '2019-03-06T00:01:01.000Z'); - await createItem('order4', status, 'item4', '2019-06-06T00:01:01.000Z'); - // query itemsByCreatedAt with limit of 2 - // const items = await itemsByCreatedAt(createdAt, { beginsWith: status }, 2); - const items = await itemsByStatus(status, { beginsWith: '2019' }, 2); - expect(items.data).toBeDefined(); - const itemsNextToken = items.data.itemsByStatus.nextToken; - expect(itemsNextToken).toBeDefined(); - // get first two values - expect(items.data.itemsByStatus.items).toHaveLength(2); - expect(items.data.itemsByStatus.items).toEqual( - expect.arrayContaining([ - expect.objectContaining({ orderId: 'order1', name: 'item1' }), - expect.objectContaining({ orderId: 'order2', name: 'item2' }), - ]), - ); - // use next token to get other values - const items2 = await itemsByStatus(status, { beginsWith: '2019' }, 2, itemsNextToken); - expect(items2.data).toBeDefined(); - // get last two values - expect(items2.data.itemsByStatus.items).toHaveLength(2); - expect(items2.data.itemsByStatus.items).toEqual( - expect.arrayContaining([ - expect.objectContaining({ orderId: 'order3', name: 'item3' }), - expect.objectContaining({ orderId: 'order4', name: 'item4' }), - ]), - ); - // deleteItems - await deleteItem('order1', status, createdAt); - await deleteItem('order2', status, createdAt); - await deleteItem('order3', status, createdAt); - await deleteItem('order4', status, createdAt); -}); -test('getX with a two part primary key.', async () => { - const order1 = await createOrder('test@gmail.com', '1'); - const getOrder1 = await getOrder('test@gmail.com', order1.data.createOrder.createdAt); - expect(getOrder1.data.getOrder.orderId).toEqual('1'); -}); - -test('updateX with a two part primary key.', async () => { - const order2 = await createOrder('test3@gmail.com', '2'); - let getOrder2 = await getOrder('test3@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder.orderId).toEqual('2'); - const updateOrder2 = await updateOrder('test3@gmail.com', order2.data.createOrder.createdAt, '3'); - expect(updateOrder2.data.updateOrder.orderId).toEqual('3'); - getOrder2 = await getOrder('test3@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder.orderId).toEqual('3'); -}); - -test('deleteX with a two part primary key.', async () => { - const order2 = await createOrder('test2@gmail.com', '2'); - let getOrder2 = await getOrder('test2@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder.orderId).toEqual('2'); - const delOrder2 = await deleteOrder('test2@gmail.com', order2.data.createOrder.createdAt); - expect(delOrder2.data.deleteOrder.orderId).toEqual('2'); - getOrder2 = await getOrder('test2@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder).toBeNull(); -}); - -test('getX with a three part primary key', async () => { - const item1 = await createItem('1', 'PENDING', 'item1'); - const getItem1 = await getItem('1', 'PENDING', item1.data.createItem.createdAt); - expect(getItem1.data.getItem.orderId).toEqual('1'); - expect(getItem1.data.getItem.status).toEqual('PENDING'); -}); - -test('updateX with a three part primary key.', async () => { - const item2 = await createItem('2', 'PENDING', 'item2'); - let getItem2 = await getItem('2', 'PENDING', item2.data.createItem.createdAt); - expect(getItem2.data.getItem.orderId).toEqual('2'); - const updateItem2 = await updateItem('2', 'PENDING', item2.data.createItem.createdAt, 'item2.1'); - expect(updateItem2.data.updateItem.name).toEqual('item2.1'); - getItem2 = await getItem('2', 'PENDING', item2.data.createItem.createdAt); - expect(getItem2.data.getItem.name).toEqual('item2.1'); -}); - -test('deleteX with a three part primary key.', async () => { - const item3 = await createItem('3', 'IN_TRANSIT', 'item3'); - let getItem3 = await getItem('3', 'IN_TRANSIT', item3.data.createItem.createdAt); - expect(getItem3.data.getItem.name).toEqual('item3'); - const delItem3 = await deleteItem('3', 'IN_TRANSIT', item3.data.createItem.createdAt); - expect(delItem3.data.deleteItem.name).toEqual('item3'); - getItem3 = await getItem('3', 'IN_TRANSIT', item3.data.createItem.createdAt); - expect(getItem3.data.getItem).toBeNull(); -}); - -test('listX with three part primary key.', async () => { - const hashKey = 'TEST_LIST_ID'; - await createItem(hashKey, 'IN_TRANSIT', 'list1', '2018-01-01T00:01:01.000Z'); - await createItem(hashKey, 'PENDING', 'list2', '2018-06-01T00:01:01.000Z'); - await createItem(hashKey, 'PENDING', 'item3', '2018-09-01T00:01:01.000Z'); - let items = await listItem(undefined); - expect(items.data.listItems.items.length).toBeGreaterThan(0); - items = await listItem(hashKey); - expect(items.data.listItems.items).toHaveLength(3); - items = await listItem(hashKey, { beginsWith: { status: 'PENDING' } }); - expect(items.data.listItems.items).toHaveLength(2); - items = await listItem(hashKey, { beginsWith: { status: 'IN_TRANSIT' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { - beginsWith: { status: 'PENDING', createdAt: '2018-09' }, - }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { - eq: { status: 'PENDING', createdAt: '2018-09-01T00:01:01.000Z' }, - }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { - between: [ - { status: 'PENDING', createdAt: '2018-08-01' }, - { status: 'PENDING', createdAt: '2018-10-01' }, - ], - }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { - gt: { status: 'PENDING', createdAt: '2018-08-1' }, - }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { - ge: { status: 'PENDING', createdAt: '2018-09-01T00:01:01.000Z' }, - }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { - lt: { status: 'IN_TRANSIT', createdAt: '2018-01-02' }, - }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { - le: { status: 'IN_TRANSIT', createdAt: '2018-01-01T00:01:01.000Z' }, - }); - expect(items.data.listItems.items).toHaveLength(1); - await deleteItem(hashKey, 'IN_TRANSIT', '2018-01-01T00:01:01.000Z'); - await deleteItem(hashKey, 'PENDING', '2018-06-01T00:01:01.000Z'); - await deleteItem(hashKey, 'PENDING', '2018-09-01T00:01:01.000Z'); -}); - -test('query with three part secondary key.', async () => { - const hashKey = 'UNKNOWN'; - await createItem('order1', 'UNKNOWN', 'list1', '2018-01-01T00:01:01.000Z'); - await createItem('order2', 'UNKNOWN', 'list2', '2018-06-01T00:01:01.000Z'); - await createItem('order3', 'UNKNOWN', 'item3', '2018-09-01T00:01:01.000Z'); - let items = await itemsByStatus(undefined); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - items = await itemsByStatus(hashKey); - expect(items.data.itemsByStatus.items).toHaveLength(3); - items = await itemsByStatus(hashKey, { beginsWith: '2018-09' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { eq: '2018-09-01T00:01:01.000Z' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { - between: ['2018-08-01', '2018-10-01'], - }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { gt: '2018-08-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { ge: '2018-09-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { lt: '2018-07-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(2); - items = await itemsByStatus(hashKey, { le: '2018-06-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(undefined, { le: '2018-09-01' }); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - await deleteItem('order1', hashKey, '2018-01-01T00:01:01.000Z'); - await deleteItem('order2', hashKey, '2018-06-01T00:01:01.000Z'); - await deleteItem('order3', hashKey, '2018-09-01T00:01:01.000Z'); -}); - -test('query with three part secondary key, where sort key is an enum.', async () => { - const hashKey = '2018-06-01T00:01:01.000Z'; - const sortKey = 'UNKNOWN'; - await createItem('order1', sortKey, 'list1', '2018-01-01T00:01:01.000Z'); - await createItem('order2', sortKey, 'list2', hashKey); - await createItem('order3', sortKey, 'item3', '2018-09-01T00:01:01.000Z'); - let items = await itemsByCreatedAt(undefined); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - items = await itemsByCreatedAt(hashKey); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { beginsWith: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { eq: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { between: [sortKey, sortKey] }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { gt: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(0); - items = await itemsByCreatedAt(hashKey, { ge: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { lt: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(0); - items = await itemsByCreatedAt(hashKey, { le: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(undefined, { le: sortKey }); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - await deleteItem('order1', sortKey, '2018-01-01T00:01:01.000Z'); - await deleteItem('order2', sortKey, hashKey); - await deleteItem('order3', sortKey, '2018-09-01T00:01:01.000Z'); -}); - -test('update mutation validation with three part secondary key.', async () => { - const createResponseMissingLastSortKey = await createShippingUpdate({ orderId: '1sttry', itemId: 'item1', name: '42' }); - expect(createResponseMissingLastSortKey.data.createShippingUpdate).toBeNull(); - expect(createResponseMissingLastSortKey.errors).toHaveLength(1); - - const createResponseMissingFirstSortKey = await createShippingUpdate({ orderId: '2ndtry', status: 'PENDING', name: '43?' }); - expect(createResponseMissingFirstSortKey.data.createShippingUpdate).toBeNull(); - expect(createResponseMissingFirstSortKey.errors).toHaveLength(1); - - await createShippingUpdate({ orderId: 'order1', itemId: 'item1', status: 'PENDING', name: 'name1' }); - const items = await getShippingUpdates('order1'); - expect(items.data.shippingUpdates.items).toHaveLength(1); - const item = items.data.shippingUpdates.items[0]; - expect(item.name).toEqual('name1'); - - const itemsWithFilter = await getShippingUpdatesWithNameFilter('order1', 'name1'); - expect(itemsWithFilter.data.shippingUpdates.items).toHaveLength(1); - const itemWithFilter = itemsWithFilter.data.shippingUpdates.items[0]; - expect(itemWithFilter.name).toEqual('name1'); - - const itemsWithUnknownFilter = await getShippingUpdatesWithNameFilter('order1', 'unknownname'); - expect(itemsWithUnknownFilter.data.shippingUpdates.items).toHaveLength(0); - - const updateResponseMissingLastSortKey = await updateShippingUpdate({ - id: item.id, - orderId: 'order1', - itemId: 'item1', - name: 'name2', - }); - expect(updateResponseMissingLastSortKey.data.updateShippingUpdate).toBeNull(); - expect(updateResponseMissingLastSortKey.errors).toHaveLength(1); - const updateResponseMissingFirstSortKey = await updateShippingUpdate({ - id: item.id, - orderId: 'order1', - status: 'PENDING', - name: 'name3', - }); - expect(updateResponseMissingFirstSortKey.data.updateShippingUpdate).toBeNull(); - expect(updateResponseMissingFirstSortKey.errors).toHaveLength(1); - const updateResponseMissingAllSortKeys = await updateShippingUpdate({ - id: item.id, - orderId: 'order1', - name: 'testing', - }); - expect(updateResponseMissingAllSortKeys.data.updateShippingUpdate.name).toEqual('testing'); - const updateResponseMissingNoKeys = await updateShippingUpdate({ - id: item.id, - orderId: 'order1', - itemId: 'item1', - status: 'PENDING', - name: 'testing2', - }); - expect(updateResponseMissingNoKeys.data.updateShippingUpdate.name).toEqual('testing2'); -}); - -test('Customer Create with list member and secondary key', async () => { - await createCustomer('customer1@email.com', ['thing1', 'thing2'], 'customerusr1'); - const getCustomer1 = await getCustomer('customer1@email.com'); - expect(getCustomer1.data.getCustomer.addresslist).toEqual(['thing1', 'thing2']); -}); - -test('cannot overwrite customer record with custom primary key', async () => { - await createCustomer('customer42@email.com', ['thing1', 'thing2'], 'customerusr42'); - const response = await createCustomer('customer42@email.com', ['thing2'], 'customerusr43'); - expect(response.errors).toBeDefined(); - expect(response.errors[0]).toEqual( - expect.objectContaining({ - message: 'The conditional request failed', - errorType: 'DynamoDB:ConditionalCheckFailedException', - }), - ); -}); - -test('Customer Mutation with list member', async () => { - await updateCustomer('customer1@email.com', ['thing3', 'thing4'], 'new_customerusr1'); - const getCustomer1 = await getCustomer('customer1@email.com'); - expect(getCustomer1.data.getCustomer.addresslist).toEqual(['thing3', 'thing4']); -}); - -async function createCustomer(email: string, addresslist: string[], username: string) { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateCustomer($input: CreateCustomerInput!) { - createCustomer(input: $input) { - email - addresslist - username - } - }`, - { - input: { email, addresslist, username }, - }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function updateCustomer(email: string, addresslist: string[], username: string) { - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateCustomer($input: UpdateCustomerInput!) { - updateCustomer(input: $input) { - email - addresslist - username - } - }`, - { - input: { email, addresslist, username }, - }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function getCustomer(email: string) { - const result = await GRAPHQL_CLIENT.query( - `query GetCustomer($email: String!) { - getCustomer(email: $email) { - email - addresslist - username - } - }`, - { - email, - }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function createOrder(customerEmail: string, orderId: string) { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateOrder($input: CreateOrderInput!) { - createOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, orderId, createdAt: new Date().toISOString() }, - }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function updateOrder(customerEmail: string, createdAt: string, orderId: string) { - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateOrder($input: UpdateOrderInput!) { - updateOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, orderId, createdAt }, - }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function deleteOrder(customerEmail: string, createdAt: string) { - const result = await GRAPHQL_CLIENT.query( - `mutation DeleteOrder($input: DeleteOrderInput!) { - deleteOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, createdAt }, - }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function getOrder(customerEmail: string, createdAt: string) { - const result = await GRAPHQL_CLIENT.query( - `query GetOrder($customerEmail: String!, $createdAt: String!) { - getOrder(customerEmail: $customerEmail, createdAt: $createdAt) { - customerEmail - orderId - createdAt - } - }`, - { customerEmail, createdAt }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function createItem(orderId: string, status: string, name: string, createdAt: string = new Date().toISOString()) { - const input = { status, orderId, name, createdAt }; - const result = await GRAPHQL_CLIENT.query( - `mutation CreateItem($input: CreateItemInput!) { - createItem(input: $input) { - orderId - status - createdAt - name - } - }`, - { - input, - }, - ); - logDebug(`Running create: ${JSON.stringify(input)}`); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function updateItem(orderId: string, status: string, createdAt: string, name: string) { - const input = { status, orderId, createdAt, name }; - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateItem($input: UpdateItemInput!) { - updateItem(input: $input) { - orderId - status - createdAt - name - } - }`, - { - input, - }, - ); - logDebug(`Running create: ${JSON.stringify(input)}`); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function deleteItem(orderId: string, status: string, createdAt: string) { - const input = { orderId, status, createdAt }; - const result = await GRAPHQL_CLIENT.query( - `mutation DeleteItem($input: DeleteItemInput!) { - deleteItem(input: $input) { - orderId - status - createdAt - name - } - }`, - { - input, - }, - ); - logDebug(`Running delete: ${JSON.stringify(input)}`); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function getItem(orderId: string, status: string, createdAt: string) { - const result = await GRAPHQL_CLIENT.query( - `query GetItem($orderId: ID!, $status: Status!, $createdAt: AWSDateTime!) { - getItem(orderId: $orderId, status: $status, createdAt: $createdAt) { - orderId - status - createdAt - name - } - }`, - { orderId, status, createdAt }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -interface StringKeyConditionInput { - eq?: string; - gt?: string; - ge?: string; - lt?: string; - le?: string; - between?: string[]; - beginsWith?: string; -} - -interface ItemCompositeKeyConditionInput { - eq?: ItemCompositeKeyInput; - gt?: ItemCompositeKeyInput; - ge?: ItemCompositeKeyInput; - lt?: ItemCompositeKeyInput; - le?: ItemCompositeKeyInput; - between?: ItemCompositeKeyInput[]; - beginsWith?: ItemCompositeKeyInput; -} -interface ItemCompositeKeyInput { - status?: string; - createdAt?: string; -} -async function listItem(orderId?: string, statusCreatedAt?: ItemCompositeKeyConditionInput, limit?: number, nextToken?: string) { - const result = await GRAPHQL_CLIENT.query( - `query ListItems($orderId: ID, $statusCreatedAt: ModelItemPrimaryCompositeKeyConditionInput, $limit: Int, $nextToken: String) { - listItems(orderId: $orderId, statusCreatedAt: $statusCreatedAt, limit: $limit, nextToken: $nextToken) { - items { - orderId - status - createdAt - name - } - nextToken - } - }`, - { orderId, statusCreatedAt, limit, nextToken }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function itemsByStatus(status: string, createdAt?: StringKeyConditionInput, limit?: number, nextToken?: string) { - const result = await GRAPHQL_CLIENT.query( - `query ListByStatus($status: Status!, $createdAt: ModelStringKeyConditionInput, $limit: Int, $nextToken: String) { - itemsByStatus(status: $status, createdAt: $createdAt, limit: $limit, nextToken: $nextToken) { - items { - orderId - status - createdAt - name - } - nextToken - } - }`, - { status, createdAt, limit, nextToken }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function itemsByCreatedAt(createdAt: string, status?: StringKeyConditionInput, limit?: number, nextToken?: string) { - const result = await GRAPHQL_CLIENT.query( - `query ListByCreatedAt($createdAt: AWSDateTime!, $status: ModelStringKeyConditionInput, $limit: Int, $nextToken: String) { - itemsByCreatedAt(createdAt: $createdAt, status: $status, limit: $limit, nextToken: $nextToken) { - items { - orderId - status - createdAt - name - } - nextToken - } - }`, - { createdAt, status, limit, nextToken }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -interface CreateShippingInput { - id?: string; - orderId?: string; - status?: string; - itemId?: string; - name?: string; -} - -async function createShippingUpdate(input: CreateShippingInput) { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateShippingUpdate($input: CreateShippingUpdateInput!) { - createShippingUpdate(input: $input) { - orderId - status - itemId - name - id - } - }`, - { - input, - }, - ); - logDebug(`Running create: ${JSON.stringify(input)}`); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -interface UpdateShippingInput { - id: string; - orderId?: string; - status?: string; - itemId?: string; - name?: string; -} -async function updateShippingUpdate(input: UpdateShippingInput) { - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateShippingUpdate($input: UpdateShippingUpdateInput!) { - updateShippingUpdate(input: $input) { - orderId - status - itemId - name - id - } - }`, - { - input, - }, - ); - logDebug(`Running update: ${JSON.stringify(input)}`); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function getShippingUpdates(orderId: string) { - const result = await GRAPHQL_CLIENT.query( - `query GetShippingUpdates($orderId: ID!) { - shippingUpdates(orderId: $orderId) { - items { - id - orderId - status - itemId - name - } - nextToken - } - }`, - { orderId }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function getShippingUpdatesWithNameFilter(orderId: string, name: string) { - const result = await GRAPHQL_CLIENT.query( - `query GetShippingUpdates($orderId: ID!, $name: String) { - shippingUpdates(orderId: $orderId, filter: { name: { eq: $name }}) { - items { - id - orderId - status - itemId - name - } - nextToken - } - }`, - { orderId, name }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} diff --git a/packages/amplify-util-mock/src/__e2e__/key-with-auth.e2e.test.ts b/packages/amplify-util-mock/src/__e2e__/key-with-auth.e2e.test.ts deleted file mode 100644 index ffcc04b612..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/key-with-auth.e2e.test.ts +++ /dev/null @@ -1,295 +0,0 @@ -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { KeyTransformer } from 'graphql-key-transformer'; -import { FeatureFlagProvider, GraphQLTransform } from 'graphql-transformer-core'; -import { signUpAddToGroupAndGetJwtToken } from './utils/cognito-utils'; -import { GraphQLClient } from './utils/graphql-client'; -import { deploy, launchDDBLocal, logDebug, terminateDDB } from './utils/index'; -import 'isomorphic-fetch'; - -jest.setTimeout(2000000); - -let GRAPHQL_ENDPOINT = undefined; -let ddbEmulator = null; -let dbPath = null; -let server; -/** - * Client 1 is logged in and is a member of the Admin group. - */ -let GRAPHQL_CLIENT_1 = undefined; - -/** - * Client 2 is logged in and is a member of the Devs group. - */ -let GRAPHQL_CLIENT_2 = undefined; - -/** - * Client 3 is logged in and has no group memberships. - */ -let GRAPHQL_CLIENT_3 = undefined; - -let USER_POOL_ID = 'fake_user_pool'; - -const USERNAME1 = 'user1@test.com'; -const USERNAME2 = 'user2@test.com'; -const USERNAME3 = 'user3@test.com'; - -const ADMIN_GROUP_NAME = 'Admin'; -const DEVS_GROUP_NAME = 'Devs'; -const PARTICIPANT_GROUP_NAME = 'Participant'; - -beforeAll(async () => { - // Create a stack for the post model with auth enabled. - const validSchema = ` - type Order - @model - @key(fields: ["customerEmail", "orderId"]) - @key(name: "GSI", fields: ["orderId"], queryField: "ordersByOrderId") - @auth(rules: [{ allow: owner, ownerField: "customerEmail" }, { allow: groups, groups: ["Admin"] }]) - { - customerEmail: String! - createdAt: String - orderId: String! - } - `; - const transformer = new GraphQLTransform({ - transformers: [ - new DynamoDBModelTransformer(), - new KeyTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - featureFlags: { - getBoolean: (name) => name === 'improvePluralization', - } as FeatureFlagProvider, - }); - - try { - // Clean the bucket - const out = transformer.transform(validSchema); - - let ddbClient; - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - - const result = await deploy(out, ddbClient); - server = result.simulator; - - GRAPHQL_ENDPOINT = server.url + '/graphql'; - logDebug(`Using graphql url: ${GRAPHQL_ENDPOINT}`); - - // Verify we have all the details - expect(GRAPHQL_ENDPOINT).toBeTruthy(); - - const idToken = signUpAddToGroupAndGetJwtToken(USER_POOL_ID, USERNAME1, USERNAME1, [ - ADMIN_GROUP_NAME, - PARTICIPANT_GROUP_NAME, - PARTICIPANT_GROUP_NAME, - ]); - GRAPHQL_CLIENT_1 = new GraphQLClient(GRAPHQL_ENDPOINT, { - Authorization: idToken, - }); - - const idToken2 = signUpAddToGroupAndGetJwtToken(USER_POOL_ID, USERNAME2, USERNAME2, [DEVS_GROUP_NAME]); - GRAPHQL_CLIENT_2 = new GraphQLClient(GRAPHQL_ENDPOINT, { - Authorization: idToken2, - }); - - const idToken3 = signUpAddToGroupAndGetJwtToken(USER_POOL_ID, USERNAME3, USERNAME3, []); - GRAPHQL_CLIENT_3 = new GraphQLClient(GRAPHQL_ENDPOINT, { - Authorization: idToken3, - }); - - // Wait for any propagation to avoid random - // "The security token included in the request is invalid" errors - await new Promise((res) => setTimeout(() => res(), 5000)); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - try { - if (server) { - await server.stop(); - } - await terminateDDB(ddbEmulator, dbPath); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -/** - * Test queries below - */ -test('createOrder mutation as admin', async () => { - const response = await createOrder(GRAPHQL_CLIENT_1, USERNAME2, 'order1'); - expect(response.data.createOrder.customerEmail).toBeDefined(); - expect(response.data.createOrder.orderId).toEqual('order1'); - expect(response.data.createOrder.createdAt).toBeDefined(); -}); - -test('createOrder mutation as owner', async () => { - const response = await createOrder(GRAPHQL_CLIENT_2, USERNAME2, 'order2'); - expect(response.data.createOrder.customerEmail).toBeDefined(); - expect(response.data.createOrder.orderId).toEqual('order2'); - expect(response.data.createOrder.createdAt).toBeDefined(); -}); - -test('createOrder mutation as owner', async () => { - const response = await createOrder(GRAPHQL_CLIENT_3, USERNAME2, 'order3'); - expect(response.data.createOrder).toBeNull(); - expect(response.errors).toHaveLength(1); -}); - -test('list orders as owner', async () => { - await createOrder(GRAPHQL_CLIENT_3, USERNAME3, 'owned1'); - await createOrder(GRAPHQL_CLIENT_3, USERNAME3, 'owned2'); - const listResponse = await listOrders(GRAPHQL_CLIENT_3, USERNAME3, { - beginsWith: 'owned', - }); - expect(listResponse.data.listOrders.items).toHaveLength(2); -}); - -test('list orders as non owner', async () => { - await createOrder(GRAPHQL_CLIENT_3, USERNAME3, 'unowned1'); - await createOrder(GRAPHQL_CLIENT_3, USERNAME3, 'unowned2'); - const listResponse = await listOrders(GRAPHQL_CLIENT_2, USERNAME3, { - beginsWith: 'unowned', - }); - expect(listResponse.data.listOrders.items).toHaveLength(0); -}); - -test('get orders as owner', async () => { - await createOrder(GRAPHQL_CLIENT_2, USERNAME2, 'myobj'); - const getResponse = await getOrder(GRAPHQL_CLIENT_2, USERNAME2, 'myobj'); - expect(getResponse.data.getOrder.orderId).toEqual('myobj'); -}); - -test('get orders as non-owner', async () => { - await createOrder(GRAPHQL_CLIENT_2, USERNAME2, 'notmyobj'); - const getResponse = await getOrder(GRAPHQL_CLIENT_3, USERNAME2, 'notmyobj'); - expect(getResponse.data.getOrder).toBeNull(); - expect(getResponse.errors).toHaveLength(1); -}); - -test('query orders as owner', async () => { - await createOrder(GRAPHQL_CLIENT_3, USERNAME3, 'ownedby3a'); - const listResponse = await ordersByOrderId(GRAPHQL_CLIENT_3, 'ownedby3a'); - expect(listResponse.data.ordersByOrderId.items).toHaveLength(1); -}); - -test('query orders as non owner', async () => { - await createOrder(GRAPHQL_CLIENT_3, USERNAME3, 'notownedby2a'); - const listResponse = await ordersByOrderId(GRAPHQL_CLIENT_2, 'notownedby2a'); - expect(listResponse.data.ordersByOrderId.items).toHaveLength(0); -}); - -async function createOrder(client: GraphQLClient, customerEmail: string, orderId: string) { - const result = await client.query( - `mutation CreateOrder($input: CreateOrderInput!) { - createOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, orderId }, - }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function updateOrder(client: GraphQLClient, customerEmail: string, orderId: string) { - const result = await client.query( - `mutation UpdateOrder($input: UpdateOrderInput!) { - updateOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, orderId }, - }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function deleteOrder(client: GraphQLClient, customerEmail: string, orderId: string) { - const result = await client.query( - `mutation DeleteOrder($input: DeleteOrderInput!) { - deleteOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, orderId }, - }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function getOrder(client: GraphQLClient, customerEmail: string, orderId: string) { - const result = await client.query( - `query GetOrder($customerEmail: String!, $orderId: String!) { - getOrder(customerEmail: $customerEmail, orderId: $orderId) { - customerEmail - orderId - createdAt - } - }`, - { customerEmail, orderId }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function listOrders(client: GraphQLClient, customerEmail: string, orderId: { beginsWith: string }) { - const result = await client.query( - `query ListOrder($customerEmail: String, $orderId: ModelStringKeyConditionInput) { - listOrders(customerEmail: $customerEmail, orderId: $orderId) { - items { - customerEmail - orderId - createdAt - } - nextToken - } - }`, - { customerEmail, orderId }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function ordersByOrderId(client: GraphQLClient, orderId: string) { - const result = await client.query( - `query OrdersByOrderId($orderId: String!) { - ordersByOrderId(orderId: $orderId) { - items { - customerEmail - orderId - createdAt - } - nextToken - } - }`, - { orderId }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} diff --git a/packages/amplify-util-mock/src/__e2e__/model-auth-transformer.e2e.test.ts b/packages/amplify-util-mock/src/__e2e__/model-auth-transformer.e2e.test.ts deleted file mode 100644 index c81e7e9ab2..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/model-auth-transformer.e2e.test.ts +++ /dev/null @@ -1,2623 +0,0 @@ -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { FeatureFlagProvider, GraphQLTransform } from 'graphql-transformer-core'; -import { signUpAddToGroupAndGetJwtToken } from './utils/cognito-utils'; -import { GraphQLClient } from './utils/graphql-client'; -import { deploy, launchDDBLocal, logDebug, terminateDDB } from './utils/index'; -import 'isomorphic-fetch'; - -jest.setTimeout(2000000); - -let GRAPHQL_ENDPOINT = undefined; - -let ddbEmulator = null; -let dbPath = null; -let server; -/** - * Client 1 is logged in and is a member of the Admin group. - */ -let GRAPHQL_CLIENT_1 = undefined; - -/** - * Client 1 is logged in and is a member of the Admin group via an access token. - */ -let GRAPHQL_CLIENT_1_ACCESS = undefined; - -/** - * Client 2 is logged in and is a member of the Devs group. - */ -let GRAPHQL_CLIENT_2 = undefined; - -/** - * Client 3 is logged in and has no group memberships. - */ -let GRAPHQL_CLIENT_3 = undefined; - -const USER_POOL_ID = 'fake_user_pool'; - -const USERNAME1 = 'user1@test.com'; -const USERNAME2 = 'user2@test.com'; -const USERNAME3 = 'user3@test.com'; - -const ADMIN_GROUP_NAME = 'Admin'; -const DEVS_GROUP_NAME = 'Devs'; -const PARTICIPANT_GROUP_NAME = 'Participant'; -const WATCHER_GROUP_NAME = 'Watcher'; - -beforeAll(async () => { - // Create a stack for the post model with auth enabled. - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner }]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - owner: String - } - type Salary @model @auth( - rules: [ - {allow: owner}, - {allow: groups, groups: ["Admin"]} - ] - ) { - id: ID! - wage: Int - owner: String - } - type AdminNote @model @auth( - rules: [ - {allow: groups, groups: ["Admin"]} - ] - ) { - id: ID! - content: String! - } - type ManyGroupProtected @model @auth(rules: [{allow: groups, groupsField: "groups"}]) { - id: ID! - value: Int - groups: [String] - } - type SingleGroupProtected @model @auth(rules: [{allow: groups, groupsField: "group"}]) { - id: ID! - value: Int - group: String - } - type PWProtected - @auth(rules: [ - {allow: groups, groupsField: "participants", mutations: [update, delete], queries: [get, list]}, - {allow: groups, groupsField: "watchers", mutations: [], queries: [get, list]} - ]) - @model - { - id: ID! - content: String! - participants: String - watchers: String - } - type AllThree - @auth(rules: [ - {allow: owner, identityField: "username" }, - {allow: owner, ownerField: "editors", identityField: "cognito:username" }, - {allow: groups, groups: ["Admin"]}, - {allow: groups, groups: ["Execs"]}, - {allow: groups, groupsField: "groups"}, - {allow: groups, groupsField: "alternativeGroup"} - ]) - @model - { - id: ID! - owner: String - editors: [String] - groups: [String] - alternativeGroup: String - } - # The owner should always start with https://cognito-idp - type TestIdentity @model @auth(rules: [{ allow: owner, identityField: "iss" }]) { - id: ID! - title: String! - owner: String - } - type OwnerReadProtected @model @auth(rules: [{ allow: owner, operations: [read] }]) { - id: ID! - content: String - owner: String - } - type OwnerCreateUpdateDeleteProtected @model @auth(rules: [{ allow: owner, operations: [create, update, delete] }]) { - id: ID! - content: String - owner: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - featureFlags: { - getBoolean: (name) => name === 'improvePluralization', - } as FeatureFlagProvider, - }); - - try { - const out = transformer.transform(validSchema); - - let ddbClient; - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - - const result = await deploy(out, ddbClient); - server = result.simulator; - - GRAPHQL_ENDPOINT = server.url + '/graphql'; - logDebug(`Using graphql url: ${GRAPHQL_ENDPOINT}`); - - const apiKey = result.config.appSync.apiKey; - - const idToken = signUpAddToGroupAndGetJwtToken(USER_POOL_ID, USERNAME1, USERNAME1, [ - ADMIN_GROUP_NAME, - PARTICIPANT_GROUP_NAME, - WATCHER_GROUP_NAME, - ]); - GRAPHQL_CLIENT_1 = new GraphQLClient(GRAPHQL_ENDPOINT, { - Authorization: idToken, - }); - - const accessToken = signUpAddToGroupAndGetJwtToken( - USER_POOL_ID, - USERNAME1, - USERNAME1, - [ADMIN_GROUP_NAME, PARTICIPANT_GROUP_NAME, WATCHER_GROUP_NAME], - 'access', - ); - GRAPHQL_CLIENT_1_ACCESS = new GraphQLClient(GRAPHQL_ENDPOINT, { - Authorization: accessToken, - }); - - const idToken2 = signUpAddToGroupAndGetJwtToken(USER_POOL_ID, USERNAME2, USERNAME2, [DEVS_GROUP_NAME]); - GRAPHQL_CLIENT_2 = new GraphQLClient(GRAPHQL_ENDPOINT, { - Authorization: idToken2, - }); - - const idToken3 = signUpAddToGroupAndGetJwtToken(USER_POOL_ID, USERNAME2, USERNAME3, []); - GRAPHQL_CLIENT_3 = new GraphQLClient(GRAPHQL_ENDPOINT, { - Authorization: idToken3, - }); - - // Wait for any propagation to avoid random - // "The security token included in the request is invalid" errors - await new Promise((res) => setTimeout(() => res(), 5000)); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - try { - if (server) { - await server.stop(); - } - await terminateDDB(ddbEmulator, dbPath); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -/** - * Test queries below - */ -test('createPost mutation', async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - logDebug(response); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.owner).toEqual(USERNAME1); - - logDebug('Using access token based client\n'); - const response2 = await GRAPHQL_CLIENT_1_ACCESS.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - logDebug(response2); - expect(response2.data.createPost.id).toBeDefined(); - expect(response2.data.createPost.title).toEqual('Hello, World!'); - expect(response2.data.createPost.createdAt).toBeDefined(); - expect(response2.data.createPost.updatedAt).toBeDefined(); - expect(response2.data.createPost.owner).toEqual(USERNAME1); -}); - -test('getPost query when authorized', async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - logDebug(response); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.owner).toEqual(USERNAME1); - const getResponse = await GRAPHQL_CLIENT_1.query( - `query { - getPost(id: "${response.data.createPost.id}") { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - logDebug(getResponse); - expect(getResponse.data.getPost.id).toBeDefined(); - expect(getResponse.data.getPost.title).toEqual('Hello, World!'); - expect(getResponse.data.getPost.createdAt).toBeDefined(); - expect(getResponse.data.getPost.updatedAt).toBeDefined(); - expect(getResponse.data.getPost.owner).toEqual(USERNAME1); - - const getResponseAccess = await GRAPHQL_CLIENT_1_ACCESS.query( - `query { - getPost(id: "${response.data.createPost.id}") { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(getResponseAccess.data.getPost.id).toBeDefined(); - expect(getResponseAccess.data.getPost.title).toEqual('Hello, World!'); - expect(getResponseAccess.data.getPost.createdAt).toBeDefined(); - expect(getResponseAccess.data.getPost.updatedAt).toBeDefined(); - expect(getResponseAccess.data.getPost.owner).toEqual(USERNAME1); -}); - -test('getPost query when not authorized', async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.owner).toBeDefined(); - const getResponse = await GRAPHQL_CLIENT_2.query( - `query { - getPost(id: "${response.data.createPost.id}") { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(getResponse.data.getPost).toEqual(null); - expect(getResponse.errors.length).toEqual(1); - expect((getResponse.errors[0] as any).errorType).toEqual('Unauthorized'); -}); - -test('updatePost mutation when authorized', async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.owner).toEqual(USERNAME1); - const updateResponse = await GRAPHQL_CLIENT_1.query( - `mutation { - updatePost(input: { id: "${response.data.createPost.id}", title: "Bye, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(updateResponse.data.updatePost.id).toEqual(response.data.createPost.id); - expect(updateResponse.data.updatePost.title).toEqual('Bye, World!'); - expect(updateResponse.data.updatePost.updatedAt > response.data.createPost.updatedAt).toEqual(true); - - const updateResponseAccess = await GRAPHQL_CLIENT_1_ACCESS.query( - `mutation { - updatePost(input: { id: "${response.data.createPost.id}", title: "Bye, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(updateResponseAccess.data.updatePost.id).toEqual(response.data.createPost.id); - expect(updateResponseAccess.data.updatePost.title).toEqual('Bye, World!'); - expect(updateResponseAccess.data.updatePost.updatedAt > response.data.createPost.updatedAt).toEqual(true); -}); - -test('updatePost mutation when not authorized', async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.owner).toBeDefined(); - const updateResponse = await GRAPHQL_CLIENT_2.query( - `mutation { - updatePost(input: { id: "${response.data.createPost.id}", title: "Bye, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(updateResponse.data.updatePost).toEqual(null); - expect(updateResponse.errors.length).toEqual(1); - logDebug(updateResponse); - expect((updateResponse.errors[0] as any).data).toBeNull(); - expect((updateResponse.errors[0] as any).errorType).toEqual('DynamoDB:ConditionalCheckFailedException'); -}); - -test('deletePost mutation when authorized', async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.owner).toEqual(USERNAME1); - const deleteResponse = await GRAPHQL_CLIENT_1.query( - `mutation { - deletePost(input: { id: "${response.data.createPost.id}" }) { - id - } - }`, - {}, - ); - expect(deleteResponse.data.deletePost.id).toEqual(response.data.createPost.id); - - const responseAccess = await GRAPHQL_CLIENT_1_ACCESS.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(responseAccess.data.createPost.id).toBeDefined(); - expect(responseAccess.data.createPost.title).toEqual('Hello, World!'); - expect(responseAccess.data.createPost.createdAt).toBeDefined(); - expect(responseAccess.data.createPost.updatedAt).toBeDefined(); - expect(responseAccess.data.createPost.owner).toEqual(USERNAME1); - const deleteResponseAccess = await GRAPHQL_CLIENT_1_ACCESS.query( - `mutation { - deletePost(input: { id: "${responseAccess.data.createPost.id}" }) { - id - } - }`, - {}, - ); - expect(deleteResponseAccess.data.deletePost.id).toEqual(responseAccess.data.createPost.id); -}); - -test('deletePost mutation when not authorized', async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.owner).toEqual(USERNAME1); - const deleteResponse = await GRAPHQL_CLIENT_2.query( - `mutation { - deletePost(input: { id: "${response.data.createPost.id}" }) { - id - } - }`, - {}, - ); - expect(deleteResponse.data.deletePost).toEqual(null); - expect(deleteResponse.errors.length).toEqual(1); - expect((deleteResponse.errors[0] as any).data).toBeNull(); - expect((deleteResponse.errors[0] as any).errorType).toEqual('DynamoDB:ConditionalCheckFailedException'); -}); - -test('listPosts query when authorized', async () => { - const firstPost = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "testing list" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(firstPost.data.createPost.id).toBeDefined(); - expect(firstPost.data.createPost.title).toEqual('testing list'); - expect(firstPost.data.createPost.createdAt).toBeDefined(); - expect(firstPost.data.createPost.updatedAt).toBeDefined(); - expect(firstPost.data.createPost.owner).toEqual(USERNAME1); - const secondPost = await GRAPHQL_CLIENT_2.query( - `mutation { - createPost(input: { title: "testing list" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - // There are two posts but only 1 created by me. - const listResponse = await GRAPHQL_CLIENT_1.query( - `query { - listPosts(filter: { title: { eq: "testing list" } }, limit: 25) { - items { - id - } - } - }`, - {}, - ); - logDebug(JSON.stringify(listResponse, null, 4)); - expect(listResponse.data.listPosts.items.length).toEqual(1); - - const listResponseAccess = await GRAPHQL_CLIENT_1_ACCESS.query( - `query { - listPosts(filter: { title: { eq: "testing list" } }, limit: 25) { - items { - id - } - } - }`, - {}, - ); - logDebug(JSON.stringify(listResponseAccess, null, 4)); - expect(listResponseAccess.data.listPosts.items.length).toEqual(1); -}); - -/** - * Static Group Auth - */ -test(`createSalary w/ Admin group protection authorized`, async () => { - const req = await GRAPHQL_CLIENT_1.query(` - mutation { - createSalary(input: { wage: 10 }) { - id - wage - } - } - `); - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(10); -}); - -test(`update my own salary without admin permission`, async () => { - const req = await GRAPHQL_CLIENT_2.query(` - mutation { - createSalary(input: { wage: 10 }) { - id - wage - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.data.createSalary.wage).toEqual(10); - const req2 = await GRAPHQL_CLIENT_2.query(` - mutation { - updateSalary(input: { id: "${req.data.createSalary.id}", wage: 14 }) { - id - wage - } - } - `); - logDebug(JSON.stringify(req2, null, 4)); - expect(req2.data.updateSalary.wage).toEqual(14); -}); - -test(`updating someone else's salary as an admin`, async () => { - const req = await GRAPHQL_CLIENT_2.query(` - mutation { - createSalary(input: { wage: 11 }) { - id - wage - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(11); - const req2 = await GRAPHQL_CLIENT_1.query(` - mutation { - updateSalary(input: { id: "${req.data.createSalary.id}", wage: 12 }) { - id - wage - } - } - `); - logDebug(JSON.stringify(req2, null, 4)); - expect(req2.data.updateSalary.id).toEqual(req.data.createSalary.id); - expect(req2.data.updateSalary.wage).toEqual(12); -}); - -test(`updating someone else's salary when I am not admin.`, async () => { - const req = await GRAPHQL_CLIENT_1.query(` - mutation { - createSalary(input: { wage: 13 }) { - id - wage - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(13); - const req2 = await GRAPHQL_CLIENT_2.query(` - mutation { - updateSalary(input: { id: "${req.data.createSalary.id}", wage: 14 }) { - id - wage - } - } - `); - expect(req2.data.updateSalary).toEqual(null); - expect(req2.errors.length).toEqual(1); - expect((req2.errors[0] as any).data).toBeNull(); - expect((req2.errors[0] as any).errorType).toEqual('DynamoDB:ConditionalCheckFailedException'); -}); - -test(`deleteSalary w/ Admin group protection authorized`, async () => { - const req = await GRAPHQL_CLIENT_1.query(` - mutation { - createSalary(input: { wage: 15 }) { - id - wage - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(15); - const req2 = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteSalary(input: { id: "${req.data.createSalary.id}" }) { - id - wage - } - } - `); - logDebug(JSON.stringify(req2, null, 4)); - expect(req2.data.deleteSalary.id).toEqual(req.data.createSalary.id); - expect(req2.data.deleteSalary.wage).toEqual(15); -}); - -test(`deleteSalary w/ Admin group protection not authorized`, async () => { - const req = await GRAPHQL_CLIENT_1.query(` - mutation { - createSalary(input: { wage: 16 }) { - id - wage - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(16); - const req2 = await GRAPHQL_CLIENT_2.query(` - mutation { - deleteSalary(input: { id: "${req.data.createSalary.id}" }) { - id - wage - } - } - `); - expect(req2.data.deleteSalary).toEqual(null); - expect(req2.errors.length).toEqual(1); - expect((req2.errors[0] as any).data).toBeNull(); - expect((req2.errors[0] as any).errorType).toEqual('DynamoDB:ConditionalCheckFailedException'); -}); - -test(`and Admin can get a salary created by any user`, async () => { - const req = await GRAPHQL_CLIENT_2.query(` - mutation { - createSalary(input: { wage: 15 }) { - id - wage - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(15); - const req2 = await GRAPHQL_CLIENT_1.query(` - query { - getSalary(id: "${req.data.createSalary.id}") { - id - wage - } - } - `); - expect(req2.data.getSalary.id).toEqual(req.data.createSalary.id); - expect(req2.data.getSalary.wage).toEqual(15); -}); - -test(`owner can create and get a salary when not admin`, async () => { - const req = await GRAPHQL_CLIENT_2.query(` - mutation { - createSalary(input: { wage: 15 }) { - id - wage - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(15); - const req2 = await GRAPHQL_CLIENT_2.query(` - query { - getSalary(id: "${req.data.createSalary.id}") { - id - wage - } - } - `); - expect(req2.data.getSalary.id).toEqual(req.data.createSalary.id); - expect(req2.data.getSalary.wage).toEqual(15); -}); - -test(`getSalary w/ Admin group protection not authorized`, async () => { - const req = await GRAPHQL_CLIENT_1.query(` - mutation { - createSalary(input: { wage: 16 }) { - id - wage - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(16); - const req2 = await GRAPHQL_CLIENT_2.query(` - query { - getSalary(id: "${req.data.createSalary.id}") { - id - wage - } - } - `); - expect(req2.data.getSalary).toEqual(null); - expect(req2.errors.length).toEqual(1); - expect((req2.errors[0] as any).errorType).toEqual('Unauthorized'); -}); - -test(`listSalaries w/ Admin group protection authorized`, async () => { - const req = await GRAPHQL_CLIENT_1.query(` - mutation { - createSalary(input: { wage: 101 }) { - id - wage - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(101); - const req2 = await GRAPHQL_CLIENT_1.query(` - query { - listSalaries(filter: { wage: { eq: 101 }}) { - items { - id - wage - } - } - } - `); - expect(req2.data.listSalaries.items.length).toEqual(1); - expect(req2.data.listSalaries.items[0].id).toEqual(req.data.createSalary.id); - expect(req2.data.listSalaries.items[0].wage).toEqual(101); -}); - -test(`listSalaries w/ Admin group protection not authorized`, async () => { - const req = await GRAPHQL_CLIENT_1.query(` - mutation { - createSalary(input: { wage: 102 }) { - id - wage - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(102); - const req2 = await GRAPHQL_CLIENT_2.query(` - query { - listSalaries(filter: { wage: { eq: 102 }}) { - items { - id - wage - } - } - } - `); - expect(req2.data.listSalaries.items).toEqual([]); -}); - -/** - * Dynamic Group Auth - */ -test(`createManyGroupProtected w/ dynamic group protection authorized`, async () => { - const req = await GRAPHQL_CLIENT_1.query(` - mutation { - createManyGroupProtected(input: { value: 10, groups: ["Admin"] }) { - id - value - groups - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.data.createManyGroupProtected.id).toBeDefined(); - expect(req.data.createManyGroupProtected.value).toEqual(10); - expect(req.data.createManyGroupProtected.groups).toEqual(['Admin']); -}); - -test(`createManyGroupProtected w/ dynamic group protection when not authorized`, async () => { - const req = await GRAPHQL_CLIENT_2.query(` - mutation { - createManyGroupProtected(input: { value: 10, groups: ["Admin"] }) { - id - value - groups - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.data.createManyGroupProtected).toEqual(null); - expect(req.errors.length).toEqual(1); - expect((req.errors[0] as any).errorType).toEqual('Unauthorized'); -}); - -test(`createSingleGroupProtected w/ dynamic group protection authorized`, async () => { - const req = await GRAPHQL_CLIENT_1.query(` - mutation { - createSingleGroupProtected(input: { value: 10, group: "Admin" }) { - id - value - group - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.data.createSingleGroupProtected.id).toBeDefined(); - expect(req.data.createSingleGroupProtected.value).toEqual(10); - expect(req.data.createSingleGroupProtected.group).toEqual('Admin'); -}); - -test(`createSingleGroupProtected w/ dynamic group protection when not authorized`, async () => { - const req = await GRAPHQL_CLIENT_2.query(` - mutation { - createSingleGroupProtected(input: { value: 10, group: "Admin" }) { - id - value - group - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.data.createSingleGroupProtected).toEqual(null); - expect(req.errors.length).toEqual(1); - expect((req.errors[0] as any).errorType).toEqual('Unauthorized'); -}); - -test(`listPWProtecteds when the user is authorized.`, async () => { - const req = await GRAPHQL_CLIENT_1.query(` - mutation { - createPWProtected(input: { content: "Foobie", participants: "${PARTICIPANT_GROUP_NAME}", watchers: "${WATCHER_GROUP_NAME}" }) { - id - content - participants - watchers - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.data.createPWProtected).toBeTruthy(); - - const uReq = await GRAPHQL_CLIENT_1.query(` - mutation { - updatePWProtected(input: { id: "${req.data.createPWProtected.id}", content: "Foobie2" }) { - id - content - participants - watchers - } - } - `); - logDebug(JSON.stringify(uReq, null, 4)); - expect(uReq.data.updatePWProtected).toBeTruthy(); - - const req2 = await GRAPHQL_CLIENT_1.query(` - query { - listPWProtecteds { - items { - id - content - participants - watchers - } - nextToken - } - } - `); - expect(req2.data.listPWProtecteds.items.length).toEqual(1); - expect(req2.data.listPWProtecteds.items[0].id).toEqual(req.data.createPWProtected.id); - expect(req2.data.listPWProtecteds.items[0].content).toEqual('Foobie2'); - - const req3 = await GRAPHQL_CLIENT_1.query(` - query { - getPWProtected(id: "${req.data.createPWProtected.id}") { - id - content - participants - watchers - } - } - `); - logDebug(JSON.stringify(req3, null, 4)); - expect(req3.data.getPWProtected).toBeTruthy(); - - const dReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deletePWProtected(input: { id: "${req.data.createPWProtected.id}" }) { - id - content - participants - watchers - } - } - `); - logDebug(JSON.stringify(dReq, null, 4)); - expect(dReq.data.deletePWProtected).toBeTruthy(); -}); - -test(`Protecteds when the user is not authorized.`, async () => { - const req = await GRAPHQL_CLIENT_1.query(` - mutation { - createPWProtected(input: { content: "Barbie", participants: "${PARTICIPANT_GROUP_NAME}", watchers: "${WATCHER_GROUP_NAME}" }) { - id - content - participants - watchers - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.data.createPWProtected).toBeTruthy(); - - const req2 = await GRAPHQL_CLIENT_2.query(` - query { - listPWProtecteds { - items { - id - content - participants - watchers - } - nextToken - } - } - `); - logDebug(JSON.stringify(req2, null, 4)); - expect(req2.data.listPWProtecteds.items.length).toEqual(0); - expect(req2.data.listPWProtecteds.nextToken).toBeNull(); - - const uReq = await GRAPHQL_CLIENT_2.query(` - mutation { - updatePWProtected(input: { id: "${req.data.createPWProtected.id}", content: "Foobie2" }) { - id - content - participants - watchers - } - } - `); - logDebug(JSON.stringify(uReq, null, 4)); - expect(uReq.data.updatePWProtected).toBeNull(); - - const req3 = await GRAPHQL_CLIENT_2.query(` - query { - getPWProtected(id: "${req.data.createPWProtected.id}") { - id - content - participants - watchers - } - } - `); - logDebug(JSON.stringify(req3, null, 4)); - expect(req3.data.getPWProtected).toBeNull(); - - const dReq = await GRAPHQL_CLIENT_2.query(` - mutation { - deletePWProtected(input: { id: "${req.data.createPWProtected.id}" }) { - id - content - participants - watchers - } - } - `); - logDebug(JSON.stringify(dReq, null, 4)); - expect(dReq.data.deletePWProtected).toBeNull(); - - // The record should still exist after delete. - const getReq = await GRAPHQL_CLIENT_1.query(` - query { - getPWProtected(id: "${req.data.createPWProtected.id}") { - id - content - participants - watchers - } - } - `); - logDebug(JSON.stringify(getReq, null, 4)); - expect(getReq.data.getPWProtected).toBeTruthy(); -}); - -test(`creating, updating, and deleting an admin note as an admin`, async () => { - const req = await GRAPHQL_CLIENT_1.query(` - mutation { - createAdminNote(input: { content: "Hello" }) { - id - content - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.data.createAdminNote.id).toBeDefined(); - expect(req.data.createAdminNote.content).toEqual('Hello'); - const req2 = await GRAPHQL_CLIENT_1.query(` - mutation { - updateAdminNote(input: { id: "${req.data.createAdminNote.id}", content: "Hello 2" }) { - id - content - } - } - `); - logDebug(JSON.stringify(req2, null, 4)); - expect(req2.data.updateAdminNote.id).toEqual(req.data.createAdminNote.id); - expect(req2.data.updateAdminNote.content).toEqual('Hello 2'); - const req3 = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAdminNote(input: { id: "${req.data.createAdminNote.id}" }) { - id - content - } - } - `); - logDebug(JSON.stringify(req3, null, 4)); - expect(req3.data.deleteAdminNote.id).toEqual(req.data.createAdminNote.id); - expect(req3.data.deleteAdminNote.content).toEqual('Hello 2'); -}); - -test(`creating, updating, and deleting an admin note as a non admin`, async () => { - const adminReq = await GRAPHQL_CLIENT_1.query(` - mutation { - createAdminNote(input: { content: "Hello" }) { - id - content - } - } - `); - logDebug(JSON.stringify(adminReq, null, 4)); - expect(adminReq.data.createAdminNote.id).toBeDefined(); - expect(adminReq.data.createAdminNote.content).toEqual('Hello'); - - const req = await GRAPHQL_CLIENT_2.query(` - mutation { - createAdminNote(input: { content: "Hello" }) { - id - content - } - } - `); - logDebug(JSON.stringify(req, null, 4)); - expect(req.errors.length).toEqual(1); - expect((req.errors[0] as any).errorType).toEqual('Unauthorized'); - - const req2 = await GRAPHQL_CLIENT_2.query(` - mutation { - updateAdminNote(input: { id: "${adminReq.data.createAdminNote.id}", content: "Hello 2" }) { - id - content - } - } - `); - logDebug(JSON.stringify(req2, null, 4)); - expect(req2.errors.length).toEqual(1); - expect((req2.errors[0] as any).errorType).toEqual('Unauthorized'); - - const req3 = await GRAPHQL_CLIENT_2.query(` - mutation { - deleteAdminNote(input: { id: "${adminReq.data.createAdminNote.id}" }) { - id - content - } - } - `); - logDebug(JSON.stringify(req3, null, 4)); - expect(req3.errors.length).toEqual(1); - expect((req3.errors[0] as any).errorType).toEqual('Unauthorized'); -}); - -/** - * Get Query Tests - */ - -test(`getAllThree as admin.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query(` - mutation { - createAllThree(input: { - owner: "user2@test.com" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedBy2, null, 4)); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - - const fetchOwnedBy2AsAdmin = await GRAPHQL_CLIENT_1.query(` - query { - getAllThree(id: "${ownedBy2.data.createAllThree.id}") { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(fetchOwnedBy2AsAdmin, null, 4)); - expect(fetchOwnedBy2AsAdmin.data.getAllThree).toBeTruthy(); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); -}); - -test(`getAllThree as owner.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query(` - mutation { - createAllThree(input: { - owner: "user2@test.com" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedBy2, null, 4)); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - - const fetchOwnedBy2AsOwner = await GRAPHQL_CLIENT_2.query(` - query { - getAllThree(id: "${ownedBy2.data.createAllThree.id}") { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(fetchOwnedBy2AsOwner, null, 4)); - expect(fetchOwnedBy2AsOwner.data.getAllThree).toBeTruthy(); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); -}); - -test(`getAllThree as one of a set of editors.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query(` - mutation { - createAllThree(input: { - editors: ["user2@test.com"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedBy2, null, 4)); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - - const fetchOwnedBy2AsEditor = await GRAPHQL_CLIENT_2.query(` - query { - getAllThree(id: "${ownedBy2.data.createAllThree.id}") { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(fetchOwnedBy2AsEditor, null, 4)); - expect(fetchOwnedBy2AsEditor.data.getAllThree).toBeTruthy(); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); -}); - -test(`getAllThree as a member of a dynamic group.`, async () => { - const ownedByAdmins = await GRAPHQL_CLIENT_1.query(` - mutation { - createAllThree(input: { - groups: ["Devs"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByAdmins, null, 4)); - expect(ownedByAdmins.data.createAllThree).toBeTruthy(); - - const fetchOwnedByAdminsAsAdmin = await GRAPHQL_CLIENT_2.query(` - query { - getAllThree(id: "${ownedByAdmins.data.createAllThree.id}") { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(fetchOwnedByAdminsAsAdmin, null, 4)); - expect(fetchOwnedByAdminsAsAdmin.data.getAllThree).toBeTruthy(); - - const fetchOwnedByAdminsAsNonAdmin = await GRAPHQL_CLIENT_3.query(` - query { - getAllThree(id: "${ownedByAdmins.data.createAllThree.id}") { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(fetchOwnedByAdminsAsNonAdmin, null, 4)); - expect(fetchOwnedByAdminsAsNonAdmin.errors.length).toEqual(1); - expect((fetchOwnedByAdminsAsNonAdmin.errors[0] as any).errorType).toEqual('Unauthorized'); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedByAdmins.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByAdmins.data.createAllThree.id); -}); - -test(`getAllThree as a member of the alternative group.`, async () => { - const ownedByAdmins = await GRAPHQL_CLIENT_1.query(` - mutation { - createAllThree(input: { - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByAdmins, null, 4)); - expect(ownedByAdmins.data.createAllThree).toBeTruthy(); - - const fetchOwnedByAdminsAsAdmin = await GRAPHQL_CLIENT_2.query(` - query { - getAllThree(id: "${ownedByAdmins.data.createAllThree.id}") { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(fetchOwnedByAdminsAsAdmin, null, 4)); - expect(fetchOwnedByAdminsAsAdmin.data.getAllThree).toBeTruthy(); - - const fetchOwnedByAdminsAsNonAdmin = await GRAPHQL_CLIENT_3.query(` - query { - getAllThree(id: "${ownedByAdmins.data.createAllThree.id}") { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(fetchOwnedByAdminsAsNonAdmin, null, 4)); - expect(fetchOwnedByAdminsAsNonAdmin.errors.length).toEqual(1); - expect((fetchOwnedByAdminsAsNonAdmin.errors[0] as any).errorType).toEqual('Unauthorized'); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedByAdmins.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByAdmins.data.createAllThree.id); -}); - -/** - * List Query Tests - */ - -test(`listAllThrees as admin.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query(` - mutation { - createAllThree(input: { - owner: "user2@test.com" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedBy2, null, 4)); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - - const fetchOwnedBy2AsAdmin = await GRAPHQL_CLIENT_1.query(` - query { - listAllThrees { - items { - id - owner - editors - groups - alternativeGroup - } - } - } - `); - logDebug(JSON.stringify(fetchOwnedBy2AsAdmin, null, 4)); - expect(fetchOwnedBy2AsAdmin.data.listAllThrees.items).toHaveLength(1); - expect(fetchOwnedBy2AsAdmin.data.listAllThrees.items[0].id).toEqual(ownedBy2.data.createAllThree.id); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); -}); - -test(`listAllThrees as owner.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query(` - mutation { - createAllThree(input: { - owner: "user2@test.com" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedBy2, null, 4)); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - - const fetchOwnedBy2AsOwner = await GRAPHQL_CLIENT_2.query(` - query { - listAllThrees { - items { - id - owner - editors - groups - alternativeGroup - } - } - } - `); - logDebug(JSON.stringify(fetchOwnedBy2AsOwner, null, 4)); - expect(fetchOwnedBy2AsOwner.data.listAllThrees.items).toHaveLength(1); - expect(fetchOwnedBy2AsOwner.data.listAllThrees.items[0].id).toEqual(ownedBy2.data.createAllThree.id); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); -}); - -test(`listAllThrees as one of a set of editors.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query(` - mutation { - createAllThree(input: { - editors: ["user2@test.com"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedBy2, null, 4)); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - - const fetchOwnedBy2AsEditor = await GRAPHQL_CLIENT_2.query(` - query { - listAllThrees { - items { - id - owner - editors - groups - alternativeGroup - } - } - } - `); - logDebug(JSON.stringify(fetchOwnedBy2AsEditor, null, 4)); - expect(fetchOwnedBy2AsEditor.data.listAllThrees.items).toHaveLength(1); - expect(fetchOwnedBy2AsEditor.data.listAllThrees.items[0].id).toEqual(ownedBy2.data.createAllThree.id); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); -}); - -test(`listAllThrees as a member of a dynamic group.`, async () => { - const ownedByAdmins = await GRAPHQL_CLIENT_1.query(` - mutation { - createAllThree(input: { - groups: ["Devs"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByAdmins, null, 4)); - expect(ownedByAdmins.data.createAllThree).toBeTruthy(); - - const fetchOwnedByAdminsAsAdmin = await GRAPHQL_CLIENT_2.query(` - query { - listAllThrees { - items { - id - owner - editors - groups - alternativeGroup - } - } - } - `); - logDebug(JSON.stringify(fetchOwnedByAdminsAsAdmin, null, 4)); - expect(fetchOwnedByAdminsAsAdmin.data.listAllThrees.items).toHaveLength(1); - expect(fetchOwnedByAdminsAsAdmin.data.listAllThrees.items[0].id).toEqual(ownedByAdmins.data.createAllThree.id); - - const fetchOwnedByAdminsAsNonAdmin = await GRAPHQL_CLIENT_3.query(` - query { - listAllThrees { - items { - id - owner - editors - groups - alternativeGroup - } - } - } - `); - logDebug(JSON.stringify(fetchOwnedByAdminsAsNonAdmin, null, 4)); - expect(fetchOwnedByAdminsAsNonAdmin.data.listAllThrees.items).toHaveLength(0); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedByAdmins.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByAdmins.data.createAllThree.id); -}); - -test(`getAllThree as a member of the alternative group.`, async () => { - const ownedByAdmins = await GRAPHQL_CLIENT_1.query(` - mutation { - createAllThree(input: { - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByAdmins, null, 4)); - expect(ownedByAdmins.data.createAllThree).toBeTruthy(); - - const fetchOwnedByAdminsAsAdmin = await GRAPHQL_CLIENT_2.query(` - query { - listAllThrees { - items { - id - owner - editors - groups - alternativeGroup - } - } - } - `); - logDebug(JSON.stringify(fetchOwnedByAdminsAsAdmin, null, 4)); - expect(fetchOwnedByAdminsAsAdmin.data.listAllThrees.items).toHaveLength(1); - expect(fetchOwnedByAdminsAsAdmin.data.listAllThrees.items[0].id).toEqual(ownedByAdmins.data.createAllThree.id); - - const fetchOwnedByAdminsAsNonAdmin = await GRAPHQL_CLIENT_3.query(` - query { - listAllThrees { - items { - id - owner - editors - groups - alternativeGroup - } - } - } - `); - logDebug(JSON.stringify(fetchOwnedByAdminsAsNonAdmin, null, 4)); - expect(fetchOwnedByAdminsAsNonAdmin.data.listAllThrees.items).toHaveLength(0); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedByAdmins.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByAdmins.data.createAllThree.id); -}); - -/** - * Create Mutation Tests - */ - -test(`createAllThree as admin.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query(` - mutation { - createAllThree(input: { - owner: "user2@test.com" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedBy2, null, 4)); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - // set by input - expect(ownedBy2.data.createAllThree.owner).toEqual('user2@test.com'); - // auto filled as logged in user. - expect(ownedBy2.data.createAllThree.editors[0]).toEqual('user1@test.com'); - expect(ownedBy2.data.createAllThree.groups).toBeNull(); - expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedBy2NoEditors = await GRAPHQL_CLIENT_1.query(` - mutation { - createAllThree(input: { - owner: "user2@test.com", - editors: [] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedBy2NoEditors, null, 4)); - expect(ownedBy2NoEditors.data.createAllThree).toBeTruthy(); - // set by input - expect(ownedBy2NoEditors.data.createAllThree.owner).toEqual('user2@test.com'); - // set by input - expect(ownedBy2NoEditors.data.createAllThree.editors).toHaveLength(0); - expect(ownedBy2NoEditors.data.createAllThree.groups).toBeNull(); - expect(ownedBy2NoEditors.data.createAllThree.alternativeGroup).toBeNull(); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); - - const deleteReq2 = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedBy2NoEditors.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq2, null, 4)); - expect(deleteReq2.data.deleteAllThree.id).toEqual(ownedBy2NoEditors.data.createAllThree.id); -}); - -test(`createAllThree as owner.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_2.query(` - mutation { - createAllThree(input: { - owner: "user2@test.com", - editors: [] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedBy2, null, 4)); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - expect(ownedBy2.data.createAllThree.owner).toEqual('user2@test.com'); - expect(ownedBy2.data.createAllThree.editors).toHaveLength(0); - expect(ownedBy2.data.createAllThree.groups).toBeNull(); - expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedBy1 = await GRAPHQL_CLIENT_2.query(` - mutation { - createAllThree(input: { - owner: "user1@test.com", - editors: [] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedBy1, null, 4)); - expect(ownedBy1.errors.length).toEqual(1); - expect((ownedBy1.errors[0] as any).errorType).toEqual('Unauthorized'); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); -}); - -test(`createAllThree as one of a set of editors.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_2.query(` - mutation { - createAllThree(input: { - owner: null, - editors: ["user2@test.com"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedBy2, null, 4)); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - expect(ownedBy2.data.createAllThree.owner).toBeNull(); - expect(ownedBy2.data.createAllThree.editors[0]).toEqual('user2@test.com'); - expect(ownedBy2.data.createAllThree.groups).toBeNull(); - expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedBy2WithDefaultOwner = await GRAPHQL_CLIENT_2.query(` - mutation { - createAllThree(input: { - editors: ["user2@test.com"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedBy2WithDefaultOwner, null, 4)); - expect(ownedBy2WithDefaultOwner.data.createAllThree).toBeTruthy(); - expect(ownedBy2WithDefaultOwner.data.createAllThree.owner).toEqual('user2@test.com'); - expect(ownedBy2WithDefaultOwner.data.createAllThree.editors[0]).toEqual('user2@test.com'); - expect(ownedBy2WithDefaultOwner.data.createAllThree.groups).toBeNull(); - expect(ownedBy2WithDefaultOwner.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedByEditorsUnauthed = await GRAPHQL_CLIENT_2.query(` - mutation { - createAllThree(input: { - owner: null, - editors: ["user1@test.com"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByEditorsUnauthed, null, 4)); - expect(ownedByEditorsUnauthed.errors.length).toEqual(1); - expect((ownedByEditorsUnauthed.errors[0] as any).errorType).toEqual('Unauthorized'); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); - - const deleteReq2 = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedBy2WithDefaultOwner.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq2, null, 4)); - expect(deleteReq2.data.deleteAllThree.id).toEqual(ownedBy2WithDefaultOwner.data.createAllThree.id); -}); - -test(`createAllThree as a member of a dynamic group.`, async () => { - const ownedByDevs = await GRAPHQL_CLIENT_2.query(` - mutation { - createAllThree(input: { - owner: null, - editors: [], - groups: ["Devs"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByDevs, null, 4)); - expect(ownedByDevs.data.createAllThree).toBeTruthy(); - expect(ownedByDevs.data.createAllThree.owner).toBeNull(); - expect(ownedByDevs.data.createAllThree.editors).toHaveLength(0); - expect(ownedByDevs.data.createAllThree.groups[0]).toEqual('Devs'); - expect(ownedByDevs.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedByAdminsUnauthed = await GRAPHQL_CLIENT_3.query(` - mutation { - createAllThree(input: { - owner: null, - editors: [], - groups: ["Devs"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByAdminsUnauthed, null, 4)); - expect(ownedByAdminsUnauthed.errors.length).toEqual(1); - expect((ownedByAdminsUnauthed.errors[0] as any).errorType).toEqual('Unauthorized'); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedByDevs.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByDevs.data.createAllThree.id); -}); - -test(`createAllThree as a member of the alternative group.`, async () => { - const ownedByAdmins = await GRAPHQL_CLIENT_2.query(` - mutation { - createAllThree(input: { - owner: null, - editors: [], - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByAdmins, null, 4)); - expect(ownedByAdmins.data.createAllThree).toBeTruthy(); - expect(ownedByAdmins.data.createAllThree.owner).toBeNull(); - expect(ownedByAdmins.data.createAllThree.editors).toHaveLength(0); - expect(ownedByAdmins.data.createAllThree.alternativeGroup).toEqual('Devs'); - - const ownedByAdminsUnauthed = await GRAPHQL_CLIENT_3.query(` - mutation { - createAllThree(input: { - owner: null, - editors: [], - alternativeGroup: "Admin" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByAdminsUnauthed, null, 4)); - expect(ownedByAdminsUnauthed.errors.length).toEqual(1); - expect((ownedByAdminsUnauthed.errors[0] as any).errorType).toEqual('Unauthorized'); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedByAdmins.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByAdmins.data.createAllThree.id); -}); - -/** - * Update Mutation Tests - */ - -test(`updateAllThree and deleteAllThree as admin.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query(` - mutation { - createAllThree(input: { - editors: [] - owner: "user2@test.com" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedBy2, null, 4)); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - // set by input - expect(ownedBy2.data.createAllThree.owner).toEqual('user2@test.com'); - // auto filled as logged in user. - expect(ownedBy2.data.createAllThree.editors).toHaveLength(0); - expect(ownedBy2.data.createAllThree.groups).toBeNull(); - expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedByTwoUpdate = await GRAPHQL_CLIENT_1.query(` - mutation { - updateAllThree(input: { - id: "${ownedBy2.data.createAllThree.id}", - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByTwoUpdate, null, 4)); - expect(ownedByTwoUpdate.data.updateAllThree).toBeTruthy(); - // set by input - expect(ownedByTwoUpdate.data.updateAllThree.owner).toEqual('user2@test.com'); - // set by input - expect(ownedByTwoUpdate.data.updateAllThree.editors).toHaveLength(0); - expect(ownedByTwoUpdate.data.updateAllThree.groups).toBeNull(); - expect(ownedByTwoUpdate.data.updateAllThree.alternativeGroup).toEqual('Devs'); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); -}); - -test(`updateAllThree and deleteAllThree as owner.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_2.query(` - mutation { - createAllThree(input: { - owner: "user2@test.com", - editors: [] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedBy2, null, 4)); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - expect(ownedBy2.data.createAllThree.owner).toEqual('user2@test.com'); - expect(ownedBy2.data.createAllThree.editors).toHaveLength(0); - expect(ownedBy2.data.createAllThree.groups).toBeNull(); - expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedBy2Update = await GRAPHQL_CLIENT_2.query(` - mutation { - updateAllThree(input: { - id: "${ownedBy2.data.createAllThree.id}", - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedBy2Update, null, 4)); - expect(ownedBy2Update.data.updateAllThree).toBeTruthy(); - // set by input - expect(ownedBy2Update.data.updateAllThree.owner).toEqual('user2@test.com'); - // set by input - expect(ownedBy2Update.data.updateAllThree.editors).toHaveLength(0); - expect(ownedBy2Update.data.updateAllThree.groups).toBeNull(); - expect(ownedBy2Update.data.updateAllThree.alternativeGroup).toEqual('Devs'); - - const deleteReq = await GRAPHQL_CLIENT_2.query(` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); -}); - -test(`updateAllThree and deleteAllThree as one of a set of editors.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_2.query(` - mutation { - createAllThree(input: { - owner: null, - editors: ["user2@test.com"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedBy2, null, 4)); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - expect(ownedBy2.data.createAllThree.owner).toBeNull(); - expect(ownedBy2.data.createAllThree.editors[0]).toEqual('user2@test.com'); - expect(ownedBy2.data.createAllThree.groups).toBeNull(); - expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedByUpdate = await GRAPHQL_CLIENT_2.query(` - mutation { - updateAllThree(input: { - id: "${ownedBy2.data.createAllThree.id}", - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByUpdate, null, 4)); - expect(ownedByUpdate.data.updateAllThree).toBeTruthy(); - // set by input - expect(ownedByUpdate.data.updateAllThree.owner).toBeNull(); - // set by input - expect(ownedByUpdate.data.updateAllThree.editors[0]).toEqual('user2@test.com'); - expect(ownedByUpdate.data.updateAllThree.groups).toBeNull(); - expect(ownedByUpdate.data.updateAllThree.alternativeGroup).toEqual('Devs'); - - const deleteReq = await GRAPHQL_CLIENT_2.query(` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); -}); - -test(`updateAllThree and deleteAllThree as a member of a dynamic group.`, async () => { - const ownedByDevs = await GRAPHQL_CLIENT_1.query(` - mutation { - createAllThree(input: { - owner: null, - editors: [], - groups: ["Devs"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByDevs, null, 4)); - expect(ownedByDevs.data.createAllThree).toBeTruthy(); - expect(ownedByDevs.data.createAllThree.owner).toBeNull(); - expect(ownedByDevs.data.createAllThree.editors).toHaveLength(0); - expect(ownedByDevs.data.createAllThree.groups[0]).toEqual('Devs'); - expect(ownedByDevs.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedByUpdate = await GRAPHQL_CLIENT_2.query(` - mutation { - updateAllThree(input: { - id: "${ownedByDevs.data.createAllThree.id}", - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByUpdate, null, 4)); - expect(ownedByUpdate.data.updateAllThree).toBeTruthy(); - // set by input - expect(ownedByUpdate.data.updateAllThree.owner).toBeNull(); - // set by input - expect(ownedByUpdate.data.updateAllThree.editors).toHaveLength(0); - expect(ownedByUpdate.data.updateAllThree.groups[0]).toEqual('Devs'); - expect(ownedByUpdate.data.updateAllThree.alternativeGroup).toEqual('Devs'); - - const ownedByAdminsUnauthed = await GRAPHQL_CLIENT_3.query(` - mutation { - createAllThree(input: { - owner: null, - editors: [], - groups: ["Devs"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByAdminsUnauthed, null, 4)); - expect(ownedByAdminsUnauthed.errors.length).toEqual(1); - expect((ownedByAdminsUnauthed.errors[0] as any).errorType).toEqual('Unauthorized'); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedByDevs.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByDevs.data.createAllThree.id); -}); - -test(`updateAllThree and deleteAllThree as a member of the alternative group.`, async () => { - const ownedByDevs = await GRAPHQL_CLIENT_1.query(` - mutation { - createAllThree(input: { - owner: null, - editors: [], - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByDevs, null, 4)); - expect(ownedByDevs.data.createAllThree).toBeTruthy(); - expect(ownedByDevs.data.createAllThree.owner).toBeNull(); - expect(ownedByDevs.data.createAllThree.editors).toHaveLength(0); - expect(ownedByDevs.data.createAllThree.alternativeGroup).toEqual('Devs'); - - const ownedByUpdate = await GRAPHQL_CLIENT_2.query(` - mutation { - updateAllThree(input: { - id: "${ownedByDevs.data.createAllThree.id}", - alternativeGroup: "Admin" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByUpdate, null, 4)); - expect(ownedByUpdate.data.updateAllThree).toBeTruthy(); - // set by input - expect(ownedByUpdate.data.updateAllThree.owner).toBeNull(); - // set by input - expect(ownedByUpdate.data.updateAllThree.editors).toHaveLength(0); - expect(ownedByUpdate.data.updateAllThree.groups).toBeNull(); - expect(ownedByUpdate.data.updateAllThree.alternativeGroup).toEqual('Admin'); - - const ownedByAdminsUnauthed = await GRAPHQL_CLIENT_2.query(` - mutation { - updateAllThree(input: { - id: "${ownedByDevs.data.createAllThree.id}", - alternativeGroup: "Dev" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByAdminsUnauthed, null, 4)); - expect(ownedByAdminsUnauthed.errors.length).toEqual(1); - expect((ownedByAdminsUnauthed.errors[0] as any).data).toBeNull(); - expect((ownedByAdminsUnauthed.errors[0] as any).errorType).toEqual('DynamoDB:ConditionalCheckFailedException'); - - const ownedByDevs2 = await GRAPHQL_CLIENT_1.query(` - mutation { - createAllThree(input: { - owner: null, - editors: [], - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `); - logDebug(JSON.stringify(ownedByDevs2, null, 4)); - expect(ownedByDevs2.data.createAllThree).toBeTruthy(); - expect(ownedByDevs2.data.createAllThree.owner).toBeNull(); - expect(ownedByDevs2.data.createAllThree.editors).toHaveLength(0); - expect(ownedByDevs2.data.createAllThree.alternativeGroup).toEqual('Devs'); - - const deleteReq2 = await GRAPHQL_CLIENT_2.query(` - mutation { - deleteAllThree(input: { id: "${ownedByDevs2.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq2, null, 4)); - expect(deleteReq2.data.deleteAllThree.id).toEqual(ownedByDevs2.data.createAllThree.id); - - const deleteReq = await GRAPHQL_CLIENT_1.query(` - mutation { - deleteAllThree(input: { id: "${ownedByDevs.data.createAllThree.id}" }) { - id - } - } - `); - logDebug(JSON.stringify(deleteReq, null, 4)); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByDevs.data.createAllThree.id); -}); - -test(`createTestIdentity as admin.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query(` - mutation { - createTestIdentity(input: { - title: "Test title" - }) { - id - title - owner - } - } - `); - logDebug(JSON.stringify(ownedBy2, null, 4)); - expect(ownedBy2.data.createTestIdentity).toBeTruthy(); - expect(ownedBy2.data.createTestIdentity.title).toEqual('Test title'); - expect(ownedBy2.data.createTestIdentity.owner.slice(0, 19)).toEqual('https://cognito-idp'); - - // user 2 should be able to update because they share the same issuer. - const update = await GRAPHQL_CLIENT_3.query(` - mutation { - updateTestIdentity(input: { - id: "${ownedBy2.data.createTestIdentity.id}", - title: "Test title update" - }) { - id - title - owner - } - } - `); - logDebug(JSON.stringify(update, null, 4)); - expect(update.data.updateTestIdentity).toBeTruthy(); - expect(update.data.updateTestIdentity.title).toEqual('Test title update'); - expect(update.data.updateTestIdentity.owner.slice(0, 19)).toEqual('https://cognito-idp'); - - // user 2 should be able to get because they share the same issuer. - const getReq = await GRAPHQL_CLIENT_3.query(` - query { - getTestIdentity(id: "${ownedBy2.data.createTestIdentity.id}") { - id - title - owner - } - } - `); - logDebug(JSON.stringify(getReq, null, 4)); - expect(getReq.data.getTestIdentity).toBeTruthy(); - expect(getReq.data.getTestIdentity.title).toEqual('Test title update'); - expect(getReq.data.getTestIdentity.owner.slice(0, 19)).toEqual('https://cognito-idp'); - - const listResponse = await GRAPHQL_CLIENT_3.query( - `query { - listTestIdentities(filter: { title: { eq: "Test title update" } }, limit: 100) { - items { - id - title - owner - } - } - }`, - {}, - ); - const relevantPost = listResponse.data.listTestIdentities.items.find((p) => p.id === getReq.data.getTestIdentity.id); - logDebug(JSON.stringify(listResponse, null, 4)); - expect(relevantPost).toBeTruthy(); - expect(relevantPost.title).toEqual('Test title update'); - expect(relevantPost.owner.slice(0, 19)).toEqual('https://cognito-idp'); - - // user 2 should be able to delete because they share the same issuer. - const delReq = await GRAPHQL_CLIENT_3.query(` - mutation { - deleteTestIdentity(input: { - id: "${ownedBy2.data.createTestIdentity.id}" - }) { - id - title - owner - } - } - `); - logDebug(JSON.stringify(delReq, null, 4)); - expect(delReq.data.deleteTestIdentity).toBeTruthy(); - expect(delReq.data.deleteTestIdentity.title).toEqual('Test title update'); - expect(delReq.data.deleteTestIdentity.owner.slice(0, 19)).toEqual('https://cognito-idp'); -}); - -/** - * Test 'operations' argument - */ -test("get and list with 'read' operation set", async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createOwnerReadProtected(input: { content: "Hello, World!", owner: "${USERNAME1}" }) { - id - content - owner - } - }`, - {}, - ); - logDebug(response); - expect(response.data.createOwnerReadProtected.id).toBeDefined(); - expect(response.data.createOwnerReadProtected.content).toEqual('Hello, World!'); - expect(response.data.createOwnerReadProtected.owner).toEqual(USERNAME1); - - const response2 = await GRAPHQL_CLIENT_2.query( - `query { - getOwnerReadProtected(id: "${response.data.createOwnerReadProtected.id}") { - id content owner - } - }`, - {}, - ); - logDebug(response2); - expect(response2.data.getOwnerReadProtected).toBeNull(); - expect(response2.errors).toHaveLength(1); - - const response3 = await GRAPHQL_CLIENT_1.query( - `query { - getOwnerReadProtected(id: "${response.data.createOwnerReadProtected.id}") { - id content owner - } - }`, - {}, - ); - logDebug(response3); - expect(response3.data.getOwnerReadProtected.id).toBeDefined(); - expect(response3.data.getOwnerReadProtected.content).toEqual('Hello, World!'); - expect(response3.data.getOwnerReadProtected.owner).toEqual(USERNAME1); - - const response4 = await GRAPHQL_CLIENT_1.query( - `query { - listOwnerReadProtecteds { - items { - id content owner - } - } - }`, - {}, - ); - logDebug(response4); - expect(response4.data.listOwnerReadProtecteds.items.length).toBeGreaterThanOrEqual(1); - - const response5 = await GRAPHQL_CLIENT_2.query( - `query { - listOwnerReadProtecteds { - items { - id content owner - } - } - }`, - {}, - ); - logDebug(response5); - expect(response5.data.listOwnerReadProtecteds.items).toHaveLength(0); -}); - -test("createOwnerCreateUpdateDeleteProtected with 'create' operation set", async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createOwnerCreateUpdateDeleteProtected(input: { content: "Hello, World!", owner: "${USERNAME1}" }) { - id - content - owner - } - }`, - {}, - ); - logDebug(response); - expect(response.data.createOwnerCreateUpdateDeleteProtected.id).toBeDefined(); - expect(response.data.createOwnerCreateUpdateDeleteProtected.content).toEqual('Hello, World!'); - expect(response.data.createOwnerCreateUpdateDeleteProtected.owner).toEqual(USERNAME1); - - const response2 = await GRAPHQL_CLIENT_1.query( - `mutation { - createOwnerCreateUpdateDeleteProtected(input: { content: "Hello, World!", owner: "${USERNAME2}" }) { - id - content - owner - } - }`, - {}, - ); - logDebug(response2); - expect(response2.data.createOwnerCreateUpdateDeleteProtected).toBeNull(); - expect(response2.errors).toHaveLength(1); -}); - -test("updateOwnerCreateUpdateDeleteProtected with 'update' operation set", async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createOwnerCreateUpdateDeleteProtected(input: { content: "Hello, World!", owner: "${USERNAME1}" }) { - id - content - owner - } - }`, - {}, - ); - logDebug(response); - expect(response.data.createOwnerCreateUpdateDeleteProtected.id).toBeDefined(); - expect(response.data.createOwnerCreateUpdateDeleteProtected.content).toEqual('Hello, World!'); - expect(response.data.createOwnerCreateUpdateDeleteProtected.owner).toEqual(USERNAME1); - - const response2 = await GRAPHQL_CLIENT_2.query( - `mutation { - updateOwnerCreateUpdateDeleteProtected( - input: { - id: "${response.data.createOwnerCreateUpdateDeleteProtected.id}", - content: "Bye, World!" - } - ) { - id - content - owner - } - }`, - {}, - ); - logDebug(response2); - expect(response2.data.updateOwnerCreateUpdateDeleteProtected).toBeNull(); - expect(response2.errors).toHaveLength(1); - - const response3 = await GRAPHQL_CLIENT_1.query( - `mutation { - updateOwnerCreateUpdateDeleteProtected( - input: { - id: "${response.data.createOwnerCreateUpdateDeleteProtected.id}", - content: "Bye, World!" - } - ) { - id - content - owner - } - }`, - {}, - ); - logDebug(response3); - expect(response3.data.updateOwnerCreateUpdateDeleteProtected.id).toBeDefined(); - expect(response3.data.updateOwnerCreateUpdateDeleteProtected.content).toEqual('Bye, World!'); - expect(response3.data.updateOwnerCreateUpdateDeleteProtected.owner).toEqual(USERNAME1); -}); - -test("deleteOwnerCreateUpdateDeleteProtected with 'update' operation set", async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createOwnerCreateUpdateDeleteProtected(input: { content: "Hello, World!", owner: "${USERNAME1}" }) { - id - content - owner - } - }`, - {}, - ); - logDebug(response); - expect(response.data.createOwnerCreateUpdateDeleteProtected.id).toBeDefined(); - expect(response.data.createOwnerCreateUpdateDeleteProtected.content).toEqual('Hello, World!'); - expect(response.data.createOwnerCreateUpdateDeleteProtected.owner).toEqual(USERNAME1); - - const response2 = await GRAPHQL_CLIENT_2.query( - `mutation { - deleteOwnerCreateUpdateDeleteProtected( - input: { - id: "${response.data.createOwnerCreateUpdateDeleteProtected.id}" - } - ) { - id - content - owner - } - }`, - {}, - ); - logDebug(response2); - expect(response2.data.deleteOwnerCreateUpdateDeleteProtected).toBeNull(); - expect(response2.errors).toHaveLength(1); - - const response3 = await GRAPHQL_CLIENT_1.query( - `mutation { - deleteOwnerCreateUpdateDeleteProtected( - input: { - id: "${response.data.createOwnerCreateUpdateDeleteProtected.id}" - } - ) { - id - content - owner - } - }`, - {}, - ); - logDebug(response3); - expect(response3.data.deleteOwnerCreateUpdateDeleteProtected.id).toBeDefined(); - expect(response3.data.deleteOwnerCreateUpdateDeleteProtected.content).toEqual('Hello, World!'); - expect(response3.data.deleteOwnerCreateUpdateDeleteProtected.owner).toEqual(USERNAME1); -}); diff --git a/packages/amplify-util-mock/src/__e2e__/model-connection-transformer.e2e.test.ts b/packages/amplify-util-mock/src/__e2e__/model-connection-transformer.e2e.test.ts deleted file mode 100644 index 3106043111..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/model-connection-transformer.e2e.test.ts +++ /dev/null @@ -1,500 +0,0 @@ -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { FeatureFlagProvider, GraphQLTransform } from 'graphql-transformer-core'; - -import { GraphQLClient } from './utils/graphql-client'; -import { deploy, launchDDBLocal, terminateDDB, logDebug } from './utils/index'; - -let GRAPHQL_CLIENT = undefined; -let GRAPHQL_ENDPOINT = undefined; -let ddbEmulator = null; -let dbPath = null; -let server; -jest.setTimeout(20000); -beforeAll(async () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - createdAt: String - updatedAt: String - comments: [Comment] @connection(name: "PostComments", keyField: "postId", limit: 50) - sortedComments: [SortedComment] @connection(name: "SortedPostComments", keyField: "postId", sortField: "when") - } - type Comment @model { - id: ID! - content: String! - post: Post @connection(name: "PostComments", keyField: "postId") - } - type SortedComment @model{ - id: ID! - content: String! - when: String! - post: Post @connection(name: "SortedPostComments", keyField: "postId", sortField: "when") - } - `; - - try { - const transformer = new GraphQLTransform({ - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }, - }), - new ModelConnectionTransformer(), - ], - featureFlags: { - getBoolean: (name) => name === 'improvePluralization', - } as FeatureFlagProvider, - }); - const out = transformer.transform(validSchema); - - let ddbClient; - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - const result = await deploy(out, ddbClient); - server = result.simulator; - - GRAPHQL_ENDPOINT = server.url + '/graphql'; - logDebug(`Using graphql url: ${GRAPHQL_ENDPOINT}`); - - const apiKey = result.config.appSync.apiKey; - logDebug(apiKey); - GRAPHQL_CLIENT = new GraphQLClient(GRAPHQL_ENDPOINT, { - 'x-api-key': apiKey, - }); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - try { - if (server) { - await server.stop(); - } - await terminateDDB(ddbEmulator, dbPath); - } catch (e) { - logDebug(e); - expect(true).toEqual(false); - } -}); - -/** - * Test queries below - */ - -test('queryPost query', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Query" }) { - id - title - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Query'); - const createCommentResponse = await GRAPHQL_CLIENT.query( - `mutation { - createComment(input: { content: "A comment!", postId: "${createResponse.data.createPost.id}" }) { - id - content - post { - id - title - } - } - }`, - {}, - ); - expect(createCommentResponse.data.createComment.id).toBeDefined(); - expect(createCommentResponse.data.createComment.content).toEqual('A comment!'); - expect(createCommentResponse.data.createComment.post.id).toEqual(createResponse.data.createPost.id); - expect(createCommentResponse.data.createComment.post.title).toEqual(createResponse.data.createPost.title); - const queryResponse = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - comments { - items { - id - content - } - } - } - }`, - {}, - ); - expect(queryResponse.data.getPost).toBeDefined(); - const items = queryResponse.data.getPost.comments.items; - expect(items.length).toEqual(1); - expect(items[0].id).toEqual(createCommentResponse.data.createComment.id); -}); - -const title = 'Test Query with Sort Field'; -const comment1 = 'a comment and a date! - 1'; -const comment2 = 'a comment and a date! - 2'; -const whenpast = '2017-10-01T00:00:00.000Z'; -const when1 = '2018-10-01T00:00:00.000Z'; -const whenmid = '2018-12-01T00:00:00.000Z'; -const when2 = '2019-10-01T00:00:01.000Z'; -const whenfuture = '2020-10-01T00:00:00.000Z'; - -test('queryPost query with sortField', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "${title}" }) { - id - title - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual(title); - const createCommentResponse1 = await GRAPHQL_CLIENT.query( - `mutation { - createSortedComment(input: - { content: "${comment1}", - when: "${when1}" - postId: "${createResponse.data.createPost.id}" - }) { - id - content - post { - id - title - } - } - }`, - {}, - ); - expect(createCommentResponse1.data.createSortedComment.id).toBeDefined(); - expect(createCommentResponse1.data.createSortedComment.content).toEqual(comment1); - expect(createCommentResponse1.data.createSortedComment.post.id).toEqual(createResponse.data.createPost.id); - expect(createCommentResponse1.data.createSortedComment.post.title).toEqual(createResponse.data.createPost.title); - - // create 2nd comment, 1 second later - const createCommentResponse2 = await GRAPHQL_CLIENT.query( - `mutation { - createSortedComment(input: - { content: "${comment2}", - when: "${when2}" - postId: "${createResponse.data.createPost.id}" - }) { - id - content - post { - id - title - } - } - }`, - {}, - ); - expect(createCommentResponse2.data.createSortedComment.id).toBeDefined(); - expect(createCommentResponse2.data.createSortedComment.content).toEqual(comment2); - expect(createCommentResponse2.data.createSortedComment.post.id).toEqual(createResponse.data.createPost.id); - expect(createCommentResponse2.data.createSortedComment.post.title).toEqual(createResponse.data.createPost.title); - - const queryResponse = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponse.data.getPost).toBeDefined(); - const items = queryResponse.data.getPost.sortedComments.items; - expect(items.length).toEqual(2); - expect(items[0].id).toEqual(createCommentResponse1.data.createSortedComment.id); - expect(items[1].id).toEqual(createCommentResponse2.data.createSortedComment.id); - - const queryResponseDesc = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments(sortDirection: DESC) { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponseDesc.data.getPost).toBeDefined(); - const itemsDesc = queryResponseDesc.data.getPost.sortedComments.items; - expect(itemsDesc.length).toEqual(2); - expect(itemsDesc[0].id).toEqual(createCommentResponse2.data.createSortedComment.id); - expect(itemsDesc[1].id).toEqual(createCommentResponse1.data.createSortedComment.id); - - const queryResponseWithKeyCondition = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments(when: { beginsWith: "2018"}) { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponseWithKeyCondition.data.getPost).toBeDefined(); - const itemsDescWithKeyCondition = queryResponseWithKeyCondition.data.getPost.sortedComments.items; - expect(itemsDescWithKeyCondition.length).toEqual(1); - expect(itemsDescWithKeyCondition[0].id).toEqual(createCommentResponse1.data.createSortedComment.id); - - const queryResponseWithKeyConditionEq = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments(when: { eq: "${when1}"}) { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponseWithKeyConditionEq.data.getPost).toBeDefined(); - const itemsDescWithKeyConditionEq = queryResponseWithKeyConditionEq.data.getPost.sortedComments.items; - expect(itemsDescWithKeyConditionEq.length).toEqual(1); - expect(itemsDescWithKeyConditionEq[0].id).toEqual(createCommentResponse1.data.createSortedComment.id); - - const queryResponseWithKeyConditionGt = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments(when: { gt: "${when1}"}) { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponseWithKeyConditionGt.data.getPost).toBeDefined(); - const itemsDescWithKeyConditionGt = queryResponseWithKeyConditionGt.data.getPost.sortedComments.items; - expect(itemsDescWithKeyConditionGt.length).toEqual(1); - expect(itemsDescWithKeyConditionGt[0].id).toEqual(createCommentResponse2.data.createSortedComment.id); - - const queryResponseWithKeyConditionGe = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments(when: { ge: "${when1}"}) { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponseWithKeyConditionGe.data.getPost).toBeDefined(); - const itemsDescWithKeyConditionGe = queryResponseWithKeyConditionGe.data.getPost.sortedComments.items; - expect(itemsDescWithKeyConditionGe.length).toEqual(2); - expect(itemsDescWithKeyConditionGe[0].id).toEqual(createCommentResponse1.data.createSortedComment.id); - expect(itemsDescWithKeyConditionGe[1].id).toEqual(createCommentResponse2.data.createSortedComment.id); - - const queryResponseWithKeyConditionLe = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments(when: { le: "${when2}"}) { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponseWithKeyConditionLe.data.getPost).toBeDefined(); - const itemsDescWithKeyConditionLe = queryResponseWithKeyConditionLe.data.getPost.sortedComments.items; - expect(itemsDescWithKeyConditionLe.length).toEqual(2); - expect(itemsDescWithKeyConditionLe[0].id).toEqual(createCommentResponse1.data.createSortedComment.id); - expect(itemsDescWithKeyConditionLe[1].id).toEqual(createCommentResponse2.data.createSortedComment.id); - - const queryResponseWithKeyConditionLt = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments(when: { lt: "${when2}"}) { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponseWithKeyConditionLt.data.getPost).toBeDefined(); - const itemsDescWithKeyConditionLt = queryResponseWithKeyConditionLt.data.getPost.sortedComments.items; - expect(itemsDescWithKeyConditionLt.length).toEqual(1); - expect(itemsDescWithKeyConditionLt[0].id).toEqual(createCommentResponse1.data.createSortedComment.id); - - const queryResponseWithKeyConditionBetween = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments(when: { between: ["${whenmid}", "${whenfuture}"]}) { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponseWithKeyConditionBetween.data.getPost).toBeDefined(); - const itemsDescWithKeyConditionBetween = queryResponseWithKeyConditionBetween.data.getPost.sortedComments.items; - expect(itemsDescWithKeyConditionBetween.length).toEqual(1); - expect(itemsDescWithKeyConditionBetween[0].id).toEqual(createCommentResponse2.data.createSortedComment.id); -}); - -test('create comment without a post and then querying the comment.', async () => { - try { - const createCommentResponse1 = await GRAPHQL_CLIENT.query( - `mutation { - createComment(input: - { content: "${comment1}" }) { - id - content - post { - id - title - } - } - }`, - {}, - ); - expect(createCommentResponse1.data.createComment.id).toBeDefined(); - expect(createCommentResponse1.data.createComment.content).toEqual(comment1); - expect(createCommentResponse1.data.createComment.post).toBeNull(); - - const queryResponseDesc = await GRAPHQL_CLIENT.query( - `query { - getComment(id: "${createCommentResponse1.data.createComment.id}") { - id - content - post { - id - } - } - }`, - {}, - ); - expect(queryResponseDesc.data.getComment).toBeDefined(); - expect(queryResponseDesc.data.getComment.post).toBeNull(); - } catch (e) { - console.error(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('default limit is 50', async () => { - // create Auth logic around this - const postID = 'e2eConnectionPost'; - const postTitle = 'samplePost'; - const createPost = await GRAPHQL_CLIENT.query( - `mutation CreatePost { - createPost(input: {title: "${postTitle}", id: "${postID}"}) { - id - title - } - } - `, - {}, - ); - expect(createPost.data.createPost).toBeDefined(); - expect(createPost.data.createPost.id).toEqual(postID); - expect(createPost.data.createPost.title).toEqual(postTitle); - - for (let i = 0; i < 51; i++) { - await GRAPHQL_CLIENT.query( - ` - mutation CreateComment { - createComment(input: {postId: "${postID}", content: "content_${i}"}) { - content - id - post { - title - } - } - } - `, - {}, - ); - } - - const getPost = await GRAPHQL_CLIENT.query( - ` - query GetPost($id: ID!) { - getPost(id: $id) { - id - title - createdAt - updatedAt - comments { - items { - id - content - } - nextToken - } - } - }`, - { id: postID }, - ); - - expect(getPost.data.getPost.comments.items.length).toEqual(50); -}); diff --git a/packages/amplify-util-mock/src/__e2e__/model-connection-with-key-transformer.e2e.test.ts b/packages/amplify-util-mock/src/__e2e__/model-connection-with-key-transformer.e2e.test.ts deleted file mode 100644 index ddf8287a36..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/model-connection-with-key-transformer.e2e.test.ts +++ /dev/null @@ -1,465 +0,0 @@ -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { KeyTransformer } from 'graphql-key-transformer'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { FeatureFlagProvider, GraphQLTransform } from 'graphql-transformer-core'; - -import { GraphQLClient } from './utils/graphql-client'; -import { deploy, launchDDBLocal, terminateDDB, logDebug } from './utils/index'; - -let GRAPHQL_CLIENT = undefined; -let GRAPHQL_ENDPOINT = undefined; -let ddbEmulator = null; -let dbPath = null; -let server; -jest.setTimeout(20000); -beforeAll(async () => { - const validSchema = ` - type AProject - @model(subscriptions: null) - @key(fields: ["projectId"]) - { - projectId: String! - name: String - team: ATeam @connection - } - - type ATeam - @model(subscriptions: null) - @key(fields: ["teamId"]) - { - teamId: String! - name: String - } - - type BProject - @model(subscriptions: null) - @key(fields: ["projectId"]) - { - projectId: String! - name: String - teams: [BTeam] @connection - } - - type BTeam - @model(subscriptions: null) - @key(fields: ["teamId"]) - { - teamId: String! - name: String - } - - type CProject - @model(subscriptions: null) - @key(fields: ["projectId"]) - { - projectId: ID! - name: String - team: CTeam @connection(name: "CProjectCTeam") - } - - type CTeam - @model(subscriptions: null) - @key(fields: ["teamId"]) - { - teamId: ID! - name: String - project: CProject @connection(name: "CProjectCTeam") - } - - type DProject - @model(subscriptions: null) - @key(fields: ["projectId"]) - { - projectId: ID! - name: String - teams: [DTeam] @connection(name: "DProjectDTeam") - } - - type DTeam - @model(subscriptions: null) - @key(fields: ["teamId"]) - { - teamId: ID! - name: String - project: DProject @connection(name: "DProjectDTeam") - } - - type Model1 @model(subscriptions: null) @key(fields: ["id", "sort" ]) - { - id: ID! - sort: Int! - name: String! - } - type Model2 @model(subscriptions: null) - { - id: ID! - connection: Model1 @connection(sortField: "modelOneSort") - modelOneSort: Int! - } - `; - try { - const transformer = new GraphQLTransform({ - transformers: [ - new DynamoDBModelTransformer(), - new ModelConnectionTransformer(), - new KeyTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - featureFlags: { - getBoolean: (name) => name === 'improvePluralization', - } as FeatureFlagProvider, - }); - const out = transformer.transform(validSchema); - - let ddbClient; - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - const result = await deploy(out, ddbClient); - server = result.simulator; - - GRAPHQL_ENDPOINT = server.url + '/graphql'; - logDebug(`Using graphql url: ${GRAPHQL_ENDPOINT}`); - - const apiKey = result.config.appSync.apiKey; - logDebug(apiKey); - GRAPHQL_CLIENT = new GraphQLClient(GRAPHQL_ENDPOINT, { - 'x-api-key': apiKey, - }); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - try { - if (server) { - await server.stop(); - } - await terminateDDB(ddbEmulator, dbPath); - } catch (e) { - logDebug(e); - expect(true).toEqual(false); - } -}); - -/** - * Test queries below - */ - -test('Unnamed connection 1 way navigation, with primary @key directive 1:1', async () => { - await GRAPHQL_CLIENT.query( - ` - mutation CreateATeam { - createATeam(input: {teamId: "T1", name: "Team 1"}) { - teamId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateAProject { - createAProject(input: {projectId: "P1", name: "P1", aProjectTeamId: "T1"}) { - projectId - name - } - } - `, - {}, - ); - - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query ListAProjects { - listAProjects { - items { - projectId - name - team { - teamId - name - } - } - } - } - `, - {}, - ); - expect(queryResponse.data.listAProjects).toBeDefined(); - const items = queryResponse.data.listAProjects.items; - expect(items.length).toEqual(1); - expect(items[0].projectId).toEqual('P1'); - expect(items[0].team).toBeDefined(); - expect(items[0].team.teamId).toEqual('T1'); -}); - -test('Unnamed connection 1 way navigation, with primary @key directive 1:M', async () => { - await GRAPHQL_CLIENT.query( - ` - mutation CreateBProject { - createBProject(input: {projectId: "P1", name: "P1"}) { - projectId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateBTeam { - createBTeam(input: {teamId: "T1", name: "Team 1", bProjectTeamsId: "P1"}) { - teamId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateBTeam { - createBTeam(input: {teamId: "T2", name: "Team 2", bProjectTeamsId: "P1"}) { - teamId - name - } - } - `, - {}, - ); - - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query ListBProjects { - listBProjects { - items { - projectId - name - teams { - items { - teamId - name - } - } - } - } - } - `, - {}, - ); - expect(queryResponse.data.listBProjects).toBeDefined(); - const items = queryResponse.data.listBProjects.items; - expect(items.length).toEqual(1); - expect(items[0].projectId).toEqual('P1'); - expect(items[0].teams).toBeDefined(); - expect(items[0].teams.items).toBeDefined(); - expect(items[0].teams.items.length).toEqual(2); - expect(items[0].teams.items[0].teamId).toEqual('T1'); - expect(items[0].teams.items[1].teamId).toEqual('T2'); -}); - -test('Named connection 2 way navigation, with with custom @key fields 1:1', async () => { - await GRAPHQL_CLIENT.query( - ` - mutation CreateCTeam { - createCTeam(input: {teamId: "T1", name: "Team 1", cTeamProjectId: "P1"}) { - teamId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateCProject { - createCProject(input: {projectId: "P1", name: "P1", cProjectTeamId: "T1"}) { - projectId - name - } - } - `, - {}, - ); - - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query ListCProjects { - listCProjects { - items { - projectId - name - team { - teamId - name - project { - projectId - name - } - } - } - } - } - `, - {}, - ); - expect(queryResponse.data.listCProjects).toBeDefined(); - const items = queryResponse.data.listCProjects.items; - expect(items.length).toEqual(1); - expect(items[0].projectId).toEqual('P1'); - expect(items[0].team).toBeDefined(); - expect(items[0].team.teamId).toEqual('T1'); - expect(items[0].team.project).toBeDefined(); - expect(items[0].team.project.projectId).toEqual('P1'); -}); - -test('Named connection 2 way navigation, with with custom @key fields 1:M', async () => { - await GRAPHQL_CLIENT.query( - ` - mutation CreateDProject { - createDProject(input: {projectId: "P1", name: "P1"}) { - projectId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateDTeam { - createDTeam(input: {teamId: "T1", name: "Team 1", dTeamProjectId: "P1"}) { - teamId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateDTeam { - createDTeam(input: {teamId: "T2", name: "Team 2", dTeamProjectId: "P1"}) { - teamId - name - } - } - `, - {}, - ); - - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query ListDProjects { - listDProjects { - items { - projectId - name - teams { - items { - teamId - name - project { - projectId - name - } - } - } - } - } - } - `, - {}, - ); - expect(queryResponse.data.listDProjects).toBeDefined(); - const items = queryResponse.data.listDProjects.items; - expect(items.length).toEqual(1); - expect(items[0].projectId).toEqual('P1'); - expect(items[0].teams).toBeDefined(); - expect(items[0].teams.items).toBeDefined(); - expect(items[0].teams.items.length).toEqual(2); - expect(items[0].teams.items[0].teamId).toEqual('T1'); - expect(items[0].teams.items[0].project).toBeDefined(); - expect(items[0].teams.items[0].project.projectId).toEqual('P1'); - expect(items[0].teams.items[1].teamId).toEqual('T2'); - expect(items[0].teams.items[1].project).toBeDefined(); - expect(items[0].teams.items[1].project.projectId).toEqual('P1'); -}); - -test('Unnamed connection with sortField parameter only #2100', async () => { - await GRAPHQL_CLIENT.query( - ` - mutation M11 { - createModel1(input: {id: "M11", sort: 10, name: "M1-1"}) { - id - name - sort - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation M12 { - createModel1(input: {id: "M12", sort: 10, name: "M1-2"}) { - id - name - sort - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation M21 { - createModel2(input: {id: "M21", modelOneSort: 10, model2ConnectionId: "M11"}) { - id - modelOneSort - } - } - `, - {}, - ); - - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query Query { - getModel2(id: "M21") { - id - connection { - id - sort - name - } - } - } - `, - {}, - ); - expect(queryResponse.data.getModel2).toBeDefined(); - const item = queryResponse.data.getModel2; - expect(item.id).toEqual('M21'); - expect(item.connection).toBeDefined(); - expect(item.connection.id).toEqual('M11'); - expect(item.connection.sort).toEqual(10); -}); diff --git a/packages/amplify-util-mock/src/__e2e__/model-with-maps-to.e2e.test.ts b/packages/amplify-util-mock/src/__e2e__/model-with-maps-to.e2e.test.ts deleted file mode 100644 index 51d8280bbd..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/model-with-maps-to.e2e.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { GraphQLClient } from './utils/graphql-client'; -import { defaultTransformParams, deploy, launchDDBLocal, logDebug, terminateDDB, transformAndSynth } from './utils/index'; - -jest.setTimeout(1000 * 30); - -let graphqlClient; -let server; - -let dbPath; -let ddbEmulator; - -beforeAll(async () => { - const validSchema = ` - type Todo @model @mapsTo(name: "Task") @auth(rules: [{allow: public}]) { - id: ID! - title: String! - description: String - } - `; - try { - const out = transformAndSynth({ - ...defaultTransformParams, - schema: validSchema, - transformParameters: { - ...defaultTransformParams.transformParameters, - useSubUsernameForDefaultIdentityClaim: false, - }, - }); - - let ddbClient; - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - const result = await deploy(out, ddbClient); - server = result.simulator; - - const endpoint = server.url + '/graphql'; - logDebug(`Using graphql url: ${endpoint}`); - - const apiKey = result.config.appSync.apiKey; - graphqlClient = new GraphQLClient(endpoint, { 'x-api-key': apiKey }); - } catch (e) { - logDebug(e); - console.warn(`Could not setup mock server: ${e}`); - } -}); - -afterAll(async () => { - try { - if (server) { - await server.stop(); - } - await terminateDDB(ddbEmulator, dbPath); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -/** - * Test queries below - */ -test('Model with original name specified points to original table', async () => { - const response = await graphqlClient.query( - `mutation { - createTodo(input: {title: "Test Todo"}) { - id - title - } - }`, - {}, - ); - logDebug(JSON.stringify(response, null, 2)); - expect(response?.data?.createTodo?.id).toBeDefined(); - expect(response?.data?.createTodo?.title).toEqual('Test Todo'); - // successful response means that it was able to write to the original table correctly -}); diff --git a/packages/amplify-util-mock/src/__e2e__/multi-auth-model-auth-transformer.e2e.test.ts b/packages/amplify-util-mock/src/__e2e__/multi-auth-model-auth-transformer.e2e.test.ts deleted file mode 100644 index 3f2ddbd9c7..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/multi-auth-model-auth-transformer.e2e.test.ts +++ /dev/null @@ -1,497 +0,0 @@ -import AWSAppSyncClient, { AUTH_TYPE } from 'aws-appsync'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import gql from 'graphql-tag'; -import { FeatureFlagProvider, GraphQLTransform } from 'graphql-transformer-core'; -import { signUpAddToGroupAndGetJwtToken } from './utils/cognito-utils'; -import { deploy, launchDDBLocal, logDebug, terminateDDB } from './utils/index'; -import 'isomorphic-fetch'; - -jest.setTimeout(2000000); - -const REGION = 'us-west-2'; - -let ddbEmulator = null; -let dbPath = null; -let server; - -let GRAPHQL_ENDPOINT = undefined; - -let APIKEY_GRAPHQL_CLIENT: AWSAppSyncClient = undefined; -let USER_POOL_AUTH_CLIENT: AWSAppSyncClient = undefined; - -let USER_POOL_ID = 'fake_user_pool'; - -const USERNAME1 = 'user1@test.com'; - -beforeAll(async () => { - // Create a stack for the post model with auth enabled. - const validSchema = ` - # Allow anyone to access. This is translated into API_KEY. - type PostPublic @model @auth(rules: [{ allow: public }]) { - id: ID! - title: String - } - - # Allow anyone to access. This is translated to IAM with unauth role. - type PostPublicIAM @model @auth(rules: [{ allow: public, provider: iam }]) { - id: ID! - title: String - } - - # Allow anyone with a valid Amazon Cognito UserPools JWT to access. - type PostPrivate @model @auth(rules: [{ allow: private }]) { - id: ID! - title: String - } - - # Allow anyone with a sigv4 signed request with relevant policy to access. - type PostPrivateIAM @model @auth(rules: [{ allow: private, provider: iam }]) { - id: ID! - title: String - } - - # I have a model that is protected by userPools by default. - # I want to call createPost from my lambda. - type PostOwnerIAM @model - @auth ( - rules: [ - # The cognito user pool owner can CRUD. - { allow: owner }, - # A lambda function using IAM can call Mutation.createPost. - { allow: private, provider: iam, operations: [create] } - ] - ) - { - id: ID! - title: String - owner: String - } - - type PostSecretFieldIAM @model - @auth ( - rules: [ - # The cognito user pool and can CRUD. - { allow: private } - ] - ) - { - id: ID! - title: String - owner: String - secret: String - @auth ( - rules: [ - # Only a lambda function using IAM can create/update this field - { allow: private, provider: iam, operations: [create, update] } - ] - ) - } - - type PostConnection @model @auth(rules:[{allow: public}]){ - id: ID! - title: String! - comments: [CommentConnection] @connection(name: "PostComments") - } - - type CommentConnection @model { - id: ID! - content: String! - post: PostConnection @connection(name: "PostComments") - } - `; - - const transformer = new GraphQLTransform({ - transformers: [ - new DynamoDBModelTransformer(), - new ModelConnectionTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'API_KEY', - apiKeyConfig: { - description: 'E2E Test API Key', - apiKeyExpirationDays: 300, - }, - }, - { - authenticationType: 'AWS_IAM', - }, - ], - }, - }), - ], - featureFlags: { - getBoolean: (name) => name === 'improvePluralization', - } as FeatureFlagProvider, - }); - - try { - // Clean the bucket - const out = transformer.transform(validSchema); - - let ddbClient; - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - - const result = await deploy(out, ddbClient); - server = result.simulator; - - GRAPHQL_ENDPOINT = server.url + '/graphql'; - logDebug(`Using graphql url: ${GRAPHQL_ENDPOINT}`); - - const apiKey = result.config.appSync.apiKey; - logDebug(`API KEY: ${apiKey}`); - expect(apiKey).toBeTruthy(); - - // Verify we have all the details - expect(GRAPHQL_ENDPOINT).toBeTruthy(); - expect(USER_POOL_ID).toBeTruthy(); - - const idToken = signUpAddToGroupAndGetJwtToken(USER_POOL_ID, USERNAME1, USERNAME1, []); - - USER_POOL_AUTH_CLIENT = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: REGION, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: () => idToken, - }, - offlineConfig: { - keyPrefix: 'userPools', - }, - disableOffline: true, - }); - - APIKEY_GRAPHQL_CLIENT = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: REGION, - auth: { - type: AUTH_TYPE.API_KEY, - apiKey: apiKey, - }, - offlineConfig: { - keyPrefix: 'apikey', - }, - disableOffline: true, - }); - - // Wait for any propagation to avoid random - // "The security token included in the request is invalid" errors - await new Promise((res) => setTimeout(() => res(), 5000)); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - try { - if (server) { - await server.stop(); - } - await terminateDDB(ddbEmulator, dbPath); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -/** - * Test queries below - */ -test(`'public' authStrategy`, async () => { - try { - const createMutation = gql` - mutation { - createPostPublic(input: { title: "Hello, World!" }) { - id - title - } - } - `; - - const getQuery = gql` - query ($id: ID!) { - getPostPublic(id: $id) { - id - title - } - } - `; - - const response: any = await APIKEY_GRAPHQL_CLIENT.mutate({ - mutation: createMutation, - fetchPolicy: 'no-cache', - }); - expect(response.data.createPostPublic.id).toBeDefined(); - expect(response.data.createPostPublic.title).toEqual('Hello, World!'); - - const postId = response.data.createPostPublic.id; - - // Authenticate User Pools user must fail - try { - await USER_POOL_AUTH_CLIENT.query({ - query: getQuery, - fetchPolicy: 'no-cache', - variables: { - id: postId, - }, - }); - - expect(true).toBe(false); - } catch (e) { - expect(e.message).toMatch('GraphQL error: Not Authorized to access getPostPublic on type Query'); - } - } catch (e) { - expect(true).toBe(false); - } -}); - -test(`'private' authStrategy`, async () => { - try { - const createMutation = gql` - mutation { - createPostPrivate(input: { title: "Hello, World!" }) { - id - title - } - } - `; - - const getQuery = gql` - query ($id: ID!) { - getPostPrivate(id: $id) { - id - title - } - } - `; - - const response: any = await USER_POOL_AUTH_CLIENT.mutate({ - mutation: createMutation, - fetchPolicy: 'no-cache', - }); - expect(response.data.createPostPrivate.id).toBeDefined(); - expect(response.data.createPostPrivate.title).toEqual('Hello, World!'); - - const postId = response.data.createPostPrivate.id; - - // Authenticate API Key fail - try { - await APIKEY_GRAPHQL_CLIENT.query({ - query: getQuery, - fetchPolicy: 'no-cache', - variables: { - id: postId, - }, - }); - - expect(true).toBe(false); - } catch (e) { - expect(e.message).toMatch('GraphQL error: Not Authorized to access getPostPrivate on type Query'); - } - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -describe(`Connection tests with @auth on type`, () => { - const createPostMutation = gql` - mutation { - createPostConnection(input: { title: "Hello, World!" }) { - id - title - } - } - `; - - const createCommentMutation = gql` - mutation ($postId: ID!) { - createCommentConnection(input: { content: "Comment", commentConnectionPostId: $postId }) { - id - content - } - } - `; - - const getPostQuery = gql` - query ($postId: ID!) { - getPostConnection(id: $postId) { - id - title - } - } - `; - - const getPostQueryWithComments = gql` - query ($postId: ID!) { - getPostConnection(id: $postId) { - id - title - comments { - items { - id - content - } - } - } - } - `; - - const getCommentQuery = gql` - query ($commentId: ID!) { - getCommentConnection(id: $commentId) { - id - content - } - } - `; - - const getCommentWithPostQuery = gql` - query ($commentId: ID!) { - getCommentConnection(id: $commentId) { - id - content - post { - id - title - } - } - } - `; - - let postId = ''; - let commentId = ''; - - beforeAll(async () => { - try { - // Add a comment with ApiKey - Succeed - const response: any = await APIKEY_GRAPHQL_CLIENT.mutate({ - mutation: createPostMutation, - fetchPolicy: 'no-cache', - }); - - postId = response.data.createPostConnection.id; - - // Add a comment with UserPool - Succeed - const commentResponse: any = await USER_POOL_AUTH_CLIENT.mutate({ - mutation: createCommentMutation, - fetchPolicy: 'no-cache', - variables: { - postId, - }, - }); - - commentId = commentResponse.data.createCommentConnection.id; - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } - }); - - it('Create a Post with UserPool - Fail', async () => { - expect.assertions(1); - await expect( - USER_POOL_AUTH_CLIENT.mutate({ - mutation: createPostMutation, - fetchPolicy: 'no-cache', - }), - ).rejects.toThrow('GraphQL error: Not Authorized to access createPostConnection on type Mutation'); - }); - - it('Add a comment with ApiKey - Fail', async () => { - expect.assertions(1); - await expect( - APIKEY_GRAPHQL_CLIENT.mutate({ - mutation: createCommentMutation, - fetchPolicy: 'no-cache', - variables: { - postId, - }, - }), - ).rejects.toThrow('Not Authorized to access createCommentConnection on type Mutation'); - }); - - it('Get Post with ApiKey - Succeed', async () => { - const responseGetPost = await APIKEY_GRAPHQL_CLIENT.query({ - query: getPostQuery, - fetchPolicy: 'no-cache', - variables: { - postId, - }, - }); - expect(responseGetPost.data.getPostConnection.id).toEqual(postId); - expect(responseGetPost.data.getPostConnection.title).toEqual('Hello, World!'); - }); - - it('Get Post+Comments with ApiKey - Fail', async () => { - expect.assertions(1); - await expect( - APIKEY_GRAPHQL_CLIENT.query({ - query: getPostQueryWithComments, - fetchPolicy: 'no-cache', - variables: { - postId, - }, - }), - ).rejects.toThrow('Not Authorized to access items on type ModelCommentConnectionConnection'); - }); - - it('Get Post with UserPool - Fail', async () => { - expect.assertions(1); - await expect( - USER_POOL_AUTH_CLIENT.query({ - query: getPostQuery, - fetchPolicy: 'no-cache', - variables: { - postId, - }, - }), - ).rejects.toThrow('Not Authorized to access getPostConnection on type Query'); - }); - - it('Get Comment with UserPool - Succeed', async () => { - const responseGetComment = await USER_POOL_AUTH_CLIENT.query({ - query: getCommentQuery, - fetchPolicy: 'no-cache', - variables: { - commentId, - }, - }); - expect(responseGetComment.data.getCommentConnection.id).toEqual(commentId); - expect(responseGetComment.data.getCommentConnection.content).toEqual('Comment'); - }); - - it('Get Comment with ApiKey - Fail', async () => { - expect.assertions(1); - await expect( - APIKEY_GRAPHQL_CLIENT.query({ - query: getCommentQuery, - fetchPolicy: 'no-cache', - variables: { - commentId, - }, - }), - ).rejects.toThrow('Not Authorized to access getCommentConnection on type Query'); - }); - - it('Get Comment with Post with UserPool - Succeed, but null for Post field', async () => { - const responseGetComment = await USER_POOL_AUTH_CLIENT.query({ - query: getCommentWithPostQuery, - errorPolicy: 'all', - fetchPolicy: 'no-cache', - variables: { - commentId, - }, - }); - expect(responseGetComment.data.getCommentConnection.id).toEqual(commentId); - expect(responseGetComment.data.getCommentConnection.content).toEqual('Comment'); - expect(responseGetComment.data.getCommentConnection.post).toBeNull(); - }); -}); diff --git a/packages/amplify-util-mock/src/__e2e__/per-field-auth-tests.e2e.test.ts b/packages/amplify-util-mock/src/__e2e__/per-field-auth-tests.e2e.test.ts deleted file mode 100644 index cfce4254c3..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/per-field-auth-tests.e2e.test.ts +++ /dev/null @@ -1,592 +0,0 @@ -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { FeatureFlagProvider, GraphQLTransform } from 'graphql-transformer-core'; -import { GraphQLClient } from './utils/graphql-client'; -import { deploy, launchDDBLocal, logDebug, terminateDDB } from './utils/index'; -import { signUpAddToGroupAndGetJwtToken } from './utils/cognito-utils'; -import 'isomorphic-fetch'; - -jest.setTimeout(2000000); - -let GRAPHQL_ENDPOINT = undefined; -let ddbEmulator = null; -let dbPath = null; -let server; - -/** - * Client 1 is logged in and is a member of the Admin group. - */ -let GRAPHQL_CLIENT_1 = undefined; - -/** - * Client 2 is logged in and is a member of the Devs group. - */ -let GRAPHQL_CLIENT_2 = undefined; - -/** - * Client 3 is logged in and has no group memberships. - */ -let GRAPHQL_CLIENT_3 = undefined; - -const USER_POOL_ID = 'fake_user_pool'; - -const USERNAME1 = 'user1@test.com'; -const USERNAME2 = 'user2@test.com'; -const USERNAME3 = 'user3@test.com'; - -const ADMIN_GROUP_NAME = 'Admin'; -const DEVS_GROUP_NAME = 'Devs'; -const PARTICIPANT_GROUP_NAME = 'Participant'; -const WATCHER_GROUP_NAME = 'Watcher'; -const INSTRUCTOR_GROUP_NAME = 'Instructor'; - -beforeAll(async () => { - const validSchema = `# Owners may update their owned records. - # Admins may create Employee records. - # Any authenticated user may view Employee ids & emails. - # Owners and members of "Admin" group may see employee salaries. - # Owners of "Admin" group may create and update employee salaries. - type Employee @model ( - subscriptions: { - level: public - } - ) @auth(rules: [ - { allow: owner, ownerField: "email", operations: [update] }, - { allow: groups, groups: ["Admin"], operations: [create,update,delete]} - ]) { - id: ID! - - # The only field that can be updated by the owner. - bio: String - - # Fields with ownership conditions take precendence to the Object @auth. - # That means that both the @auth on Object AND the @auth on the field must - # be satisfied. - - # Owners & "Admin"s may view employee email addresses. Only "Admin"s may create/update. - # TODO: { allow: authenticated } would be useful here so that any employee could view. - email: String @auth(rules: [ - { allow: groups, groups: ["Admin"], operations: [create, update, read]} - { allow: owner, ownerField: "email", operations: [read]} - ]) - - # The owner & "Admin"s may view the salary. Only "Admins" may create/update. - salary: Int @auth(rules: [ - { allow: groups, groups: ["Admin"], operations: [create, update, read]} - { allow: owner, ownerField: "email", operations: [read]} - ]) - - # The delete operation means you cannot update the value to "null" or "undefined". - # Since delete operations are at the object level, this actually adds auth rules to the update mutation. - notes: String @auth(rules: [{ allow: owner, ownerField: "email", operations: [delete] }]) - } - - type Student @model - @auth(rules: [ - {allow: owner} - {allow: groups, groups: ["Instructor"]} - ]) { - id: String, - name: String, - bio: String, - notes: String @auth(rules: [{allow: owner}]) - } - - type Post @model - @auth(rules: [{ allow: groups, groups: ["Admin"] }, - { allow: owner, ownerField: "owner1", operations: [read, create] }]) - { - id: ID! - owner1: String! @auth(rules: [{allow: owner, ownerField: "notAllowed", operations: [update]}]) - text: String @auth(rules: [{ allow: owner, ownerField: "owner1", operations : [update]}]) - } - # add auth on a field - type Query { - someFunction: String @auth(rules: [{ allow: groups, groups: ["Admin"] }]) - } - `; - const transformer = new GraphQLTransform({ - transformers: [ - new DynamoDBModelTransformer(), - new ModelConnectionTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - featureFlags: { - getBoolean: (name) => name === 'improvePluralization', - } as FeatureFlagProvider, - }); - - try { - const out = transformer.transform(validSchema); - - let ddbClient; - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - - const result = await deploy(out, ddbClient); - server = result.simulator; - - GRAPHQL_ENDPOINT = server.url + '/graphql'; - // Verify we have all the details - expect(GRAPHQL_ENDPOINT).toBeTruthy(); - // Configure Amplify, create users, and sign in. - - const idToken = signUpAddToGroupAndGetJwtToken(USER_POOL_ID, USERNAME1, USERNAME1, [ - ADMIN_GROUP_NAME, - PARTICIPANT_GROUP_NAME, - WATCHER_GROUP_NAME, - INSTRUCTOR_GROUP_NAME, - ]); - GRAPHQL_CLIENT_1 = new GraphQLClient(GRAPHQL_ENDPOINT, { - Authorization: idToken, - }); - - const idToken2 = signUpAddToGroupAndGetJwtToken(USER_POOL_ID, USERNAME2, USERNAME2, [DEVS_GROUP_NAME, INSTRUCTOR_GROUP_NAME]); - GRAPHQL_CLIENT_2 = new GraphQLClient(GRAPHQL_ENDPOINT, { - Authorization: idToken2, - }); - - const idToken3 = signUpAddToGroupAndGetJwtToken(USER_POOL_ID, USERNAME3, USERNAME3, []); - GRAPHQL_CLIENT_3 = new GraphQLClient(GRAPHQL_ENDPOINT, { - Authorization: idToken3, - }); - - // Wait for any propagation to avoid random - // "The security token included in the request is invalid" errors - await new Promise((res) => setTimeout(() => res(), 5000)); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - try { - if (server) { - await server.stop(); - } - await terminateDDB(ddbEmulator, dbPath); - } catch (e) { - console.error(e); - throw e; - } -}); - -/** - * Tests - */ -test('that only Admins can create Employee records.', async () => { - const createUser1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createEmployee(input: { email: "user2@test.com", salary: 100 }) { - id - email - salary - } - }`, - {}, - ); - logDebug(createUser1); - expect(createUser1.data.createEmployee.email).toEqual('user2@test.com'); - expect(createUser1.data.createEmployee.salary).toEqual(100); - - const tryToCreateAsNonAdmin = await GRAPHQL_CLIENT_2.query( - `mutation { - createEmployee(input: { email: "user2@test.com", salary: 101 }) { - id - email - salary - } - }`, - {}, - ); - logDebug(tryToCreateAsNonAdmin); - expect(tryToCreateAsNonAdmin.data.createEmployee).toBeNull(); - expect(tryToCreateAsNonAdmin.errors).toHaveLength(1); - - const tryToCreateAsNonAdmin2 = await GRAPHQL_CLIENT_3.query( - `mutation { - createEmployee(input: { email: "user2@test.com", salary: 101 }) { - id - email - salary - } - }`, - {}, - ); - logDebug(tryToCreateAsNonAdmin2); - expect(tryToCreateAsNonAdmin2.data.createEmployee).toBeNull(); - expect(tryToCreateAsNonAdmin2.errors).toHaveLength(1); -}); - -test('that only Admins may update salary & email.', async () => { - const createUser1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createEmployee(input: { email: "user2@test.com", salary: 100 }) { - id - email - salary - } - }`, - {}, - ); - logDebug(createUser1); - const employeeId = createUser1.data.createEmployee.id; - expect(employeeId).not.toBeNull(); - expect(createUser1.data.createEmployee.email).toEqual('user2@test.com'); - expect(createUser1.data.createEmployee.salary).toEqual(100); - - const tryToUpdateAsNonAdmin = await GRAPHQL_CLIENT_2.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", salary: 101 }) { - id - email - salary - } - }`, - {}, - ); - logDebug(tryToUpdateAsNonAdmin); - expect(tryToUpdateAsNonAdmin.data.updateEmployee).toBeNull(); - expect(tryToUpdateAsNonAdmin.errors).toHaveLength(1); - - const tryToUpdateAsNonAdmin2 = await GRAPHQL_CLIENT_2.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", email: "someonelese@gmail.com" }) { - id - email - salary - } - }`, - {}, - ); - logDebug(tryToUpdateAsNonAdmin2); - expect(tryToUpdateAsNonAdmin2.data.updateEmployee).toBeNull(); - expect(tryToUpdateAsNonAdmin2.errors).toHaveLength(1); - - const tryToUpdateAsNonAdmin3 = await GRAPHQL_CLIENT_3.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", email: "someonelese@gmail.com" }) { - id - email - salary - } - }`, - {}, - ); - logDebug(tryToUpdateAsNonAdmin3); - expect(tryToUpdateAsNonAdmin3.data.updateEmployee).toBeNull(); - expect(tryToUpdateAsNonAdmin3.errors).toHaveLength(1); - - const updateAsAdmin = await GRAPHQL_CLIENT_1.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", email: "someonelese@gmail.com" }) { - id - email - salary - } - }`, - {}, - ); - logDebug(updateAsAdmin); - expect(updateAsAdmin.data.updateEmployee.email).toEqual('someonelese@gmail.com'); - expect(updateAsAdmin.data.updateEmployee.salary).toEqual(100); - - const updateAsAdmin2 = await GRAPHQL_CLIENT_1.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", salary: 99 }) { - id - email - salary - } - }`, - {}, - ); - logDebug(updateAsAdmin2); - expect(updateAsAdmin2.data.updateEmployee.email).toEqual('someonelese@gmail.com'); - expect(updateAsAdmin2.data.updateEmployee.salary).toEqual(99); -}); - -test('that owners may update their bio.', async () => { - const createUser1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createEmployee(input: { email: "user2@test.com", salary: 100 }) { - id - email - salary - } - }`, - {}, - ); - logDebug(createUser1); - const employeeId = createUser1.data.createEmployee.id; - expect(employeeId).not.toBeNull(); - expect(createUser1.data.createEmployee.email).toEqual('user2@test.com'); - expect(createUser1.data.createEmployee.salary).toEqual(100); - - const tryToUpdateAsNonAdmin = await GRAPHQL_CLIENT_2.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", bio: "Does cool stuff." }) { - id - email - salary - bio - } - }`, - {}, - ); - logDebug(tryToUpdateAsNonAdmin); - expect(tryToUpdateAsNonAdmin.data.updateEmployee.bio).toEqual('Does cool stuff.'); - expect(tryToUpdateAsNonAdmin.data.updateEmployee.email).toEqual('user2@test.com'); - expect(tryToUpdateAsNonAdmin.data.updateEmployee.salary).toEqual(100); -}); - -test('that everyone may view employee bios.', async () => { - const createUser1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createEmployee(input: { email: "user3@test.com", salary: 100, bio: "Likes long walks on the beach" }) { - id - email - salary - bio - } - }`, - {}, - ); - logDebug(createUser1); - const employeeId = createUser1.data.createEmployee.id; - expect(employeeId).not.toBeNull(); - expect(createUser1.data.createEmployee.email).toEqual('user3@test.com'); - expect(createUser1.data.createEmployee.salary).toEqual(100); - expect(createUser1.data.createEmployee.bio).toEqual('Likes long walks on the beach'); - - const getAsNonAdmin = await GRAPHQL_CLIENT_2.query( - `query { - getEmployee(id: "${employeeId}") { - id - email - bio - } - }`, - {}, - ); - logDebug(getAsNonAdmin); - // Should not be able to view the email as the non owner - expect(getAsNonAdmin.data.getEmployee.email).toBeNull(); - // Should be able to view the bio. - expect(getAsNonAdmin.data.getEmployee.bio).toEqual('Likes long walks on the beach'); - expect(getAsNonAdmin.errors).toHaveLength(1); - - const listAsNonAdmin = await GRAPHQL_CLIENT_2.query( - `query { - listEmployees { - items { - id - bio - } - } - }`, - {}, - ); - logDebug(listAsNonAdmin); - expect(listAsNonAdmin.data.listEmployees.items.length).toBeGreaterThan(1); - let seenId = false; - for (const item of listAsNonAdmin.data.listEmployees.items) { - if (item.id === employeeId) { - seenId = true; - expect(item.bio).toEqual('Likes long walks on the beach'); - } - } - expect(seenId).toEqual(true); -}); - -test('that only owners may "delete" i.e. update the field to null.', async () => { - const createUser1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createEmployee(input: { email: "user3@test.com", salary: 200, notes: "note1" }) { - id - email - salary - notes - } - }`, - {}, - ); - logDebug(createUser1); - const employeeId = createUser1.data.createEmployee.id; - expect(employeeId).not.toBeNull(); - expect(createUser1.data.createEmployee.email).toEqual('user3@test.com'); - expect(createUser1.data.createEmployee.salary).toEqual(200); - expect(createUser1.data.createEmployee.notes).toEqual('note1'); - - const tryToDeleteUserNotes = await GRAPHQL_CLIENT_2.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", notes: null }) { - id - notes - } - }`, - {}, - ); - logDebug(tryToDeleteUserNotes); - expect(tryToDeleteUserNotes.data.updateEmployee).toBeNull(); - expect(tryToDeleteUserNotes.errors).toHaveLength(1); - - const updateNewsWithNotes = await GRAPHQL_CLIENT_3.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", notes: "something else" }) { - id - notes - } - }`, - {}, - ); - expect(updateNewsWithNotes.data.updateEmployee.notes).toEqual('something else'); - - const updateAsAdmin = await GRAPHQL_CLIENT_1.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", notes: null }) { - id - notes - } - }`, - {}, - ); - expect(updateAsAdmin.data.updateEmployee).toBeNull(); - expect(updateAsAdmin.errors).toHaveLength(1); - - const deleteNotes = await GRAPHQL_CLIENT_3.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", notes: null }) { - id - notes - } - }`, - {}, - ); - expect(deleteNotes.data.updateEmployee.notes).toBeNull(); -}); - -test('with auth with subscriptions on default behavior', async () => { - /** - * client 1 and 2 are in the same user pool though client 1 should - * not be able to see notes if they are created by client 2 - * */ - const secureNote1 = 'secureNote1'; - const createStudent2 = await GRAPHQL_CLIENT_2.query( - `mutation { - createStudent(input: {bio: "bio1", name: "student1", notes: "${secureNote1}"}) { - id - bio - name - notes - owner - } - }`, - {}, - ); - logDebug(createStudent2); - expect(createStudent2.data.createStudent.id).toBeDefined(); - const createStudent1queryID = createStudent2.data.createStudent.id; - expect(createStudent2.data.createStudent.bio).toEqual('bio1'); - expect(createStudent2.data.createStudent.notes).toBeNull(); - // running query as username2 should return value - const queryForStudent2 = await GRAPHQL_CLIENT_2.query( - `query { - getStudent(id: "${createStudent1queryID}") { - bio - id - name - notes - owner - } - }`, - {}, - ); - logDebug(queryForStudent2); - expect(queryForStudent2.data.getStudent.notes).toEqual(secureNote1); - - // running query as username3 should return the type though return notes as null - const queryAsStudent1 = await GRAPHQL_CLIENT_1.query( - `query { - getStudent(id: "${createStudent1queryID}") { - bio - id - name - notes - owner - } - }`, - {}, - ); - console.log(JSON.stringify(queryAsStudent1)); - expect(queryAsStudent1.data.getStudent.notes).toBeNull(); -}); - -test('AND per-field dynamic auth rule test', async () => { - const createPostResponse = await GRAPHQL_CLIENT_1.query(`mutation CreatePost { - createPost(input: {owner1: "${USERNAME1}", text: "mytext"}) { - id - text - owner1 - } - }`); - logDebug(createPostResponse); - const postID1 = createPostResponse.data.createPost.id; - expect(postID1).toBeDefined(); - expect(createPostResponse.data.createPost.text).toEqual('mytext'); - expect(createPostResponse.data.createPost.owner1).toEqual(USERNAME1); - - const badUpdatePostResponse = await GRAPHQL_CLIENT_1.query(`mutation UpdatePost { - updatePost(input: {id: "${postID1}", text: "newText", owner1: "${USERNAME1}"}) { - id - owner1 - text - } - } - `); - logDebug(badUpdatePostResponse); - expect(badUpdatePostResponse.errors[0].data).toBeNull(); - expect(badUpdatePostResponse.errors[0].errorType).toEqual('DynamoDB:ConditionalCheckFailedException'); - - const correctUpdatePostResponse = await GRAPHQL_CLIENT_1.query(`mutation UpdatePost { - updatePost(input: {id: "${postID1}", text: "newText"}) { - id - owner1 - text - } - }`); - logDebug(correctUpdatePostResponse); - expect(correctUpdatePostResponse.data.updatePost.owner1).toEqual(USERNAME1); - expect(correctUpdatePostResponse.data.updatePost.text).toEqual('newText'); -}); - -test('field auth on an operation type as user in admin group', async () => { - const queryResponse = await GRAPHQL_CLIENT_1.query(` - query SomeFunction { - someFunction - } - `); - // no errors though it should return null - logDebug(queryResponse); - expect(queryResponse.data.someFunction).toBeNull(); -}); - -test('field auth on an operation type as user not in admin group', async () => { - const queryResponse = await GRAPHQL_CLIENT_3.query(` - query SomeFunction { - someFunction - } - `); - // should return an error - logDebug(queryResponse); - expect(queryResponse.errors).toBeDefined(); - expect(queryResponse.errors[0].message).toEqual('Unauthorized'); -}); diff --git a/packages/amplify-util-mock/src/__e2e__/subscriptions-with-auth.e2e.test.ts b/packages/amplify-util-mock/src/__e2e__/subscriptions-with-auth.e2e.test.ts deleted file mode 100644 index d04641c72a..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/subscriptions-with-auth.e2e.test.ts +++ /dev/null @@ -1,619 +0,0 @@ -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { FeatureFlagProvider, GraphQLTransform } from 'graphql-transformer-core'; -import AWSAppSyncClient, { AUTH_TYPE } from 'aws-appsync'; -import AWS = require('aws-sdk'); -import gql from 'graphql-tag'; -import { signUpAddToGroupAndGetJwtToken } from './utils/cognito-utils'; -import { deploy, launchDDBLocal, terminateDDB } from './utils/index'; -import 'isomorphic-fetch'; -import { GraphQLClient } from './utils/graphql-client'; - -// to deal with subscriptions in node env -(global as any).WebSocket = require('ws'); - -// To overcome of the way of how AmplifyJS picks up currentUserCredentials -const anyAWS = AWS as any; - -if (anyAWS && anyAWS.config && anyAWS.config.credentials) { - delete anyAWS.config.credentials; -} - -// delays -const SUBSCRIPTION_DELAY = 2000; -const PROPAGATAION_DELAY = 5000; -const JEST_TIMEOUT = 20000; - -jest.setTimeout(JEST_TIMEOUT); - -let GRAPHQL_ENDPOINT = undefined; -let ddbEmulator = null; -let dbPath = null; -let server; -const AWS_REGION = 'my-local-2'; - -let APPSYNC_CLIENT_1: AWSAppSyncClient = undefined; -let APPSYNC_CLIENT_2: AWSAppSyncClient = undefined; -let APPSYNC_CLIENT_3: AWSAppSyncClient = undefined; - -let GRAPHQL_CLIENT_1: GraphQLClient = undefined; -let GRAPHQL_CLIENT_2: GraphQLClient = undefined; -let GRAPHQL_CLIENT_3: GraphQLClient = undefined; - -const USER_POOL_ID = 'fake_user_pool'; - -const USERNAME1 = 'user1@domain.com'; -const USERNAME2 = 'user2@domain.com'; -const USERNAME3 = 'user3@domain.com'; - -const INSTRUCTOR_GROUP_NAME = 'Instructor'; -const ADMIN_GROUP_NAME = 'Admin'; -const MEMBER_GROUP_NAME = 'Member'; - -/** - * Interface Inputs - */ -interface MemberInput { - id: string; - name?: string; - createdAt?: string; - updatedAt?: string; -} - -interface CreateStudentInput { - id?: string; - name?: string; - email?: string; - ssn?: string; -} - -interface UpdateStudentInput { - id: string; - name?: string; - email?: string; - ssn?: string; -} - -interface CreatePostInput { - id?: string; - title: string; - postOwner: string; -} - -interface DeleteTypeInput { - id: string; -} - -beforeAll(async () => { - const validSchema = ` - type Student @model - @auth(rules: [ - {allow: owner} - {allow: groups, groups: ["Instructor"]} - ]) { - id: String, - name: String, - email: AWSEmail, - ssn: String @auth(rules: [{allow: owner}]) - } - - type Member @model - @auth(rules: [ - { allow: groups, groups: ["Admin"] } - { allow: groups, groups: ["Member"], operations: [read] } - ]) { - id: ID - name: String - createdAt: AWSDateTime - updatedAt: AWSDateTime - } - - type Post @model - @auth(rules: [ - {allow: owner, ownerField: "postOwner"} - ]) - { - id: ID! - title: String - postOwner: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - featureFlags: { - getBoolean: (name) => name === 'improvePluralization', - } as FeatureFlagProvider, - }); - - try { - const out = transformer.transform(validSchema); - - let ddbClient; - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - - const result = await deploy(out, ddbClient); - server = result.simulator; - - GRAPHQL_ENDPOINT = server.url + '/graphql'; - // Verify we have all the details - expect(GRAPHQL_ENDPOINT).toBeTruthy(); - // Configure Amplify, create users, and sign in. - const idToken1 = signUpAddToGroupAndGetJwtToken(USER_POOL_ID, USERNAME1, USERNAME1, [INSTRUCTOR_GROUP_NAME, ADMIN_GROUP_NAME]); - APPSYNC_CLIENT_1 = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: AWS_REGION, - disableOffline: true, - offlineConfig: { - keyPrefix: 'userPools', - }, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: idToken1, - }, - }); - GRAPHQL_CLIENT_1 = new GraphQLClient(GRAPHQL_ENDPOINT, { - Authorization: idToken1, - }); - const idToken2 = signUpAddToGroupAndGetJwtToken(USER_POOL_ID, USERNAME2, USERNAME2, [INSTRUCTOR_GROUP_NAME, MEMBER_GROUP_NAME]); - APPSYNC_CLIENT_2 = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: AWS_REGION, - disableOffline: true, - offlineConfig: { - keyPrefix: 'userPools', - }, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: idToken2, - }, - }); - GRAPHQL_CLIENT_2 = new GraphQLClient(GRAPHQL_ENDPOINT, { - Authorization: idToken2, - }); - const idToken3 = signUpAddToGroupAndGetJwtToken(USER_POOL_ID, USERNAME3, USERNAME3, []); - APPSYNC_CLIENT_3 = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: AWS_REGION, - disableOffline: true, - offlineConfig: { - keyPrefix: 'userPools', - }, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: idToken3, - }, - }); - GRAPHQL_CLIENT_3 = new GraphQLClient(GRAPHQL_ENDPOINT, { - Authorization: idToken3, - }); - - // Wait for any propagation to avoid random - // "The security token included in the request is invalid" errors - await new Promise((res) => setTimeout(res, PROPAGATAION_DELAY)); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - try { - if (server) { - await server.stop(); - } - await terminateDDB(ddbEmulator, dbPath); - } catch (e) { - console.error(e); - throw e; - } -}); - -/** - * Tests - */ -test('that only authorized members are allowed to view subscriptions', async () => { - // subscribe to create students as user 2 - const observer = APPSYNC_CLIENT_2.subscribe({ - query: gql` - subscription OnCreateStudent { - onCreateStudent { - id - name - email - ssn - owner - } - } - `, - }); - - const subscriptionPromise = new Promise((resolve, _) => { - let subscription = observer.subscribe((event: any) => { - const student = event.data.onCreateStudent; - subscription.unsubscribe(); - expect(student.name).toEqual('student1'); - expect(student.email).toEqual('student1@domain.com'); - expect(student.ssn).toBeNull(); - resolve(undefined); - }); - }); - - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - - await createStudent(GRAPHQL_CLIENT_1, { - name: 'student1', - email: 'student1@domain.com', - ssn: 'AAA-01-SSSS', - }); - - return subscriptionPromise; -}); - -test('a subscription on update', async () => { - // susbcribe to update students as user 2 - const subscriptionPromise = new Promise((resolve, _) => { - const observer = APPSYNC_CLIENT_2.subscribe({ - query: gql` - subscription OnUpdateStudent { - onUpdateStudent { - id - name - email - ssn - owner - } - } - `, - }); - let subscription = observer.subscribe((event: any) => { - const student = event.data.onUpdateStudent; - subscription.unsubscribe(); - expect(student.id).toEqual(student3ID); - expect(student.name).toEqual('student3'); - expect(student.email).toEqual('emailChanged@domain.com'); - expect(student.ssn).toBeNull(); - resolve(undefined); - }); - }); - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - - const student3 = await createStudent(GRAPHQL_CLIENT_1, { - name: 'student3', - email: 'changeThisEmail@domain.com', - ssn: 'CCC-01-SNSN', - }); - - expect(student3.data.createStudent).toBeDefined(); - const student3ID = student3.data.createStudent.id; - expect(student3.data.createStudent.name).toEqual('student3'); - expect(student3.data.createStudent.email).toEqual('changeThisEmail@domain.com'); - expect(student3.data.createStudent.ssn).toBeNull(); - - await updateStudent(GRAPHQL_CLIENT_1, { - id: student3ID, - email: 'emailChanged@domain.com', - }); - - return subscriptionPromise; -}); - -test('a subscription on delete', async () => { - // subscribe to onDelete as user 2 - const subscriptionPromise = new Promise((resolve, _) => { - const observer = APPSYNC_CLIENT_2.subscribe({ - query: gql` - subscription OnDeleteStudent { - onDeleteStudent { - id - name - email - ssn - owner - } - } - `, - }); - let subscription = observer.subscribe((event: any) => { - const student = event.data.onDeleteStudent; - subscription.unsubscribe(); - expect(student.id).toEqual(student4ID); - expect(student.name).toEqual('student4'); - expect(student.email).toEqual('plsDelete@domain.com'); - expect(student.ssn).toBeNull(); - resolve(undefined); - }); - }); - - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - - const student4 = await createStudent(GRAPHQL_CLIENT_1, { - name: 'student4', - email: 'plsDelete@domain.com', - ssn: 'DDD-02-SNSN', - }); - expect(student4).toBeDefined(); - const student4ID = student4.data.createStudent.id; - expect(student4.data.createStudent.email).toEqual('plsDelete@domain.com'); - expect(student4.data.createStudent.ssn).toBeNull(); - - await deleteStudent(GRAPHQL_CLIENT_1, { id: student4ID }); - - return subscriptionPromise; -}); - -test('that group is only allowed to listen to subscriptions and listen to onCreate', async () => { - const memberID = '001'; - const memberName = 'username00'; - // test that a user that only read can't mutate - const result = await createMember(GRAPHQL_CLIENT_2, { id: '001', name: 'notUser' }); - expect(result.errors[0].message === 'Unauthorized'); - - // though they should see when a new member is created - const subscriptionPromise = new Promise((resolve, _) => { - const observer = APPSYNC_CLIENT_2.subscribe({ - query: gql` - subscription OnCreateMember { - onCreateMember { - id - name - createdAt - updatedAt - } - } - `, - }); - const subscription = observer.subscribe((event: any) => { - const member = event.data.onCreateMember; - subscription.unsubscribe(); - expect(member).toBeDefined(); - expect(member.id).toEqual(memberID); - expect(member.name).toEqual(memberName); - resolve(undefined); - }); - }); - - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - // user that is authorized creates the update the mutation - await createMember(GRAPHQL_CLIENT_1, { id: memberID, name: memberName }); - - return subscriptionPromise; -}); - -test('authorized group is allowed to listen to onUpdate', async () => { - const memberID = '001'; - const memberName = 'newUsername'; - - const subscriptionPromise = new Promise((resolve, _) => { - const observer = APPSYNC_CLIENT_2.subscribe({ - query: gql` - subscription OnUpdateMember { - onUpdateMember { - id - name - createdAt - updatedAt - } - } - `, - }); - const subscription = observer.subscribe((event: any) => { - const subResponse = event.data.onUpdateMember; - subscription.unsubscribe(); - expect(subResponse).toBeDefined(); - expect(subResponse.id).toEqual(memberID); - expect(subResponse.name).toEqual(memberName); - resolve(undefined); - }); - }); - - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - // user that is authorized creates the update the mutation - await updateMember(GRAPHQL_CLIENT_1, { id: memberID, name: memberName }); - - return subscriptionPromise; -}); - -test('authoirzed group is allowed to listen to onDelete', async () => { - const memberID = '001'; - const memberName = 'newUsername'; - - const subscriptionPromise = new Promise((resolve, _) => { - const observer = APPSYNC_CLIENT_2.subscribe({ - query: gql` - subscription OnDeleteMember { - onDeleteMember { - id - name - createdAt - updatedAt - } - } - `, - }); - const subscription = observer.subscribe((event: any) => { - const subResponse = event.data.onDeleteMember; - subscription.unsubscribe(); - expect(subResponse).toBeDefined(); - expect(subResponse.id).toEqual(memberID); - expect(subResponse.name).toEqual(memberName); - resolve(undefined); - }); - }); - - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - // user that is authorized creates the update the mutation - await deleteMember(GRAPHQL_CLIENT_1, { id: memberID }); - - return subscriptionPromise; -}); - -// ownerField Tests -test('subscription onCreatePost with ownerField', async () => { - const subscriptionPromise = new Promise((resolve, _) => { - const observer = APPSYNC_CLIENT_1.subscribe({ - query: gql` - subscription OnCreatePost { - onCreatePost(postOwner: "${USERNAME1}") { - id - title - postOwner - } - }`, - }); - let subscription = observer.subscribe((event: any) => { - const post = event.data.onCreatePost; - subscription.unsubscribe(); - expect(post.title).toEqual('someTitle'); - expect(post.postOwner).toEqual(USERNAME1); - resolve(undefined); - }); - }); - - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - - await createPost(GRAPHQL_CLIENT_1, { - title: 'someTitle', - postOwner: USERNAME1, - }); - - return subscriptionPromise; -}); - -// mutations -async function createStudent(client: GraphQLClient, input: CreateStudentInput) { - const request = ` - mutation CreateStudent($input: CreateStudentInput!) { - createStudent(input: $input) { - id - name - email - ssn - owner - } - } - `; - - const result = await client.query(request, { - input: input, - }); - return result; -} - -async function createMember(client: GraphQLClient, input: MemberInput) { - const request = ` - mutation CreateMember($input: CreateMemberInput!) { - createMember(input: $input) { - id - name - createdAt - updatedAt - } - } - `; - - const result = await client.query(request, { - input: input, - }); - return result; -} - -async function updateMember(client: GraphQLClient, input: MemberInput) { - const request = ` - mutation UpdateMember($input: UpdateMemberInput!) { - updateMember(input: $input) { - id - name - createdAt - updatedAt - } - } - `; - - const result = await client.query(request, { - input: input, - }); - return result; -} - -async function deleteMember(client: GraphQLClient, input: MemberInput) { - const request = ` - mutation DeleteMember($input: DeleteMemberInput!) { - deleteMember(input: $input) { - id - name - createdAt - updatedAt - } - } - `; - - const result = await client.query(request, { - input: input, - }); - return result; -} - -async function updateStudent(client: GraphQLClient, input: UpdateStudentInput) { - const request = ` - mutation UpdateStudent($input: UpdateStudentInput!) { - updateStudent(input: $input) { - id - name - email - ssn - owner - } - } - `; - - const result = await client.query(request, { - input: input, - }); - return result; -} - -async function deleteStudent(client: GraphQLClient, input: DeleteTypeInput) { - const request = ` - mutation DeleteStudent($input: DeleteStudentInput!) { - deleteStudent(input: $input) { - id - name - email - ssn - owner - } - } - `; - - const result = await client.query(request, { - input: input, - }); - return result; -} - -async function createPost(client: GraphQLClient, input: CreatePostInput) { - const request = ` - mutation CreatePost($input: CreatePostInput!) { - createPost(input: $input) { - id - title - postOwner - } - } - `; - - const result = await client.query(request, { - input: input, - }); - return result; -} diff --git a/packages/amplify-util-mock/src/__e2e__/util-method-e2e.test.ts b/packages/amplify-util-mock/src/__e2e__/util-method-e2e.test.ts deleted file mode 100644 index 87af241f51..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/util-method-e2e.test.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { AmplifyAppSyncSimulator } from '@aws-amplify/amplify-appsync-simulator'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { FeatureFlagProvider, GraphQLTransform } from 'graphql-transformer-core'; -import { GraphQLClient } from './utils/graphql-client'; -import { deploy, launchDDBLocal, terminateDDB, logDebug, reDeploy } from './utils/index'; - -let GRAPHQL_ENDPOINT = undefined; -let GRAPHQL_CLIENT = undefined; -let ddbEmulator = null; -let dbPath = null; -let server: AmplifyAppSyncSimulator; -jest.setTimeout(2000000); - -const runTransformer = async (validSchema: string) => { - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags: { - getBoolean: (name) => name === 'improvePluralization', - } as FeatureFlagProvider, - }); - const out = await transformer.transform(validSchema); - return out; -}; -let ddbClient; -const validSchema = /* GraphQL */ ` - type Post @model { - id: ID! - title: String! - } -`; - -beforeAll(async () => { - process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; - - try { - const out = await runTransformer(validSchema); - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - const result = await deploy(out, ddbClient); - server = result.simulator; - - GRAPHQL_ENDPOINT = server.url + '/graphql'; - logDebug(`Using graphql url: ${GRAPHQL_ENDPOINT}`); - - const apiKey = result.config.appSync.apiKey; - logDebug(apiKey); - GRAPHQL_CLIENT = new GraphQLClient(GRAPHQL_ENDPOINT, { - 'x-api-key': apiKey, - }); - } catch (e) { - logDebug('error when setting up test'); - logDebug(e); - expect(true).toEqual(false); - } -}); - -afterEach(async () => { - const out = await runTransformer(validSchema); - await reDeploy(out, server, ddbClient); -}); - -afterAll(async () => { - if (server) { - await server.stop(); - } - await terminateDDB(ddbEmulator, dbPath); -}); - -describe('$util.validate', () => { - let transformerOutput; - const queryString = /* GraphQL */ ` - query getPost { - getPost(id: "10") { - id - title - } - } - `; - beforeEach(async () => { - transformerOutput = await runTransformer(validSchema); - }); - test('it should not throw error when validation condition is true', async () => { - transformerOutput.resolvers[ - 'Query.getPost.res.vtl' - ] = `$util.validate(true, "Validation Error", "ValidationError", { "id": "11", "title": "Title Sent from Error" })\n$util.toJson({"id": 11, "title": "Non Error title"})`; - await reDeploy(transformerOutput, server, ddbClient); - const response = await GRAPHQL_CLIENT.query(queryString, {}); - expect(response.data).toBeDefined(); - expect(response.data.getPost.id).toEqual('11'); - expect(response.data.getPost.title).toEqual('Non Error title'); - - expect(response.errors).not.toBeDefined(); - }); - - test('$util.validate should throw error and pass the data along with error message and error type when the condition fails', async () => { - transformerOutput.resolvers[ - 'Query.getPost.req.vtl' - ] = `$util.validate(false, "Validation Error", "ValidationError", { "id": "10", "title": "Title Sent from Error" })`; - await reDeploy(transformerOutput, server, ddbClient); - - const response = await GRAPHQL_CLIENT.query(queryString, {}); - expect(response.data).toBeDefined(); - expect(response.data.getPost.id).toEqual('10'); - expect(response.data.getPost.title).toEqual('Title Sent from Error'); - - expect(response.errors).toBeDefined(); - expect(response.errors).toHaveLength(1); - expect(response.errors[0].message).toEqual('Validation Error'); - expect(response.errors[0].errorType).toEqual('ValidationError'); - }); - - test('$util.validate should return error message and CustomTemplateException when error type is not passed', async () => { - transformerOutput.resolvers['Query.getPost.req.vtl'] = `$util.validate(false, "Validation Error")`; - await reDeploy(transformerOutput, server, ddbClient); - - const response = await GRAPHQL_CLIENT.query(queryString, {}); - expect(response.data).toBeDefined(); - expect(response.data.getPost).toBe(null); - - expect(response.errors).toBeDefined(); - expect(response.errors).toHaveLength(1); - expect(response.errors[0].message).toEqual('Validation Error'); - expect(response.errors[0].errorType).toEqual('CustomTemplateException'); - }); - - test('$util.validate should allow overriding the error type', async () => { - transformerOutput.resolvers['Query.getPost.req.vtl'] = `$util.validate(false, "Validation Error", "MyErrorType")`; - await reDeploy(transformerOutput, server, ddbClient); - - const response = await GRAPHQL_CLIENT.query(queryString, {}); - expect(response.data).toBeDefined(); - expect(response.data.getPost).toBe(null); - - expect(response.errors).toBeDefined(); - expect(response.errors).toHaveLength(1); - expect(response.errors[0].message).toEqual('Validation Error'); - expect(response.errors[0].errorType).toEqual('MyErrorType'); - }); -}); diff --git a/packages/amplify-util-mock/src/__e2e__/utils/cognito-utils.ts b/packages/amplify-util-mock/src/__e2e__/utils/cognito-utils.ts deleted file mode 100644 index f9c217bc11..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/utils/cognito-utils.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { sign, verify } from 'jsonwebtoken'; -import { v4 } from 'uuid'; - -export function signUpAddToGroupAndGetJwtToken( - userPool: string, - username: string, - email: string, - groups: string[] = [], - tokenType: 'id' | 'access' = 'id', -) { - const token = { - sub: v4(), - aud: '75pk49boud2olipfda0ke3snic', - 'cognito:groups': groups, - event_id: v4(), - token_use: tokenType, - auth_time: Math.floor(Date.now() / 1000), - iss: `https://cognito-idp.us-west-2.amazonaws.com/us-west-2_${userPool}`, - 'cognito:username': username, - exp: Math.floor(Date.now() / 1000) + 10000, - iat: Math.floor(Date.now() / 1000), - email, - }; - return generateToken(token); -} - -function generateToken(decodedToken: string | object): string { - try { - if (typeof decodedToken === 'string') { - decodedToken = JSON.parse(decodedToken); - } - const token = sign(decodedToken, 'open-secrete'); - verify(token, 'open-secrete'); - return token; - } catch (e) { - const err = new Error('Error when generating OIDC token: ' + e.message); - throw err; - } -} diff --git a/packages/amplify-util-mock/src/__e2e__/utils/graphql-client.ts b/packages/amplify-util-mock/src/__e2e__/utils/graphql-client.ts deleted file mode 100644 index cbb61f1ca2..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/utils/graphql-client.ts +++ /dev/null @@ -1,30 +0,0 @@ -import axios from 'axios'; - -export interface GraphQLLocation { - line: number; - column: number; -} -export interface GraphQLError { - message: string; - locations: GraphQLLocation[]; - path: string[]; -} -export interface GraphQLResponse { - data: any; - errors: GraphQLError[]; -} -export class GraphQLClient { - constructor(private url: string, private headers: any) {} - - async query(query: string, variables: any): Promise { - const axRes = await axios.post( - this.url, - { - query, - variables, - }, - { headers: this.headers }, - ); - return axRes.data; - } -} diff --git a/packages/amplify-util-mock/src/__e2e__/utils/index.ts b/packages/amplify-util-mock/src/__e2e__/utils/index.ts deleted file mode 100644 index 6d9c3709d3..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/utils/index.ts +++ /dev/null @@ -1,168 +0,0 @@ -import * as path from 'path'; -import { AmplifyAppSyncSimulator } from '@aws-amplify/amplify-appsync-simulator'; -import * as dynamoEmulator from 'amplify-category-api-dynamodb-simulator'; -import * as fs from 'fs-extra'; -import { v4 } from 'uuid'; -import { DynamoDB } from 'aws-sdk'; -import { functionRuntimeContributorFactory } from 'amplify-nodejs-function-runtime-provider'; -import { ExecuteTransformConfig, executeTransform } from '@aws-amplify/graphql-transformer'; -import { DeploymentResources, TransformManager } from '@aws-amplify/graphql-transformer-test-utils'; -import { AppSyncAuthConfiguration, ModelDataSourceStrategy } from '@aws-amplify/graphql-transformer-interfaces'; -import { DDB_DEFAULT_DATASOURCE_STRATEGY, constructDataSourceStrategies } from '@aws-amplify/graphql-transformer-core'; -import { processTransformerStacks } from '../../CFNParser/appsync-resource-processor'; -import { configureDDBDataSource, createAndUpdateTable } from '../../utils/dynamo-db'; -import { getFunctionDetails } from './lambda-helper'; - -const invoke = functionRuntimeContributorFactory({}).invoke; - -export * from './graphql-client'; - -jest.mock('@aws-amplify/amplify-cli-core', () => ({ - pathManager: { - getAmplifyPackageLibDirPath: jest.fn().mockReturnValue('../amplify-dynamodb-simulator'), - }, -})); - -const getAuthenticationTypesForAuthConfig = (authConfig?: AppSyncAuthConfiguration): (string | undefined)[] => - [authConfig?.defaultAuthentication, ...(authConfig?.additionalAuthenticationProviders ?? [])].map( - (authConfigEntry) => authConfigEntry?.authenticationType, - ); - -const hasIamAuth = (authConfig?: AppSyncAuthConfiguration): boolean => - getAuthenticationTypesForAuthConfig(authConfig).some((authType) => authType === 'AWS_IAM'); - -const hasUserPoolAuth = (authConfig?: AppSyncAuthConfiguration): boolean => - getAuthenticationTypesForAuthConfig(authConfig).some((authType) => authType === 'AMAZON_COGNITO_USER_POOLS'); - -export const transformAndSynth = ( - options: Omit & { - dataSourceStrategies?: Record; - }, -): DeploymentResources => { - const transformManager = new TransformManager(); - executeTransform({ - ...options, - scope: transformManager.rootStack, - nestedStackProvider: transformManager.getNestedStackProvider(), - assetProvider: transformManager.getAssetProvider(), - synthParameters: transformManager.getSynthParameters(hasIamAuth(options.authConfig), hasUserPoolAuth(options.authConfig)), - dataSourceStrategies: options.dataSourceStrategies ?? constructDataSourceStrategies(options.schema, DDB_DEFAULT_DATASOURCE_STRATEGY), - }); - return transformManager.generateDeploymentResources(); -}; - -export const defaultTransformParams: Pick = { - transformersFactoryArgs: {}, - transformParameters: { - shouldDeepMergeDirectiveConfigDefaults: true, - disableResolverDeduping: false, - sandboxModeEnabled: false, - useSubUsernameForDefaultIdentityClaim: true, - subscriptionsInheritPrimaryAuth: false, - populateOwnerFieldForStaticGroupAuth: true, - suppressApiKeyGeneration: false, - secondaryKeyAsGSI: true, - enableAutoIndexQueryNames: true, - respectPrimaryKeyAttributesOnConnectionField: true, - enableSearchNodeToNodeEncryption: false, - enableTransformerCfnOutputs: true, - allowDestructiveGraphqlSchemaUpdates: false, - replaceTableUponGsiUpdate: false, - allowGen1Patterns: true, - }, -}; - -export async function launchDDBLocal() { - let dbPath; - while (true) { - dbPath = path.join('/tmp', `amplify-cli-emulator-dynamodb-${v4()}`); - if (!fs.existsSync(dbPath)) break; - } - - fs.ensureDirSync(dbPath); - const emulator = await dynamoEmulator.launch({ - dbPath, - port: null, - }); - const client: DynamoDB = await dynamoEmulator.getClient(emulator); - logDebug(dbPath); - return { emulator, dbPath, client }; -} - -export async function deploy(transformerOutput: any, client?: DynamoDB): Promise<{ config: any; simulator: AmplifyAppSyncSimulator }> { - let config: any = processTransformerStacks(transformerOutput); - config.appSync.apiKey = 'da-fake-api-key'; - - if (client) { - await createAndUpdateTable(client, config); - config = configureDDBDataSource(config, client.config); - } - configureLambdaDataSource(config); - const simulator = await runAppSyncSimulator(config); - return { simulator, config }; -} - -export async function reDeploy( - transformerOutput: any, - simulator: AmplifyAppSyncSimulator, - client?: DynamoDB, -): Promise<{ config: any; simulator: AmplifyAppSyncSimulator }> { - let config: any = processTransformerStacks(transformerOutput); - config.appSync.apiKey = 'da-fake-api-key'; - - if (client) { - await createAndUpdateTable(client, config); - config = configureDDBDataSource(config, client.config); - } - configureLambdaDataSource(config); - simulator?.reload(config); - return { simulator, config }; -} - -async function configureLambdaDataSource(config) { - config.dataSources - .filter((d) => d.type === 'AWS_LAMBDA') - .forEach((d) => { - const arn = d.LambdaFunctionArn; - const arnParts = arn.split(':'); - let functionName = arnParts[arnParts.length - 1]; - const lambdaConfig = getFunctionDetails(functionName); - d.invoke = (payload) => { - logDebug('Invoking lambda with config', lambdaConfig); - return invoke({ - srcRoot: lambdaConfig.packageFolder, - runtime: 'nodejs', - handler: `${functionName}.${lambdaConfig.handler}`, - event: JSON.stringify(payload), - }); - }; - }); - return config; -} -export async function terminateDDB(emulator, dbPath) { - try { - if (emulator && emulator.terminate) { - await emulator.terminate(); - } - } catch (e) { - logDebug('Failed to terminate the Local DynamoDB Server', e); - } - try { - fs.removeSync(dbPath); - } catch (e) { - logDebug('Failed delete Local DynamoDB Server Folder', e); - } -} - -export async function runAppSyncSimulator(config, port?: number, wsPort?: number): Promise { - const appsyncSimulator = new AmplifyAppSyncSimulator({ port, wsPort }); - await appsyncSimulator.start(); - await appsyncSimulator.init(config); - return appsyncSimulator; -} - -export function logDebug(...msgs) { - if (process.env.DEBUG || process.env.CI) { - console.log(...msgs); - } -} diff --git a/packages/amplify-util-mock/src/__e2e__/utils/lambda-helper.ts b/packages/amplify-util-mock/src/__e2e__/utils/lambda-helper.ts deleted file mode 100644 index e0b40f8e8c..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/utils/lambda-helper.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as path from 'path'; -import * as fs from 'fs-extra'; - -export function getFunctionDetails(fnName: string) { - const lambdaFolder = path.join(__dirname, 'lambda_functions'); - if (!fs.existsSync(path.join(lambdaFolder, 'src', `${fnName}.js`))) { - throw new Error(`Can not find lambda function ${fnName}`); - } - - return { - packageFolder: lambdaFolder, - fileName: `${fnName}.js`, - handler: 'handler', - }; -} diff --git a/packages/amplify-util-mock/src/__e2e__/utils/lambda_functions/src/echoFunction.js b/packages/amplify-util-mock/src/__e2e__/utils/lambda_functions/src/echoFunction.js deleted file mode 100644 index fc29e6f816..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/utils/lambda_functions/src/echoFunction.js +++ /dev/null @@ -1,4 +0,0 @@ -exports.handler = async (event) => { - console.log(event); - return event; -}; diff --git a/packages/amplify-util-mock/src/__e2e__/utils/lambda_functions/src/hello.js b/packages/amplify-util-mock/src/__e2e__/utils/lambda_functions/src/hello.js deleted file mode 100644 index 7bbd9eb082..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/utils/lambda_functions/src/hello.js +++ /dev/null @@ -1,4 +0,0 @@ -exports.handler = async (event) => { - console.log(event); - return 'Hello, world!'; -}; diff --git a/packages/amplify-util-mock/src/__e2e__/utils/test-storage.ts b/packages/amplify-util-mock/src/__e2e__/utils/test-storage.ts deleted file mode 100644 index f28f1b2b44..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/utils/test-storage.ts +++ /dev/null @@ -1,34 +0,0 @@ -export default class TestStorage { - private data: any; - - constructor() { - this.data = {}; - } - - // set item with the key - public setItem(key: string, value: string): string { - this.data[key] = value; - return value; - } - - // get item with the key - public getItem(key: string): string { - return this.data[key]; - } - - // remove item with the key - public removeItem(key: string): void { - this.data[key] = undefined; - } - - // clear out the storage - public clear(): void { - this.data = {}; - } - - // If the storage operations are async(i.e AsyncStorage) - // Then you need to sync those items into the memory in this method - public sync(): Promise { - return Promise.resolve(this.data); - } -} diff --git a/packages/amplify-util-mock/src/__e2e__/versioned-model-transformer.e2e.test.ts b/packages/amplify-util-mock/src/__e2e__/versioned-model-transformer.e2e.test.ts deleted file mode 100644 index 69ff4a99c5..0000000000 --- a/packages/amplify-util-mock/src/__e2e__/versioned-model-transformer.e2e.test.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { FeatureFlagProvider, GraphQLTransform } from 'graphql-transformer-core'; -import { VersionedModelTransformer } from 'graphql-versioned-transformer'; -import { GraphQLClient } from './utils/graphql-client'; -import { deploy, launchDDBLocal, terminateDDB, logDebug } from './utils/index'; - -jest.setTimeout(20000); - -let GRAPHQL_CLIENT = undefined; -let ddbEmulator = null; -let dbPath = null; -let server; - -beforeAll(async () => { - const validSchema = ` - type Post @model @versioned { - id: ID! - title: String! - version: Int! - createdAt: String - updatedAt: String - } - `; - - try { - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new VersionedModelTransformer()], - featureFlags: { - getBoolean: (name) => name === 'improvePluralization', - } as FeatureFlagProvider, - }); - const out = transformer.transform(validSchema); - - let ddbClient; - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - - const result = await deploy(out, ddbClient); - server = result.simulator; - - const endpoint = server.url + '/graphql'; - logDebug(`Using graphql url: ${endpoint}`); - - const apiKey = result.config.appSync.apiKey; - expect(apiKey).toBeDefined(); - expect(endpoint).toBeDefined(); - GRAPHQL_CLIENT = new GraphQLClient(endpoint, { 'x-api-key': apiKey }); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - try { - if (server) { - await server.stop(); - } - await terminateDDB(ddbEmulator, dbPath); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -/** - * Test queries below - */ -test('createPost mutation', async () => { - const response = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - version - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.version).toEqual(1); -}); - -test('updatePost mutation', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Update" }) { - id - title - createdAt - updatedAt - version - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Update'); - expect(createResponse.data.createPost.version).toEqual(1); - const updateResponse = await GRAPHQL_CLIENT.query( - `mutation { - updatePost(input: { - id: "${createResponse.data.createPost.id}", - title: "Bye, World!", - expectedVersion: ${createResponse.data.createPost.version} - }) { - id - title - version - } - }`, - {}, - ); - expect(updateResponse.data.updatePost.title).toEqual('Bye, World!'); - expect(updateResponse.data.updatePost.version).toEqual(2); -}); - -test('failed updatePost mutation with wrong version', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Update" }) { - id - title - createdAt - updatedAt - version - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Update'); - expect(createResponse.data.createPost.version).toEqual(1); - const updateResponse = await GRAPHQL_CLIENT.query( - `mutation { - updatePost(input: { - id: "${createResponse.data.createPost.id}", - title: "Bye, World!", - expectedVersion: 3 - }) { - id - title - version - } - }`, - {}, - ); - expect(updateResponse.errors.length).toEqual(1); - expect((updateResponse.errors[0] as any).data).toBeNull(); - expect((updateResponse.errors[0] as any).errorType).toEqual('DynamoDB:ConditionalCheckFailedException'); -}); - -test('deletePost mutation', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Delete" }) { - id - title - version - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Delete'); - expect(createResponse.data.createPost.version).toBeDefined(); - const deleteResponse = await GRAPHQL_CLIENT.query( - `mutation { - deletePost(input: { id: "${createResponse.data.createPost.id}", expectedVersion: ${createResponse.data.createPost.version} }) { - id - title - version - } - }`, - {}, - ); - expect(deleteResponse.data.deletePost.title).toEqual('Test Delete'); - expect(deleteResponse.data.deletePost.version).toEqual(createResponse.data.createPost.version); -}); - -test('deletePost mutation with wrong version', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Delete" }) { - id - title - version - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Delete'); - expect(createResponse.data.createPost.version).toBeDefined(); - const deleteResponse = await GRAPHQL_CLIENT.query( - `mutation { - deletePost(input: { id: "${createResponse.data.createPost.id}", expectedVersion: 3 }) { - id - title - version - } - }`, - {}, - ); - expect(deleteResponse.errors.length).toEqual(1); - expect((deleteResponse.errors[0] as any).data).toBeNull(); - expect((deleteResponse.errors[0] as any).errorType).toEqual('DynamoDB:ConditionalCheckFailedException'); -}); diff --git a/packages/amplify-util-mock/src/__e2e_v2__/function-transformer.e2e.test.ts b/packages/amplify-util-mock/src/__e2e_v2__/function-transformer.e2e.test.ts deleted file mode 100644 index c518dbdd99..0000000000 --- a/packages/amplify-util-mock/src/__e2e_v2__/function-transformer.e2e.test.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { AmplifyAppSyncSimulator } from '@aws-amplify/amplify-appsync-simulator'; -import { deploy, logDebug, GraphQLClient, defaultTransformParams, transformAndSynth } from '../__e2e__/utils'; - -jest.setTimeout(2000000); - -const ECHO_FUNCTION_NAME = 'echoFunction'; -const HELLO_FUNCTION_NAME = 'hello'; - -let GRAPHQL_CLIENT: GraphQLClient; -let server: AmplifyAppSyncSimulator; - -describe('@function transformer', () => { - beforeAll(async () => { - const validSchema = ` - type Query { - echo(msg: String!): Context @function(name: "${ECHO_FUNCTION_NAME}") - duplicate(msg: String!): Context @function(name: "${ECHO_FUNCTION_NAME}") - pipeline(msg: String!): String @function(name: "${ECHO_FUNCTION_NAME}") @function(name: "${HELLO_FUNCTION_NAME}") - pipelineReverse(msg: String!): Context @function(name: "${HELLO_FUNCTION_NAME}") @function(name: "${ECHO_FUNCTION_NAME}") - } - - type Context { - arguments: Arguments - typeName: String - fieldName: String - } - - type Arguments { - msg: String! - }`; - try { - const out = transformAndSynth({ - ...defaultTransformParams, - schema: validSchema, - }); - const result = await deploy(out); - server = result.simulator; - - const endpoint = server.url + '/graphql'; - logDebug(`Using graphql url: ${endpoint}`); - - const apiKey = result.config.appSync.apiKey; - GRAPHQL_CLIENT = new GraphQLClient(endpoint, { 'x-api-key': apiKey }); - } catch (e) { - logDebug(e); - console.warn(`Could not setup function: ${e}`); - } - }); - - afterAll(async () => { - try { - if (server) { - server.stop(); - } - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } - }); - - /** - * Test queries below - */ - test('simple echo function', async () => { - const response = await GRAPHQL_CLIENT.query( - `query { - echo(msg: "Hello") { - arguments { - msg - } - typeName - fieldName - } - }`, - {}, - ); - - logDebug(JSON.stringify(response, null, 4)); - expect(response.data.echo.arguments.msg).toEqual('Hello'); - expect(response.data.echo.typeName).toEqual('Query'); - expect(response.data.echo.fieldName).toEqual('echo'); - }); - - test('simple duplicate function', async () => { - const response = await GRAPHQL_CLIENT.query( - `query { - duplicate(msg: "Hello") { - arguments { - msg - } - typeName - fieldName - } - }`, - {}, - ); - logDebug(JSON.stringify(response, null, 4)); - expect(response.data.duplicate.arguments.msg).toEqual('Hello'); - expect(response.data.duplicate.typeName).toEqual('Query'); - expect(response.data.duplicate.fieldName).toEqual('duplicate'); - }); - - test('pipeline of @function(s)', async () => { - const response = await GRAPHQL_CLIENT.query( - `query { - pipeline(msg: "IGNORED") - }`, - {}, - ); - logDebug(JSON.stringify(response, null, 4)); - expect(response.data.pipeline).toEqual('Hello, world!'); - }); - - test('pipelineReverse of @function(s)', async () => { - const response = await GRAPHQL_CLIENT.query( - `query { - pipelineReverse(msg: "Hello") { - arguments { - msg - } - typeName - fieldName - } - }`, - {}, - ); - logDebug(JSON.stringify(response, null, 4)); - expect(response.data.pipelineReverse.arguments.msg).toEqual('Hello'); - expect(response.data.pipelineReverse.typeName).toEqual('Query'); - expect(response.data.pipelineReverse.fieldName).toEqual('pipelineReverse'); - }); -}); diff --git a/packages/amplify-util-mock/src/__e2e_v2__/index-transformer.e2e.test.ts b/packages/amplify-util-mock/src/__e2e_v2__/index-transformer.e2e.test.ts deleted file mode 100644 index a3a2842728..0000000000 --- a/packages/amplify-util-mock/src/__e2e_v2__/index-transformer.e2e.test.ts +++ /dev/null @@ -1,742 +0,0 @@ -import { AmplifyAppSyncSimulator } from '@aws-amplify/amplify-appsync-simulator'; -import { deploy, launchDDBLocal, logDebug, terminateDDB, GraphQLClient, defaultTransformParams, transformAndSynth } from '../__e2e__/utils'; - -jest.setTimeout(2000000); - -let GRAPHQL_ENDPOINT: string; -let GRAPHQL_CLIENT: GraphQLClient; -let ddbEmulator = null; -let dbPath = null; -let server: AmplifyAppSyncSimulator; - -describe('@index transformer', () => { - beforeAll(async () => { - const validSchema = ` - type Order @model @auth(rules: [{ allow: public }]) { - customerEmail: String! @primaryKey(sortKeyFields: ["createdAt"]) - createdAt: String! - orderId: ID! - } - - type Customer @model @auth(rules: [{ allow: public }]) { - email: String! @primaryKey - addresslist: [String] - username: String - } - - type Item @model @auth(rules: [{ allow: public }]) { - orderId: ID! @primaryKey(sortKeyFields: ["status", "createdAt"]) - status: Status! @index(name: "ByStatus", queryField: "itemsByStatus", sortKeyFields: ["createdAt"]) - createdAt: AWSDateTime! @index(name: "ByCreatedAt", queryField: "itemsByCreatedAt", sortKeyFields: ["status"]) - name: String! - } - - enum Status { - DELIVERED - IN_TRANSIT - PENDING - UNKNOWN - } - - type ShippingUpdate @model @auth(rules: [{ allow: public }]) { - id: ID! - orderId: ID @index(name: "ByOrderItemStatus", sortKeyFields: ["itemId", "status"], queryField: "shippingUpdates") - itemId: ID - status: Status - name: String - } - - type TypeWithLSI @model @auth(rules: [{ allow: public }]) { - id: ID! @primaryKey(sortKeyFields: ["updatedAt"]) - @index(name: "BySpending" , sortKeyFields: ["totalSpending"]) - @index(name: "ByAttendance", sortKeyFields: ["totalAttendance"]) - totalSpending: Int! - totalAttendance: Int! - createdAt: AWSDateTime - updatedAt: AWSDateTime! - }`; - - const out = transformAndSynth({ - schema: validSchema, - ...defaultTransformParams, - }); - let ddbClient; - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - const result = await deploy(out, ddbClient); - server = result.simulator; - - GRAPHQL_ENDPOINT = server.url + '/graphql'; - logDebug(`Using graphql url: ${GRAPHQL_ENDPOINT}`); - - const apiKey = result.config.appSync.apiKey; - logDebug(apiKey); - GRAPHQL_CLIENT = new GraphQLClient(GRAPHQL_ENDPOINT, { 'x-api-key': apiKey }); - }); - - afterAll(async () => { - if (server) { - await server.stop(); - } - await terminateDDB(ddbEmulator, dbPath); - }); - - /** - * Test queries below - */ - test('next token with key', async () => { - const status = 'PENDING'; - const createdAt = '2019-06-06T00:01:01.000Z'; - - await createItem('order1', status, 'item1', '2019-01-06T00:01:01.000Z'); - await createItem('order2', status, 'item2', '2019-02-06T00:01:01.000Z'); - await createItem('order3', status, 'item3', '2019-03-06T00:01:01.000Z'); - await createItem('order4', status, 'item4', '2019-06-06T00:01:01.000Z'); - - const items = await itemsByStatus(status, { beginsWith: '2019' }, 2); - expect(items.data).toBeDefined(); - const itemsNextToken = items.data.itemsByStatus.nextToken; - expect(itemsNextToken).toBeDefined(); - - expect(items.data.itemsByStatus.items).toHaveLength(2); - expect(items.data.itemsByStatus.items).toEqual( - expect.arrayContaining([ - expect.objectContaining({ orderId: 'order1', name: 'item1' }), - expect.objectContaining({ orderId: 'order2', name: 'item2' }), - ]), - ); - - const items2 = await itemsByStatus(status, { beginsWith: '2019' }, 2, itemsNextToken); - expect(items2.data).toBeDefined(); - expect(items2.data.itemsByStatus.items).toHaveLength(2); - expect(items2.data.itemsByStatus.items).toEqual( - expect.arrayContaining([ - expect.objectContaining({ orderId: 'order3', name: 'item3' }), - expect.objectContaining({ orderId: 'order4', name: 'item4' }), - ]), - ); - - await deleteItem('order1', status, createdAt); - await deleteItem('order2', status, createdAt); - await deleteItem('order3', status, createdAt); - await deleteItem('order4', status, createdAt); - }); - - test('getX with a two part primary key.', async () => { - const order1 = await createOrder('test@gmail.com', '1'); - const getOrder1 = await getOrder('test@gmail.com', order1.data.createOrder.createdAt); - expect(getOrder1.data.getOrder.orderId).toEqual('1'); - }); - - test('updateX with a two part primary key.', async () => { - const order2 = await createOrder('test3@gmail.com', '2'); - let getOrder2 = await getOrder('test3@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder.orderId).toEqual('2'); - const updateOrder2 = await updateOrder('test3@gmail.com', order2.data.createOrder.createdAt, '3'); - expect(updateOrder2.data.updateOrder.orderId).toEqual('3'); - getOrder2 = await getOrder('test3@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder.orderId).toEqual('3'); - }); - - test('deleteX with a two part primary key.', async () => { - const order2 = await createOrder('test2@gmail.com', '2'); - let getOrder2 = await getOrder('test2@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder.orderId).toEqual('2'); - const delOrder2 = await deleteOrder('test2@gmail.com', order2.data.createOrder.createdAt); - expect(delOrder2.data.deleteOrder.orderId).toEqual('2'); - getOrder2 = await getOrder('test2@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder).toBeNull(); - }); - - test('getX with a three part primary key', async () => { - const item1 = await createItem('1', 'PENDING', 'item1'); - const getItem1 = await getItem('1', 'PENDING', item1.data.createItem.createdAt); - expect(getItem1.data.getItem.orderId).toEqual('1'); - expect(getItem1.data.getItem.status).toEqual('PENDING'); - }); - - test('updateX with a three part primary key.', async () => { - const item2 = await createItem('2', 'PENDING', 'item2'); - let getItem2 = await getItem('2', 'PENDING', item2.data.createItem.createdAt); - expect(getItem2.data.getItem.orderId).toEqual('2'); - const updateItem2 = await updateItem('2', 'PENDING', item2.data.createItem.createdAt, 'item2.1'); - expect(updateItem2.data.updateItem.name).toEqual('item2.1'); - getItem2 = await getItem('2', 'PENDING', item2.data.createItem.createdAt); - expect(getItem2.data.getItem.name).toEqual('item2.1'); - }); - - test('deleteX with a three part primary key.', async () => { - const item3 = await createItem('3', 'IN_TRANSIT', 'item3'); - let getItem3 = await getItem('3', 'IN_TRANSIT', item3.data.createItem.createdAt); - expect(getItem3.data.getItem.name).toEqual('item3'); - const delItem3 = await deleteItem('3', 'IN_TRANSIT', item3.data.createItem.createdAt); - expect(delItem3.data.deleteItem.name).toEqual('item3'); - getItem3 = await getItem('3', 'IN_TRANSIT', item3.data.createItem.createdAt); - expect(getItem3.data.getItem).toBeNull(); - }); - - test('listX with three part primary key.', async () => { - const hashKey = 'TEST_LIST_ID'; - await createItem(hashKey, 'IN_TRANSIT', 'list1', '2018-01-01T00:01:01.000Z'); - await createItem(hashKey, 'PENDING', 'list2', '2018-06-01T00:01:01.000Z'); - await createItem(hashKey, 'PENDING', 'item3', '2018-09-01T00:01:01.000Z'); - let items = await listItem(undefined); - expect(items.data.listItems.items.length).toBeGreaterThan(0); - items = await listItem(hashKey); - expect(items.data.listItems.items).toHaveLength(3); - items = await listItem(hashKey, { beginsWith: { status: 'PENDING' } }); - expect(items.data.listItems.items).toHaveLength(2); - items = await listItem(hashKey, { beginsWith: { status: 'IN_TRANSIT' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { - beginsWith: { status: 'PENDING', createdAt: '2018-09' }, - }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { - eq: { status: 'PENDING', createdAt: '2018-09-01T00:01:01.000Z' }, - }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { - between: [ - { status: 'PENDING', createdAt: '2018-08-01' }, - { status: 'PENDING', createdAt: '2018-10-01' }, - ], - }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { - gt: { status: 'PENDING', createdAt: '2018-08-1' }, - }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { - ge: { status: 'PENDING', createdAt: '2018-09-01T00:01:01.000Z' }, - }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { - lt: { status: 'IN_TRANSIT', createdAt: '2018-01-02' }, - }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { - le: { status: 'IN_TRANSIT', createdAt: '2018-01-01T00:01:01.000Z' }, - }); - expect(items.data.listItems.items).toHaveLength(1); - await deleteItem(hashKey, 'IN_TRANSIT', '2018-01-01T00:01:01.000Z'); - await deleteItem(hashKey, 'PENDING', '2018-06-01T00:01:01.000Z'); - await deleteItem(hashKey, 'PENDING', '2018-09-01T00:01:01.000Z'); - }); - - test('query with three part secondary key.', async () => { - const hashKey = 'UNKNOWN'; - await createItem('order1', 'UNKNOWN', 'list1', '2018-01-01T00:01:01.000Z'); - await createItem('order2', 'UNKNOWN', 'list2', '2018-06-01T00:01:01.000Z'); - await createItem('order3', 'UNKNOWN', 'item3', '2018-09-01T00:01:01.000Z'); - let items = await itemsByStatus(undefined); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - items = await itemsByStatus(hashKey); - expect(items.data.itemsByStatus.items).toHaveLength(3); - items = await itemsByStatus(hashKey, { beginsWith: '2018-09' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { eq: '2018-09-01T00:01:01.000Z' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { - between: ['2018-08-01', '2018-10-01'], - }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { gt: '2018-08-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { ge: '2018-09-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { lt: '2018-07-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(2); - items = await itemsByStatus(hashKey, { le: '2018-06-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(undefined, { le: '2018-09-01' }); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - await deleteItem('order1', hashKey, '2018-01-01T00:01:01.000Z'); - await deleteItem('order2', hashKey, '2018-06-01T00:01:01.000Z'); - await deleteItem('order3', hashKey, '2018-09-01T00:01:01.000Z'); - }); - - test('query with three part secondary key, where sort key is an enum.', async () => { - const hashKey = '2018-06-01T00:01:01.000Z'; - const sortKey = 'UNKNOWN'; - await createItem('order1', sortKey, 'list1', '2018-01-01T00:01:01.000Z'); - await createItem('order2', sortKey, 'list2', hashKey); - await createItem('order3', sortKey, 'item3', '2018-09-01T00:01:01.000Z'); - let items = await itemsByCreatedAt(undefined); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - items = await itemsByCreatedAt(hashKey); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { beginsWith: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { eq: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { between: [sortKey, sortKey] }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { gt: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(0); - items = await itemsByCreatedAt(hashKey, { ge: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { lt: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(0); - items = await itemsByCreatedAt(hashKey, { le: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(undefined, { le: sortKey }); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - await deleteItem('order1', sortKey, '2018-01-01T00:01:01.000Z'); - await deleteItem('order2', sortKey, hashKey); - await deleteItem('order3', sortKey, '2018-09-01T00:01:01.000Z'); - }); - - test('update mutation validation with three part secondary key.', async () => { - const createResponseMissingLastSortKey = await createShippingUpdate({ orderId: '1sttry', itemId: 'item1', name: '42' }); - expect(createResponseMissingLastSortKey.data.createShippingUpdate).toBeNull(); - expect(createResponseMissingLastSortKey.errors).toHaveLength(1); - - const createResponseMissingFirstSortKey = await createShippingUpdate({ orderId: '2ndtry', status: 'PENDING', name: '43?' }); - expect(createResponseMissingFirstSortKey.data.createShippingUpdate).toBeNull(); - expect(createResponseMissingFirstSortKey.errors).toHaveLength(1); - - await createShippingUpdate({ orderId: 'order1', itemId: 'item1', status: 'PENDING', name: 'name1' }); - const items = await getShippingUpdates('order1'); - expect(items.data.shippingUpdates.items).toHaveLength(1); - const item = items.data.shippingUpdates.items[0]; - expect(item.name).toEqual('name1'); - - const itemsWithFilter = await getShippingUpdatesWithNameFilter('order1', 'name1'); - expect(itemsWithFilter.data.shippingUpdates.items).toHaveLength(1); - const itemWithFilter = itemsWithFilter.data.shippingUpdates.items[0]; - expect(itemWithFilter.name).toEqual('name1'); - - const itemsWithUnknownFilter = await getShippingUpdatesWithNameFilter('order1', 'unknownname'); - expect(itemsWithUnknownFilter.data.shippingUpdates.items).toHaveLength(0); - - const updateResponseMissingLastSortKey = await updateShippingUpdate({ - id: item.id, - orderId: 'order1', - itemId: 'item1', - name: 'name2', - }); - expect(updateResponseMissingLastSortKey.data.updateShippingUpdate).toBeNull(); - expect(updateResponseMissingLastSortKey.errors).toHaveLength(1); - const updateResponseMissingFirstSortKey = await updateShippingUpdate({ - id: item.id, - orderId: 'order1', - status: 'PENDING', - name: 'name3', - }); - expect(updateResponseMissingFirstSortKey.data.updateShippingUpdate).toBeNull(); - expect(updateResponseMissingFirstSortKey.errors).toHaveLength(1); - const updateResponseMissingAllSortKeys = await updateShippingUpdate({ - id: item.id, - orderId: 'order1', - name: 'testing', - }); - expect(updateResponseMissingAllSortKeys.data.updateShippingUpdate.name).toEqual('testing'); - const updateResponseMissingNoKeys = await updateShippingUpdate({ - id: item.id, - orderId: 'order1', - itemId: 'item1', - status: 'PENDING', - name: 'testing2', - }); - expect(updateResponseMissingNoKeys.data.updateShippingUpdate.name).toEqual('testing2'); - }); - - test('Customer Create with list member and secondary key', async () => { - await createCustomer('customer1@email.com', ['thing1', 'thing2'], 'customerusr1'); - const getCustomer1 = await getCustomer('customer1@email.com'); - expect(getCustomer1.data.getCustomer.addresslist).toEqual(['thing1', 'thing2']); - }); - - test('cannot overwrite customer record with custom primary key', async () => { - await createCustomer('customer42@email.com', ['thing1', 'thing2'], 'customerusr42'); - const response = await createCustomer('customer42@email.com', ['thing2'], 'customerusr43'); - expect(response.errors).toBeDefined(); - expect(response.errors[0]).toEqual( - expect.objectContaining({ - message: 'The conditional request failed', - errorType: 'DynamoDB:ConditionalCheckFailedException', - }), - ); - }); - - test('Customer Mutation with list member', async () => { - await updateCustomer('customer1@email.com', ['thing3', 'thing4'], 'new_customerusr1'); - const getCustomer1 = await getCustomer('customer1@email.com'); - expect(getCustomer1.data.getCustomer.addresslist).toEqual(['thing3', 'thing4']); - }); -}); - -async function createCustomer(email: string, addresslist: string[], username: string) { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateCustomer($input: CreateCustomerInput!) { - createCustomer(input: $input) { - email - addresslist - username - } - }`, - { - input: { email, addresslist, username }, - }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function updateCustomer(email: string, addresslist: string[], username: string) { - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateCustomer($input: UpdateCustomerInput!) { - updateCustomer(input: $input) { - email - addresslist - username - } - }`, - { - input: { email, addresslist, username }, - }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function getCustomer(email: string) { - const result = await GRAPHQL_CLIENT.query( - `query GetCustomer($email: String!) { - getCustomer(email: $email) { - email - addresslist - username - } - }`, - { - email, - }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function createOrder(customerEmail: string, orderId: string) { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateOrder($input: CreateOrderInput!) { - createOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, orderId, createdAt: new Date().toISOString() }, - }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function updateOrder(customerEmail: string, createdAt: string, orderId: string) { - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateOrder($input: UpdateOrderInput!) { - updateOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, orderId, createdAt }, - }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function deleteOrder(customerEmail: string, createdAt: string) { - const result = await GRAPHQL_CLIENT.query( - `mutation DeleteOrder($input: DeleteOrderInput!) { - deleteOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, createdAt }, - }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function getOrder(customerEmail: string, createdAt: string) { - const result = await GRAPHQL_CLIENT.query( - `query GetOrder($customerEmail: String!, $createdAt: String!) { - getOrder(customerEmail: $customerEmail, createdAt: $createdAt) { - customerEmail - orderId - createdAt - } - }`, - { customerEmail, createdAt }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function createItem(orderId: string, status: string, name: string, createdAt: string = new Date().toISOString()) { - const input = { status, orderId, name, createdAt }; - const result = await GRAPHQL_CLIENT.query( - `mutation CreateItem($input: CreateItemInput!) { - createItem(input: $input) { - orderId - status - createdAt - name - } - }`, - { - input, - }, - ); - logDebug(`Running create: ${JSON.stringify(input)}`); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function updateItem(orderId: string, status: string, createdAt: string, name: string) { - const input = { status, orderId, createdAt, name }; - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateItem($input: UpdateItemInput!) { - updateItem(input: $input) { - orderId - status - createdAt - name - } - }`, - { - input, - }, - ); - logDebug(`Running create: ${JSON.stringify(input)}`); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function deleteItem(orderId: string, status: string, createdAt: string) { - const input = { orderId, status, createdAt }; - const result = await GRAPHQL_CLIENT.query( - `mutation DeleteItem($input: DeleteItemInput!) { - deleteItem(input: $input) { - orderId - status - createdAt - name - } - }`, - { - input, - }, - ); - logDebug(`Running delete: ${JSON.stringify(input)}`); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function getItem(orderId: string, status: string, createdAt: string) { - const result = await GRAPHQL_CLIENT.query( - `query GetItem($orderId: ID!, $status: Status!, $createdAt: AWSDateTime!) { - getItem(orderId: $orderId, status: $status, createdAt: $createdAt) { - orderId - status - createdAt - name - } - }`, - { orderId, status, createdAt }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -interface StringKeyConditionInput { - eq?: string; - gt?: string; - ge?: string; - lt?: string; - le?: string; - between?: string[]; - beginsWith?: string; -} - -interface ItemCompositeKeyConditionInput { - eq?: ItemCompositeKeyInput; - gt?: ItemCompositeKeyInput; - ge?: ItemCompositeKeyInput; - lt?: ItemCompositeKeyInput; - le?: ItemCompositeKeyInput; - between?: ItemCompositeKeyInput[]; - beginsWith?: ItemCompositeKeyInput; -} - -interface ItemCompositeKeyInput { - status?: string; - createdAt?: string; -} - -async function listItem(orderId?: string, statusCreatedAt?: ItemCompositeKeyConditionInput, limit?: number, nextToken?: string) { - const result = await GRAPHQL_CLIENT.query( - `query ListItems($orderId: ID, $statusCreatedAt: ModelItemPrimaryCompositeKeyConditionInput, $limit: Int, $nextToken: String) { - listItems(orderId: $orderId, statusCreatedAt: $statusCreatedAt, limit: $limit, nextToken: $nextToken) { - items { - orderId - status - createdAt - name - } - nextToken - } - }`, - { orderId, statusCreatedAt, limit, nextToken }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function itemsByStatus(status: string, createdAt?: StringKeyConditionInput, limit?: number, nextToken?: string) { - const result = await GRAPHQL_CLIENT.query( - `query ListByStatus($status: Status!, $createdAt: ModelStringKeyConditionInput, $limit: Int, $nextToken: String) { - itemsByStatus(status: $status, createdAt: $createdAt, limit: $limit, nextToken: $nextToken) { - items { - orderId - status - createdAt - name - } - nextToken - } - }`, - { status, createdAt, limit, nextToken }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function itemsByCreatedAt(createdAt: string, status?: StringKeyConditionInput, limit?: number, nextToken?: string) { - const result = await GRAPHQL_CLIENT.query( - `query ListByCreatedAt($createdAt: AWSDateTime!, $status: ModelStringKeyConditionInput, $limit: Int, $nextToken: String) { - itemsByCreatedAt(createdAt: $createdAt, status: $status, limit: $limit, nextToken: $nextToken) { - items { - orderId - status - createdAt - name - } - nextToken - } - }`, - { createdAt, status, limit, nextToken }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -interface CreateShippingInput { - id?: string; - orderId?: string; - status?: string; - itemId?: string; - name?: string; -} - -async function createShippingUpdate(input: CreateShippingInput) { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateShippingUpdate($input: CreateShippingUpdateInput!) { - createShippingUpdate(input: $input) { - orderId - status - itemId - name - id - } - }`, - { - input, - }, - ); - logDebug(`Running create: ${JSON.stringify(input)}`); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -interface UpdateShippingInput { - id: string; - orderId?: string; - status?: string; - itemId?: string; - name?: string; -} - -async function updateShippingUpdate(input: UpdateShippingInput) { - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateShippingUpdate($input: UpdateShippingUpdateInput!) { - updateShippingUpdate(input: $input) { - orderId - status - itemId - name - id - } - }`, - { - input, - }, - ); - logDebug(`Running update: ${JSON.stringify(input)}`); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function getShippingUpdates(orderId: string) { - const result = await GRAPHQL_CLIENT.query( - `query GetShippingUpdates($orderId: ID!) { - shippingUpdates(orderId: $orderId) { - items { - id - orderId - status - itemId - name - } - nextToken - } - }`, - { orderId }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} - -async function getShippingUpdatesWithNameFilter(orderId: string, name: string) { - const result = await GRAPHQL_CLIENT.query( - `query GetShippingUpdates($orderId: ID!, $name: String) { - shippingUpdates(orderId: $orderId, filter: { name: { eq: $name }}) { - items { - id - orderId - status - itemId - name - } - nextToken - } - }`, - { orderId, name }, - ); - logDebug(JSON.stringify(result, null, 4)); - return result; -} diff --git a/packages/amplify-util-mock/src/__e2e_v2__/model-relational-transformer.e2e.test.ts b/packages/amplify-util-mock/src/__e2e_v2__/model-relational-transformer.e2e.test.ts deleted file mode 100644 index c2d27865c9..0000000000 --- a/packages/amplify-util-mock/src/__e2e_v2__/model-relational-transformer.e2e.test.ts +++ /dev/null @@ -1,231 +0,0 @@ -import { AmplifyAppSyncSimulator } from '@aws-amplify/amplify-appsync-simulator'; -import { deploy, launchDDBLocal, terminateDDB, logDebug, GraphQLClient, defaultTransformParams, transformAndSynth } from '../__e2e__/utils'; - -let GRAPHQL_CLIENT: GraphQLClient; -let GRAPHQL_ENDPOINT: string; -let ddbEmulator = null; -let dbPath = null; -let server: AmplifyAppSyncSimulator; - -jest.setTimeout(20000); - -describe('@model with relational transformer', () => { - beforeAll(async () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: public }]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - comments: [Comment] @hasMany(indexName: "byPost", fields: ["id"], limit: 50) - sortedComments: [SortedComment] @hasMany(indexName: "SortedPostComments") - } - - type Comment @model @auth(rules: [{ allow: public }]) { - id: ID! - content: String! - postId: ID @index(name: "byPost") - post: Post @belongsTo(fields: ["postId"]) - } - - type SortedComment @model @auth(rules: [{ allow: public }]) { - id: ID! - content: String! - when: String! - postId: ID @index(name: "SortedPostComments", sortKeyFields: ["when"]) - post: Post @hasOne - }`; - - try { - const out = transformAndSynth({ - ...defaultTransformParams, - schema: validSchema, - transformParameters: { - ...defaultTransformParams.transformParameters, - respectPrimaryKeyAttributesOnConnectionField: false, - }, - }); - - let ddbClient; - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - const result = await deploy(out, ddbClient); - server = result.simulator; - - GRAPHQL_ENDPOINT = server.url + '/graphql'; - logDebug(`Using graphql url: ${GRAPHQL_ENDPOINT}`); - - const apiKey = result.config.appSync.apiKey; - logDebug(apiKey); - GRAPHQL_CLIENT = new GraphQLClient(GRAPHQL_ENDPOINT, { - 'x-api-key': apiKey, - }); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } - }); - - afterAll(async () => { - try { - if (server) { - await server.stop(); - } - await terminateDDB(ddbEmulator, dbPath); - } catch (e) { - logDebug(e); - expect(true).toEqual(false); - } - }); - - /** - * Test queries below - */ - - test('queryPost query', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Query" }) { - id - title - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Query'); - const createCommentResponse = await GRAPHQL_CLIENT.query( - `mutation { - createComment(input: { content: "A comment!", postId: "${createResponse.data.createPost.id}" }) { - id - content - post { - id - title - } - } - }`, - {}, - ); - expect(createCommentResponse.data.createComment.id).toBeDefined(); - expect(createCommentResponse.data.createComment.content).toEqual('A comment!'); - expect(createCommentResponse.data.createComment.post.id).toEqual(createResponse.data.createPost.id); - expect(createCommentResponse.data.createComment.post.title).toEqual(createResponse.data.createPost.title); - const queryResponse = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - comments { - items { - id - content - } - } - } - }`, - {}, - ); - expect(queryResponse.data.getPost).toBeDefined(); - const items = queryResponse.data.getPost.comments.items; - expect(items.length).toEqual(1); - expect(items[0].id).toEqual(createCommentResponse.data.createComment.id); - }); - - test('create comment without a post and then querying the comment.', async () => { - const comment1 = 'a comment and a date! - 1'; - - try { - const createCommentResponse1 = await GRAPHQL_CLIENT.query( - `mutation { - createComment(input: { content: "${comment1}" }) { - id - content - post { - id - title - } - } - }`, - {}, - ); - expect(createCommentResponse1.data.createComment.id).toBeDefined(); - expect(createCommentResponse1.data.createComment.post).toBeNull(); - - expect(createCommentResponse1.data.createComment.content).toEqual(comment1); - const queryResponseDesc = await GRAPHQL_CLIENT.query( - `query { - getComment(id: "${createCommentResponse1.data.createComment.id}") { - id - content - post { - id - } - } - }`, - {}, - ); - expect(queryResponseDesc.data.getComment).toBeDefined(); - expect(queryResponseDesc.data.getComment.post).toBeNull(); - } catch (e) { - console.error(e); - expect(e).toBeUndefined(); - } - }); - - test('default limit is 50', async () => { - const postID = 'e2eConnectionPost'; - const postTitle = 'samplePost'; - const createPost = await GRAPHQL_CLIENT.query( - `mutation CreatePost { - createPost(input: {title: "${postTitle}", id: "${postID}"}) { - id - title - } - } - `, - {}, - ); - expect(createPost.data.createPost).toBeDefined(); - expect(createPost.data.createPost.id).toEqual(postID); - expect(createPost.data.createPost.title).toEqual(postTitle); - - for (let i = 0; i < 51; i++) { - await GRAPHQL_CLIENT.query( - ` - mutation CreateComment { - createComment(input: {postId: "${postID}", content: "content_${i}"}) { - content - id - post { - title - } - } - } - `, - {}, - ); - } - - const getPost = await GRAPHQL_CLIENT.query( - ` - query GetPost($id: ID!) { - getPost(id: $id) { - id - title - createdAt - updatedAt - comments { - items { - id - content - } - nextToken - } - } - }`, - { id: postID }, - ); - - expect(getPost.data.getPost.comments.items.length).toEqual(50); - }); -}); diff --git a/packages/amplify-util-mock/src/__e2e_v2__/model-relational-with-key-transformer.e2e.test.ts b/packages/amplify-util-mock/src/__e2e_v2__/model-relational-with-key-transformer.e2e.test.ts deleted file mode 100644 index 3712d94f24..0000000000 --- a/packages/amplify-util-mock/src/__e2e_v2__/model-relational-with-key-transformer.e2e.test.ts +++ /dev/null @@ -1,353 +0,0 @@ -import { AmplifyAppSyncSimulator } from '@aws-amplify/amplify-appsync-simulator'; -import { deploy, launchDDBLocal, terminateDDB, logDebug, GraphQLClient, defaultTransformParams, transformAndSynth } from '../__e2e__/utils'; - -let GRAPHQL_CLIENT: GraphQLClient; -let GRAPHQL_ENDPOINT: string; -let ddbEmulator = null; -let dbPath = null; -let server: AmplifyAppSyncSimulator; - -jest.setTimeout(20000); - -describe('@model with relational transformers', () => { - beforeAll(async () => { - const validSchema = ` - type AProject @model(subscriptions: null) @auth(rules: [{ allow: public }]) { - projectId: String! @primaryKey - name: String - team: ATeam @hasOne - } - - type ATeam @model(subscriptions: null) @auth(rules: [{ allow: public }]) { - teamId: String! @primaryKey - name: String - } - - type BProject @model(subscriptions: null) @auth(rules: [{ allow: public }]) { - projectId: String! @primaryKey - name: String - teams: [BTeam] @hasMany - } - - type BTeam @model(subscriptions: null) @auth(rules: [{ allow: public }]) { - teamId: String! @primaryKey - name: String - } - - type CProject @model(subscriptions: null) @auth(rules: [{ allow: public }]) { - projectId: ID! @primaryKey - name: String - team: CTeam @hasOne - } - - type CTeam @model(subscriptions: null) @auth(rules: [{ allow: public }]) { - teamId: ID! @primaryKey - name: String - project: CProject @hasOne - } - - type DProject @model(subscriptions: null) @auth(rules: [{ allow: public }]) { - projectId: ID! @primaryKey - name: String - teams: [DTeam] @hasMany(indexName: "byDTeam") - } - - type DTeam @model(subscriptions: null) @auth(rules: [{ allow: public }]) { - teamId: ID! @primaryKey - name: String - dTeamProjectId: ID @index(name: "byDTeam") - project: DProject @belongsTo(fields: ["dTeamProjectId"]) - }`; - try { - const out = transformAndSynth({ - ...defaultTransformParams, - schema: validSchema, - transformParameters: { - ...defaultTransformParams.transformParameters, - respectPrimaryKeyAttributesOnConnectionField: false, - }, - }); - - let ddbClient; - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - const result = await deploy(out, ddbClient); - server = result.simulator; - - GRAPHQL_ENDPOINT = `${server.url}/graphql`; - logDebug(`Using graphql url: ${GRAPHQL_ENDPOINT}`); - - const { apiKey } = result.config.appSync; - logDebug(apiKey); - GRAPHQL_CLIENT = new GraphQLClient(GRAPHQL_ENDPOINT, { - 'x-api-key': apiKey, - }); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } - }); - - afterAll(async () => { - try { - if (server) { - await server.stop(); - } - await terminateDDB(ddbEmulator, dbPath); - } catch (e) { - logDebug(e); - expect(true).toEqual(false); - } - }); - - /** - * Test queries below - */ - - test('Unnamed connection 1 way navigation, with @primaryKey directive 1:1', async () => { - await GRAPHQL_CLIENT.query( - ` - mutation CreateATeam { - createATeam(input: {teamId: "T1", name: "Team 1"}) { - teamId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateAProject { - createAProject(input: {projectId: "P1", name: "P1", aProjectTeamId: "T1"}) { - projectId - name - } - } - `, - {}, - ); - - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query ListAProjects { - listAProjects { - items { - projectId - name - team { - teamId - name - } - } - } - } - `, - {}, - ); - expect(queryResponse.data.listAProjects).toBeDefined(); - const { items } = queryResponse.data.listAProjects; - expect(items.length).toEqual(1); - expect(items[0].projectId).toEqual('P1'); - expect(items[0].team).toBeDefined(); - expect(items[0].team.teamId).toEqual('T1'); - }); - - test('Unnamed connection 1 way navigation, with @primaryKey directive 1:M', async () => { - await GRAPHQL_CLIENT.query( - ` - mutation CreateBProject { - createBProject(input: {projectId: "P1", name: "P1"}) { - projectId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateBTeam { - createBTeam(input: {teamId: "T1", name: "Team 1", bProjectTeamsId: "P1"}) { - teamId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateBTeam { - createBTeam(input: {teamId: "T2", name: "Team 2", bProjectTeamsId: "P1"}) { - teamId - name - } - } - `, - {}, - ); - - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query ListBProjects { - listBProjects { - items { - projectId - name - teams { - items { - teamId - name - } - } - } - } - } - `, - {}, - ); - expect(queryResponse.data.listBProjects).toBeDefined(); - const { items } = queryResponse.data.listBProjects; - expect(items.length).toEqual(1); - expect(items[0].projectId).toEqual('P1'); - expect(items[0].teams).toBeDefined(); - expect(items[0].teams.items).toBeDefined(); - expect(items[0].teams.items.length).toEqual(2); - expect(items[0].teams.items[0].teamId).toEqual('T1'); - expect(items[0].teams.items[1].teamId).toEqual('T2'); - }); - - test('Named connection 2 way navigation, with with custom @primaryKey fields 1:1', async () => { - await GRAPHQL_CLIENT.query( - ` - mutation CreateCTeam { - createCTeam(input: {teamId: "T1", name: "Team 1", cTeamProjectId: "P1"}) { - teamId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateCProject { - createCProject(input: {projectId: "P1", name: "P1", cProjectTeamId: "T1"}) { - projectId - name - } - } - `, - {}, - ); - - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query ListCProjects { - listCProjects { - items { - projectId - name - team { - teamId - name - project { - projectId - name - } - } - } - } - } - `, - {}, - ); - expect(queryResponse.data.listCProjects).toBeDefined(); - const { items } = queryResponse.data.listCProjects; - expect(items.length).toEqual(1); - expect(items[0].projectId).toEqual('P1'); - expect(items[0].team).toBeDefined(); - expect(items[0].team.teamId).toEqual('T1'); - expect(items[0].team.project).toBeDefined(); - expect(items[0].team.project.projectId).toEqual('P1'); - }); - - test('Named connection 2 way navigation, with with custom @key fields 1:M', async () => { - await GRAPHQL_CLIENT.query( - ` - mutation CreateDProject { - createDProject(input: {projectId: "P1", name: "P1"}) { - projectId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateDTeam { - createDTeam(input: {teamId: "T1", name: "Team 1", dTeamProjectId: "P1"}) { - teamId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateDTeam { - createDTeam(input: {teamId: "T2", name: "Team 2", dTeamProjectId: "P1"}) { - teamId - name - } - } - `, - {}, - ); - - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query ListDProjects { - listDProjects { - items { - projectId - name - teams { - items { - teamId - name - project { - projectId - name - } - } - } - } - } - } - `, - {}, - ); - expect(queryResponse.data.listDProjects).toBeDefined(); - const { items } = queryResponse.data.listDProjects; - expect(items.length).toEqual(1); - expect(items[0].projectId).toEqual('P1'); - expect(items[0].teams).toBeDefined(); - expect(items[0].teams.items).toBeDefined(); - expect(items[0].teams.items.length).toEqual(2); - expect(items[0].teams.items[0].teamId).toEqual('T1'); - expect(items[0].teams.items[0].project).toBeDefined(); - expect(items[0].teams.items[0].project.projectId).toEqual('P1'); - expect(items[0].teams.items[1].teamId).toEqual('T2'); - expect(items[0].teams.items[1].project).toBeDefined(); - expect(items[0].teams.items[1].project.projectId).toEqual('P1'); - }); -}); diff --git a/packages/amplify-util-mock/src/__e2e_v2__/model-transformer.e2e.test.ts b/packages/amplify-util-mock/src/__e2e_v2__/model-transformer.e2e.test.ts deleted file mode 100644 index 4cecb06624..0000000000 --- a/packages/amplify-util-mock/src/__e2e_v2__/model-transformer.e2e.test.ts +++ /dev/null @@ -1,747 +0,0 @@ -import { AmplifyAppSyncSimulator } from '@aws-amplify/amplify-appsync-simulator'; -import { deploy, launchDDBLocal, terminateDDB, logDebug, GraphQLClient, defaultTransformParams, transformAndSynth } from '../__e2e__/utils'; - -let GRAPHQL_ENDPOINT: string; -let GRAPHQL_CLIENT: GraphQLClient; -let ddbEmulator = null; -let dbPath = null; -let server: AmplifyAppSyncSimulator; - -jest.setTimeout(2000000); - -describe('@model transformer', () => { - beforeAll(async () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: public }]) { - id: ID! - title: String! - createdAt: AWSDateTime - updatedAt: AWSDateTime - metadata: PostMetadata - entityMetadata: EntityMetadata - appearsIn: [Episode!] - episode: Episode - } - - type Author @model @auth(rules: [{ allow: public }]) { - id: ID! - name: String! - postMetadata: PostMetadata - entityMetadata: EntityMetadata - } - - type EntityMetadata { - isActive: Boolean - } - - type PostMetadata { - tags: Tag - } - - type Tag { - published: Boolean - metadata: PostMetadata - } - - enum Episode { - NEWHOPE - EMPIRE - JEDI - }`; - - try { - const out = transformAndSynth({ - ...defaultTransformParams, - schema: validSchema, - }); - let ddbClient; - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - const result = await deploy(out, ddbClient); - server = result.simulator; - - GRAPHQL_ENDPOINT = server.url + '/graphql'; - logDebug(`Using graphql url: ${GRAPHQL_ENDPOINT}`); - - const apiKey = result.config.appSync.apiKey; - logDebug(apiKey); - GRAPHQL_CLIENT = new GraphQLClient(GRAPHQL_ENDPOINT, { - 'x-api-key': apiKey, - }); - } catch (e) { - logDebug('error when setting up test'); - logDebug(e); - expect(true).toEqual(false); - } - }); - - afterAll(async () => { - if (server) { - await server.stop(); - } - await terminateDDB(ddbEmulator, dbPath); - }); - - afterEach(async () => { - try { - logDebug('deleting posts'); - const response = await GRAPHQL_CLIENT.query( - ` - query { - listPosts { - items { - id - } - } - }`, - {}, - ); - const rows = response.data.listPosts.items || []; - const deletePromises = []; - rows.forEach((row) => { - deletePromises.push( - GRAPHQL_CLIENT.query( - `mutation delete { - deletePost(input: {id: "${row.id}"}) { id } - }`, - {}, - ), - ); - }); - await Promise.all(deletePromises); - } catch (e) { - logDebug(e); - } - }); - - /** - * Test queries below - */ - test('createAuthor mutation', async () => { - try { - const response = await GRAPHQL_CLIENT.query( - `mutation($input: CreateAuthorInput!) { - createAuthor(input: $input) { - id - name - entityMetadata { - isActive - } - } - }`, - { - input: { - name: 'Jeff B', - entityMetadata: { - isActive: true, - }, - }, - }, - ); - logDebug(response); - expect(response.data.createAuthor.id).toBeDefined(); - expect(response.data.createAuthor.name).toEqual('Jeff B'); - expect(response.data.createAuthor.entityMetadata).toBeDefined(); - expect(response.data.createAuthor.entityMetadata.isActive).toEqual(true); - } catch (e) { - logDebug(e); - expect(e).toBeUndefined(); - } - }); - - test('createPost mutation', async () => { - try { - const response = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - } catch (e) { - logDebug(e); - expect(e).toBeUndefined(); - } - }); - - test('query on get query with null field', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - ` - mutation { - createPost(input: { title: "Cool Post" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Cool Post'); - const postID = createResponse.data.createPost.id; - try { - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query { - getPost(id: "${postID}") { - id - title - episode - } - }`, - {}, - ); - expect(queryResponse.data.getPost.id).toEqual(postID); - expect(queryResponse.data.getPost.episode).toBeNull(); - } catch (err) { - logDebug(err); - expect(err).toBeUndefined(); - } - }); - - test('updatePost mutation', async () => { - try { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Update" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - logDebug(JSON.stringify(createResponse, null, 4)); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Update'); - const updateResponse = await GRAPHQL_CLIENT.query( - `mutation { - updatePost(input: { id: "${createResponse.data.createPost.id}", title: "Bye, World!" }) { - id - title - } - }`, - {}, - ); - logDebug(JSON.stringify(updateResponse, null, 4)); - expect(updateResponse.data.updatePost.title).toEqual('Bye, World!'); - } catch (e) { - logDebug(e); - expect(e).toBeUndefined(); - } - }); - - test('createPost and updatePost mutation with a client generated id.', async () => { - try { - const clientId = 'a-client-side-generated-id'; - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { id: "${clientId}" title: "Test Update" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - logDebug(JSON.stringify(createResponse, null, 4)); - expect(createResponse.data.createPost.id).toEqual(clientId); - expect(createResponse.data.createPost.title).toEqual('Test Update'); - const updateResponse = await GRAPHQL_CLIENT.query( - `mutation { - updatePost(input: { id: "${clientId}", title: "Bye, World!" }) { - id - title - } - }`, - {}, - ); - logDebug(JSON.stringify(updateResponse, null, 4)); - expect(updateResponse.data.updatePost.id).toEqual(clientId); - expect(updateResponse.data.updatePost.title).toEqual('Bye, World!'); - const getResponse = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${clientId}") { - id - title - } - }`, - {}, - ); - logDebug(JSON.stringify(getResponse, null, 4)); - expect(getResponse.data.getPost.id).toEqual(clientId); - expect(getResponse.data.getPost.title).toEqual('Bye, World!'); - - const deleteResponse = await GRAPHQL_CLIENT.query( - `mutation { - deletePost(input: { id: "${clientId}" }) { - id - title - } - }`, - {}, - ); - logDebug(JSON.stringify(deleteResponse, null, 4)); - expect(deleteResponse.data.deletePost.id).toEqual(clientId); - expect(deleteResponse.data.deletePost.title).toEqual('Bye, World!'); - - const getResponse2 = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${clientId}") { - id - title - } - }`, - {}, - ); - logDebug(JSON.stringify(getResponse2, null, 4)); - expect(getResponse2.data.getPost).toBeNull(); - } catch (e) { - logDebug(e); - expect(e).toBeUndefined(); - } - }); - - test('deletePost mutation', async () => { - try { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Delete" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - logDebug(JSON.stringify(createResponse, null, 4)); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Delete'); - const deleteResponse = await GRAPHQL_CLIENT.query( - `mutation { - deletePost(input: { id: "${createResponse.data.createPost.id}" }) { - id - title - } - }`, - {}, - ); - logDebug(JSON.stringify(deleteResponse, null, 4)); - expect(deleteResponse.data.deletePost.title).toEqual('Test Delete'); - const getResponse = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - } - }`, - {}, - ); - logDebug(JSON.stringify(getResponse, null, 4)); - expect(getResponse.data.getPost).toBeNull(); - } catch (e) { - logDebug(e); - expect(e).toBeUndefined(); - } - }); - - test('getPost query', async () => { - try { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Get" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeTruthy(); - expect(createResponse.data.createPost.title).toEqual('Test Get'); - const getResponse = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - } - }`, - {}, - ); - expect(getResponse.data.getPost.title).toEqual('Test Get'); - } catch (e) { - logDebug(e); - expect(e).toBeUndefined(); - } - }); - - test('listPosts query', async () => { - try { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test List" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test List'); - const listResponse = await GRAPHQL_CLIENT.query( - `query { - listPosts { - items { - id - title - } - } - }`, - {}, - ); - expect(listResponse.data.listPosts.items).toBeDefined(); - const items = listResponse.data.listPosts.items; - expect(items.length).toBeGreaterThan(0); - } catch (e) { - logDebug(e); - expect(e).toBeUndefined(); - } - }); - - test('listPosts query with filter', async () => { - try { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test List with filter" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test List with filter'); - const listWithFilterResponse = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { - title: { - contains: "List with filter" - } - }) { - items { - id - title - } - } - }`, - {}, - ); - logDebug(JSON.stringify(listWithFilterResponse, null, 4)); - expect(listWithFilterResponse.data.listPosts.items).toBeDefined(); - const items = listWithFilterResponse.data.listPosts.items; - expect(items.length).toEqual(1); - expect(items[0].title).toEqual('Test List with filter'); - } catch (e) { - logDebug(e); - expect(e).toBeUndefined(); - } - }); - - test('enum filters List', async () => { - try { - await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Appears in New Hope", appearsIn: [NEWHOPE], episode: NEWHOPE }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Appears in Jedi", appearsIn: [JEDI], episode: JEDI }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Appears in Empire", appearsIn: [EMPIRE], episode: EMPIRE }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - - await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Appears in Empire & JEDI", appearsIn: [EMPIRE, JEDI] }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - - const appearsInWithFilterResponseJedi = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { appearsIn: {eq: [JEDI]}}) { - items { - title - id - } - } - } - `, - {}, - ); - expect(appearsInWithFilterResponseJedi.data.listPosts.items).toBeDefined(); - const items = appearsInWithFilterResponseJedi.data.listPosts.items; - logDebug(items); - expect(items.length).toEqual(1); - expect(items[0].title).toEqual('Appears in Jedi'); - - const appearsInWithFilterResponseNonJedi = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { appearsIn: {ne: [JEDI]}}) { - items { - title - id - } - } - } - `, - {}, - ); - logDebug(JSON.stringify(appearsInWithFilterResponseNonJedi)); - expect(appearsInWithFilterResponseNonJedi.data.listPosts.items).toBeDefined(); - const appearsInNonJediItems = appearsInWithFilterResponseNonJedi.data.listPosts.items; - expect(appearsInNonJediItems.length).toEqual(3); - appearsInNonJediItems.forEach((item) => { - expect(['Appears in Empire & JEDI', 'Appears in New Hope', 'Appears in Empire'].includes(item.title)).toBeTruthy(); - }); - - const appearsInContainingJedi = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { appearsIn: {contains: JEDI }}) { - items { - title - id - } - } - } - `, - {}, - ); - expect(appearsInContainingJedi.data.listPosts.items).toBeDefined(); - const appearsInWithJediItems = appearsInContainingJedi.data.listPosts.items; - expect(appearsInWithJediItems.length).toEqual(2); - appearsInWithJediItems.forEach((item) => { - expect(['Appears in Empire & JEDI', 'Appears in Jedi'].includes(item.title)).toBeTruthy(); - }); - - const appearsInNotContainingJedi = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { appearsIn: {notContains: JEDI }}) { - items { - title - id - } - } - } - `, - {}, - ); - expect(appearsInNotContainingJedi.data.listPosts.items).toBeDefined(); - const appearsInWithNonJediItems = appearsInNotContainingJedi.data.listPosts.items; - expect(appearsInWithNonJediItems.length).toEqual(2); - appearsInWithNonJediItems.forEach((item) => { - expect(['Appears in New Hope', 'Appears in Empire'].includes(item.title)).toBeTruthy(); - }); - - const jediEpisode = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { episode: {eq: JEDI }}) { - items { - title - id - } - } - } - `, - {}, - ); - expect(jediEpisode.data.listPosts.items).toBeDefined(); - const jediEpisodeItems = jediEpisode.data.listPosts.items; - expect(jediEpisodeItems.length).toEqual(1); - expect(jediEpisodeItems[0].title).toEqual('Appears in Jedi'); - - const nonJediEpisode = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { episode: {ne: JEDI }}) { - items { - title - id - } - } - } - `, - {}, - ); - expect(nonJediEpisode.data.listPosts.items).toBeDefined(); - const nonJediEpisodeItems = nonJediEpisode.data.listPosts.items; - expect(nonJediEpisodeItems.length).toEqual(3); - nonJediEpisodeItems.forEach((item) => { - expect(['Appears in New Hope', 'Appears in Empire', 'Appears in Empire & JEDI'].includes(item.title)).toBeTruthy(); - }); - } catch (e) { - logDebug(e); - expect(e).toBeUndefined(); - } - }); - - test('createPost mutation with non-model types', async () => { - try { - const response = await GRAPHQL_CLIENT.query( - `mutation CreatePost($input: CreatePostInput!) { - createPost(input: $input) { - id - title - createdAt - updatedAt - metadata { - tags { - published - metadata { - tags { - published - } - } - } - } - appearsIn - } - }`, - { - input: { - title: 'Check that metadata exists', - metadata: { - tags: { - published: true, - metadata: { - tags: { - published: false, - }, - }, - }, - }, - appearsIn: ['NEWHOPE'], - }, - }, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Check that metadata exists'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.metadata).toBeDefined(); - expect(response.data.createPost.metadata.tags.published).toEqual(true); - expect(response.data.createPost.metadata.tags.metadata.tags.published).toEqual(false); - expect(response.data.createPost.appearsIn).toEqual(['NEWHOPE']); - } catch (e) { - logDebug(e); - expect(e).toBeUndefined(); - } - }); - - test('updatePost mutation with non-model types', async () => { - try { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Update" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Update'); - const updateResponse = await GRAPHQL_CLIENT.query( - `mutation UpdatePost($input: UpdatePostInput!) { - updatePost(input: $input) { - id - title - createdAt - updatedAt - metadata { - tags { - published - metadata { - tags { - published - } - } - } - } - appearsIn - } - }`, - { - input: { - id: createResponse.data.createPost.id, - title: 'Add some metadata', - metadata: { - tags: { - published: true, - metadata: { - tags: { - published: false, - }, - }, - }, - }, - appearsIn: ['NEWHOPE', 'EMPIRE'], - }, - }, - ); - expect(updateResponse.data.updatePost.title).toEqual('Add some metadata'); - expect(updateResponse.data.updatePost.metadata).toBeDefined(); - expect(updateResponse.data.updatePost.metadata.tags.published).toEqual(true); - expect(updateResponse.data.updatePost.metadata.tags.metadata.tags.published).toEqual(false); - expect(updateResponse.data.updatePost.appearsIn).toEqual(['NEWHOPE', 'EMPIRE']); - } catch (e) { - logDebug(e); - expect(e).toBeUndefined(); - } - }); -}); diff --git a/packages/amplify-util-mock/src/__e2e_v2__/searchable-transformer.e2e.test.ts b/packages/amplify-util-mock/src/__e2e_v2__/searchable-transformer.e2e.test.ts deleted file mode 100644 index 662e09e650..0000000000 --- a/packages/amplify-util-mock/src/__e2e_v2__/searchable-transformer.e2e.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { AmplifyAppSyncSimulator } from '@aws-amplify/amplify-appsync-simulator'; -import { deploy, launchDDBLocal, logDebug, GraphQLClient, terminateDDB, defaultTransformParams, transformAndSynth } from '../__e2e__/utils'; - -jest.setTimeout(2000000); - -let GRAPHQL_ENDPOINT: string; -let GRAPHQL_CLIENT: GraphQLClient; -let ddbEmulator = null; -let dbPath = null; -let server: AmplifyAppSyncSimulator; - -describe('@searchable transformer', () => { - beforeAll(async () => { - const validSchema = ` - type Todo @model @searchable { - id: ID! - }`; - - try { - const out = transformAndSynth({ - ...defaultTransformParams, - schema: validSchema, - transformParameters: { - ...defaultTransformParams.transformParameters, - sandboxModeEnabled: true, - }, - }); - - let ddbClient; - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - const result = await deploy(out, ddbClient); - server = result.simulator; - - GRAPHQL_ENDPOINT = server.url + '/graphql'; - logDebug(`Using graphql url: ${GRAPHQL_ENDPOINT}`); - - const apiKey = result.config.appSync.apiKey; - logDebug(apiKey); - GRAPHQL_CLIENT = new GraphQLClient(GRAPHQL_ENDPOINT, { - 'x-api-key': apiKey, - }); - } catch (e) { - logDebug('error when setting up test'); - logDebug(e); - expect(true).toEqual(false); - } - }); - - afterAll(async () => { - try { - if (server) { - await server.stop(); - } - - await terminateDDB(ddbEmulator, dbPath); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } - }); - - /** - * Test queries below - */ - test('@searchable allows the mock server to run', async () => { - const response = await GRAPHQL_CLIENT.query( - `query { - searchTodos { - items { - id - } - } - }`, - {}, - ); - - logDebug(JSON.stringify(response, null, 4)); - expect(response.data.searchTodos.items).toEqual([]); - }); -}); diff --git a/packages/amplify-util-mock/src/__e2e_v2__/util-method.e2e.test.ts b/packages/amplify-util-mock/src/__e2e_v2__/util-method.e2e.test.ts deleted file mode 100644 index 4871920aa5..0000000000 --- a/packages/amplify-util-mock/src/__e2e_v2__/util-method.e2e.test.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { AmplifyAppSyncSimulator } from '@aws-amplify/amplify-appsync-simulator'; -import { - deploy, - launchDDBLocal, - terminateDDB, - logDebug, - reDeploy, - GraphQLClient, - defaultTransformParams, - transformAndSynth, -} from '../__e2e__/utils'; - -let GRAPHQL_ENDPOINT: string; -let GRAPHQL_CLIENT: GraphQLClient; -let ddbEmulator = null; -let dbPath = null; -let server: AmplifyAppSyncSimulator; - -jest.setTimeout(2000000); - -const runTransformer = async (validSchema: string) => - transformAndSynth({ - ...defaultTransformParams, - schema: validSchema, - transformParameters: { - ...defaultTransformParams.transformParameters, - sandboxModeEnabled: true, - }, - }); - -let ddbClient; -const validSchema = /* GraphQL */ ` - type Post @model { - id: ID! - title: String! - } -`; - -describe('$util method', () => { - beforeAll(async () => { - try { - const out = await runTransformer(validSchema); - ({ dbPath, emulator: ddbEmulator, client: ddbClient } = await launchDDBLocal()); - const result = await deploy(out, ddbClient); - server = result.simulator; - - GRAPHQL_ENDPOINT = server.url + '/graphql'; - logDebug(`Using graphql url: ${GRAPHQL_ENDPOINT}`); - - const apiKey = result.config.appSync.apiKey; - logDebug(apiKey); - GRAPHQL_CLIENT = new GraphQLClient(GRAPHQL_ENDPOINT, { - 'x-api-key': apiKey, - }); - } catch (e) { - logDebug('error when setting up test'); - logDebug(e); - expect(true).toEqual(false); - } - }); - - afterEach(async () => { - const out = await runTransformer(validSchema); - await reDeploy(out, server, ddbClient); - }); - - afterAll(async () => { - if (server) { - await server.stop(); - } - await terminateDDB(ddbEmulator, dbPath); - }); - - describe('$util.validate', () => { - let transformerOutput; - const queryString = /* GraphQL */ ` - query getPost { - getPost(id: "10") { - id - title - } - } - `; - beforeEach(async () => { - transformerOutput = await runTransformer(validSchema); - }); - test('it should not throw error when validation condition is true', async () => { - transformerOutput.resolvers[ - 'Query.getPost.res.vtl' - ] = `$util.validate(true, "Validation Error", "ValidationError", { "id": "11", "title": "Title Sent from Error" })\n$util.toJson({"id": 11, "title": "Non Error title"})`; - await reDeploy(transformerOutput, server, ddbClient); - const response = await GRAPHQL_CLIENT.query(queryString, {}); - expect(response.data).toBeDefined(); - expect(response.data.getPost.id).toEqual('11'); - expect(response.data.getPost.title).toEqual('Non Error title'); - expect(response.errors).not.toBeDefined(); - }); - - test('$util.validate should throw error and pass the data along with error message and error type when the condition fails', async () => { - transformerOutput.resolvers[ - 'Query.getPost.req.vtl' - ] = `$util.validate(false, "Validation Error", "ValidationError", { "id": "10", "title": "Title Sent from Error" })`; - await reDeploy(transformerOutput, server, ddbClient); - - const response = await GRAPHQL_CLIENT.query(queryString, {}); - expect(response.data).toBeDefined(); - expect(response.data.getPost.id).toEqual('10'); - expect(response.data.getPost.title).toEqual('Title Sent from Error'); - - expect(response.errors).toBeDefined(); - expect(response.errors).toHaveLength(1); - expect(response.errors[0].message).toEqual('Validation Error'); - expect((response.errors[0] as any).errorType).toEqual('ValidationError'); - }); - - test('$util.validate should return error message and CustomTemplateException when error type is not passed', async () => { - transformerOutput.resolvers['Query.getPost.req.vtl'] = `$util.validate(false, "Validation Error")`; - await reDeploy(transformerOutput, server, ddbClient); - - const response = await GRAPHQL_CLIENT.query(queryString, {}); - expect(response.data).toBeDefined(); - expect(response.data.getPost).toBe(null); - - expect(response.errors).toBeDefined(); - expect(response.errors).toHaveLength(1); - expect(response.errors[0].message).toEqual('Validation Error'); - expect((response.errors[0] as any).errorType).toEqual('CustomTemplateException'); - }); - - test('$util.validate should allow overriding the error type', async () => { - transformerOutput.resolvers['Query.getPost.req.vtl'] = `$util.validate(false, "Validation Error", "MyErrorType")`; - await reDeploy(transformerOutput, server, ddbClient); - - const response = await GRAPHQL_CLIENT.query(queryString, {}); - expect(response.data).toBeDefined(); - expect(response.data.getPost).toBe(null); - - expect(response.errors).toBeDefined(); - expect(response.errors).toHaveLength(1); - expect(response.errors[0].message).toEqual('Validation Error'); - expect((response.errors[0] as any).errorType).toEqual('MyErrorType'); - }); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/CFNParser/import-model-table-resolver.test.ts b/packages/amplify-util-mock/src/__tests__/CFNParser/import-model-table-resolver.test.ts deleted file mode 100644 index 4e9958de3a..0000000000 --- a/packages/amplify-util-mock/src/__tests__/CFNParser/import-model-table-resolver.test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { importModelTableResolver } from '../../CFNParser/import-model-table-resolver'; - -describe('import model table resolver', () => { - it('replaces matched imports', () => { - expect(importModelTableResolver('1234:GetAtt:MyModelTable:Name', 'dev')).toEqual('MyModel-1234-dev'); - }); - - it('identity function if no match', () => { - expect(importModelTableResolver('not a match', 'dev')).toEqual('not a match'); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/CFNParser/intrinsic-functions.test.ts b/packages/amplify-util-mock/src/__tests__/CFNParser/intrinsic-functions.test.ts deleted file mode 100644 index 1466349c5b..0000000000 --- a/packages/amplify-util-mock/src/__tests__/CFNParser/intrinsic-functions.test.ts +++ /dev/null @@ -1,387 +0,0 @@ -import { - cfnJoin, - cfnSub, - cfnGetAtt, - cfnSplit, - cfnRef, - cfnSelect, - cfnIf, - cfnEquals, - cfnNot, - cfnAnd, - cfnOr, - cfnImportValue, - cfnCondition, -} from '../../CFNParser/intrinsic-functions'; -import { CloudFormationParseContext } from '../../CFNParser/types'; - -describe('intrinsic-functions', () => { - describe('cfnJoin', () => { - const cfnContext: CloudFormationParseContext = { - params: {}, - conditions: {}, - resources: {}, - exports: {}, - }; - it('should join values', () => { - const node: any = ['-', ['foo', 'bar', 'baz']]; - const parseValue = jest.fn((ip) => ip); - expect(cfnJoin(node, cfnContext, parseValue)).toEqual('foo-bar-baz'); - expect(parseValue).toHaveBeenCalledTimes(3); - node[1].forEach((val, index) => { - expect(parseValue.mock.calls[index][0]).toEqual(val); - }); - }); - - it('should throw error if listOfValues are not present', () => { - const node: any = ['-']; - expect(() => { - cfnJoin(node, cfnContext, jest.fn()); - }).toThrow(); - }); - - it('should throw error if if there are 3 arguments to Fn::Join are not present', () => { - const node: any = ['-', [], []]; - expect(() => { - cfnJoin(node, cfnContext, jest.fn()); - }).toThrow(); - }); - }); - - describe('cfnSub', () => { - const cfnContext: CloudFormationParseContext = { - params: {}, - conditions: {}, - resources: {}, - exports: {}, - }; - it('should substitute variable', () => { - const parseValue = jest.fn((val) => val); - const expr = ['My name is ${name}. I am ${age} years old', { name: 'John', age: '25' }]; - expect(cfnSub(expr, cfnContext, parseValue)).toEqual('My name is John. I am 25 years old'); - expect(parseValue).toHaveBeenCalledTimes(2); - }); - - it('should throw error if there are no substitute variable', () => { - const expr = ['My name is ${name}. I am ${age} years old']; - expect(() => cfnSub(expr, cfnContext, (val) => val)).toThrow(); - }); - it('should throw error if there are no substitute variable', () => { - const expr = ['My name is ${name}. I am ${age} years old']; - expect(() => cfnSub(expr, cfnContext, (val) => val)).toThrow(); - }); - }); - - describe('cfnGetAtt', () => { - const cfnContext: CloudFormationParseContext = { - params: {}, - conditions: {}, - resources: { - FooResource: { - Type: 'Foo', - result: { - cfnExposedAttributes: { prop1: 'Prop1', props: 'missing' }, - Prop1: 'prop1 value', - }, - }, - }, - exports: {}, - }; - it('should get attribute value from parsed resources', () => { - const node = ['FooResource', 'prop1']; - expect(cfnGetAtt(node, cfnContext, () => {})).toEqual('prop1 value'); - }); - - it('should throw error if resource is missing in the context', () => { - const node = ['MissingResource', 'prop1']; - expect(() => cfnGetAtt(node, cfnContext, () => {})).toThrow(); - }); - - it('should throw if the property is missing in the resource', () => { - const node = ['FooResource', 'missing-prop']; - expect(() => cfnGetAtt(node, cfnContext, () => {})).toThrow(); - }); - it('should throw if the property is exposed in cfnExposedAttribute but missing in the result', () => { - const node = ['FooResource', 'prop2']; - expect(() => cfnGetAtt(node, cfnContext, () => {})).toThrow(); - }); - }); - - describe('cfnSplit', () => { - const cfnContext: CloudFormationParseContext = { - params: {}, - conditions: {}, - resources: {}, - exports: {}, - }; - it('should split string', () => { - const node = ['-', 'foo-bar-baz']; - const processValue = jest.fn((val) => val); - expect(cfnSplit(node, cfnContext, processValue)).toEqual(['foo', 'bar', 'baz']); - expect(processValue).toHaveBeenCalledWith(node[1], cfnContext); - }); - - it('should throw error when split string is missing', () => { - const node = ['-']; - const processValue = jest.fn((val) => val); - expect(() => cfnSplit(node, cfnContext, processValue)).toThrow(); - }); - }); - - describe('cfnRef', () => { - const cfnContext: CloudFormationParseContext = { - params: { fromParam: 'foo' }, - conditions: {}, - resources: { - fromResource: { Type: 'Foo', result: { ref: 'resource' } }, - fromResource2: { Type: 'Bar', result: { Name: 'bar' } }, - }, - exports: {}, - }; - - it('should get ref from params', () => { - const node = 'fromParam'; - expect(cfnRef(node, cfnContext, () => {})).toEqual('foo'); - }); - it('should get ref from resources', () => { - const node = 'fromResource'; - expect(cfnRef(node, cfnContext, () => {})).toEqual('resource'); - }); - - it('should call parseValue if the ref is not a string', () => { - const node = [{ 'Fn::Join': ['-', ['foo', 'bar']] }]; - const parseValue = jest.fn((val) => 'fromParam'); - expect(cfnRef(node, cfnContext, parseValue)).toEqual('foo'); - }); - - it('should throw error if the node has length more than 1 item', () => { - const node = ['foo', 'bar']; - expect(() => cfnRef(node, cfnContext, () => {})).toThrow(); - }); - - it('should throw error resource does not have name prop', () => { - const node = 'fromResource2'; - expect(() => cfnRef(node, cfnContext, () => {})).toThrow(); - }); - }); - - describe('cfnSelect', () => { - const cfnContext: CloudFormationParseContext = { - params: {}, - conditions: {}, - resources: {}, - exports: {}, - }; - afterEach(() => { - jest.resetAllMocks(); - }); - const parseValue = jest.fn((val) => val); - - it('should select the value', () => { - const node: any = ['2', ['foo', 'bar', 'baz']]; - expect(cfnSelect(node, cfnContext, parseValue)).toEqual('baz'); - expect(parseValue).toHaveBeenCalledTimes(2); - expect(parseValue.mock.calls[0][0]).toEqual(node[1]); - expect(parseValue.mock.calls[1][0]).toEqual('baz'); - }); - it('should resolve nested intrinsic functions to a list', () => { - parseValue.mockReturnValueOnce(['this', 'is', 'the', 'expected value']).mockImplementationOnce((input) => input); - const parseThis = { parse: 'this' }; - const node: any = [3, parseThis]; - expect(cfnSelect(node, cfnContext, parseValue)).toEqual('expected value'); - expect(parseValue).toHaveBeenCalledTimes(2); - expect(parseValue.mock.calls[0][0]).toEqual(parseThis); - expect(parseValue.mock.calls[1][0]).toEqual('expected value'); - }); - - it('should error on a non-list value', () => { - parseValue.mockReturnValueOnce('this is not an array'); - const parseThis = { parse: 'this' }; - const node: any = [2, parseThis]; - expect(() => cfnSelect(node, cfnContext, parseValue)).toThrowErrorMatchingInlineSnapshot( - `"FN::Select expects list item to be an array instead got \\"this is not an array\\""`, - ); - expect(parseValue).toHaveBeenCalled(); - expect(parseValue.mock.calls[0][0]).toEqual(parseThis); - }); - }); - - describe('cfnIf', () => { - const cfnContext: CloudFormationParseContext = { - params: {}, - conditions: { - foo: true, - bar: false, - }, - resources: {}, - exports: {}, - }; - let parseValue; - beforeEach(() => { - parseValue = jest.fn((val) => val); - }); - it('should return true value section when condition is true', () => { - const node = ['foo', 'foo value', 'bar value']; - expect(cfnIf(node, cfnContext, parseValue)).toEqual('foo value'); - }); - it('should return false value section when condition is true', () => { - const node = ['bar', 'foo value', 'bar value']; - expect(cfnIf(node, cfnContext, parseValue)).toEqual('bar value'); - }); - it('should return `undefined` when the returned value section is a `AWS::NoValue` Ref', () => { - const node = ['foo', { Ref: 'AWS::NoValue' }, 'bar value']; - expect(cfnIf(node, cfnContext, parseValue)).toBeUndefined(); - }); - }); - - describe('cfnEquals', () => { - const cfnContext: CloudFormationParseContext = { - params: {}, - conditions: { - foo: true, - bar: false, - }, - resources: {}, - exports: {}, - }; - const parseValue = jest.fn((val) => val); - it('should return true when equal', () => { - const node = ['foo', 'foo']; - expect(cfnEquals(node, cfnContext, parseValue)).toBeTruthy(); - expect(parseValue).toHaveBeenCalled(); - }); - - it('should return false when not equal', () => { - const node = ['foo', 'bar']; - expect(cfnEquals(node, cfnContext, (val) => val)).toBeFalsy(); - }); - }); - - describe('cfnNot', () => { - const cfnContext: CloudFormationParseContext = { - params: {}, - conditions: {}, - resources: {}, - exports: {}, - }; - const parseValue = jest.fn((val) => val); - it('should return false when Fn::Not(trueCondition)', () => { - parseValue.mockReturnValueOnce(true); - const node = ['trueCondition']; - expect(cfnNot(node, cfnContext, parseValue)).toBeFalsy(); - expect(parseValue).toHaveBeenCalled(); - }); - - it('should return true when {Fn::Not, falseCondition}', () => { - parseValue.mockReturnValueOnce(false); - const node = ['falseCondition']; - expect(cfnNot(node, cfnContext, parseValue)).toBeTruthy(); - expect(parseValue).toHaveBeenCalled(); - }); - }); - - describe('cfnAnd', () => { - const cfnContext: CloudFormationParseContext = { - params: {}, - conditions: {}, - resources: {}, - exports: {}, - }; - - let parseValue; - beforeEach(() => { - parseValue = jest.fn(); - }); - it('should return false when Fn::And encounter a false value', () => { - parseValue.mockReturnValueOnce(true); - parseValue.mockReturnValueOnce(true); - parseValue.mockReturnValueOnce(false); - parseValue.mockReturnValueOnce(true); - const node = ['cond1', 'cond2', 'cond3', 'cond4']; - expect(cfnAnd(node, cfnContext, parseValue)).toBeFalsy(); - expect(parseValue).toHaveBeenCalled(); - }); - - it('should return false when Fn::And encounter all true values', () => { - parseValue.mockReturnValue(true); - - const node = ['cond1', 'cond2', 'cond3', 'cond4']; - expect(cfnAnd(node, cfnContext, parseValue)).toBeTruthy(); - expect(parseValue).toHaveBeenCalledTimes(4); - }); - }); - describe('cfnOr', () => { - const cfnContext: CloudFormationParseContext = { - params: {}, - conditions: {}, - resources: {}, - exports: {}, - }; - - let parseValue; - beforeEach(() => { - parseValue = jest.fn(); - }); - it('should return true when Fn::Or encounter at least one true value', () => { - parseValue.mockReturnValueOnce(true); - parseValue.mockReturnValueOnce(true); - parseValue.mockReturnValueOnce(false); - parseValue.mockReturnValueOnce(true); - const node = ['cond1', 'cond2', 'cond3', 'cond4']; - expect(cfnOr(node, cfnContext, parseValue)).toBeTruthy(); - expect(parseValue).toHaveBeenCalled(); - }); - - it('should return false when Fn::Or encounter all false values', () => { - parseValue.mockReturnValue(false); - - const node = ['cond1', 'cond2', 'cond3', 'cond4']; - expect(cfnAnd(node, cfnContext, parseValue)).toBeFalsy(); - expect(parseValue).toHaveBeenCalledTimes(4); - }); - }); - - describe('cfnImportValue', () => { - const cfnContext: CloudFormationParseContext = { - params: {}, - conditions: {}, - resources: {}, - exports: { foo: 'fooValue' }, - }; - let parseValue; - beforeEach(() => { - parseValue = jest.fn((val) => val); - }); - - it('should return value for key from exports', () => { - const node = 'foo'; - expect(cfnImportValue(node, cfnContext, parseValue)).toEqual('fooValue'); - expect(parseValue).toHaveBeenCalled(); - }); - - it('should return key if the value is not presnt in exports', () => { - const node = 'bar'; - expect(cfnImportValue(node, cfnContext, parseValue)).toEqual(node); - }); - }); - - describe('cfnCondition', () => { - const cfnContext: CloudFormationParseContext = { - params: {}, - conditions: { - foo: true, - bar: false, - }, - resources: {}, - exports: {}, - }; - - it('should return condition value', () => { - expect(cfnCondition('bar', cfnContext, () => {})).toBeFalsy(); - expect(cfnCondition('foo', cfnContext, () => {})).toBeTruthy(); - }); - it('should throw if the condition is missing', () => { - expect(() => cfnCondition('missing-condition', cfnContext, () => {})).toThrow(); - }); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/CFNParser/nested-aws-no-value.test.ts b/packages/amplify-util-mock/src/__tests__/CFNParser/nested-aws-no-value.test.ts deleted file mode 100644 index 334f2938e3..0000000000 --- a/packages/amplify-util-mock/src/__tests__/CFNParser/nested-aws-no-value.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { CloudFormationTemplate } from '../../CFNParser/stack/types'; -import { CloudFormationParseContext } from '../../CFNParser/types'; -import { parseValue } from '../../CFNParser/field-parser'; - -describe('cloudformation templates', () => { - const nestedNoValue: CloudFormationTemplate = { - Conditions: { - AlwaysTrue: { - 'Fn::Equals': ['true', 'true'], - }, - AlwaysFalse: { - 'Fn::Equals': ['false', 'true'], - }, - }, - Resources: { - DummyResource: { - Type: 'Resource::Dummy', - Properties: { - ConditionalValue: { - 'Fn::If': ['AlwaysTrue', 'ConditionIsTrue', { Ref: 'AWS::NoValue' }], - }, - ConditionalRef: { - 'Fn::If': ['AlwaysFalse', { Ref: 'AWS::NoValue' }, { Ref: 'SomeRef' }], - }, - ConditionalNoValue: { - 'Fn::If': ['AlwaysTrue', { Ref: 'AWS::NoValue' }, { Ref: 'SomeRef' }], - }, - }, - }, - }, - }; - const cfnContext: CloudFormationParseContext = { - params: {}, - conditions: { - AlwaysTrue: true, - AlwaysFalse: false, - }, - resources: { - SomeRef: { - Type: 'String', - result: { ref: 'resolvedRefValue' }, - }, - }, - exports: {}, - }; - - it('should resolve nested `Fn::If`', () => { - const value = parseValue(nestedNoValue.Resources.DummyResource.Properties.ConditionalValue, cfnContext); - expect(value).toEqual('ConditionIsTrue'); - }); - - it('should resolve nested `Fn::If` and evaluate a resulting Ref', () => { - const value = parseValue(nestedNoValue.Resources.DummyResource.Properties.ConditionalRef, cfnContext); - expect(value).toEqual('resolvedRefValue'); - }); - - it('should resolve nested `Fn::If` and evaluate a resulting `AWS::NoValue` Ref', () => { - const value = parseValue(nestedNoValue.Resources.DummyResource.Properties.ConditionalNoValue, cfnContext); - expect(value).toBeUndefined(); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/CFNParser/resource-processors/appsync.test.ts b/packages/amplify-util-mock/src/__tests__/CFNParser/resource-processors/appsync.test.ts deleted file mode 100644 index cf953bfdf9..0000000000 --- a/packages/amplify-util-mock/src/__tests__/CFNParser/resource-processors/appsync.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { appSyncFunctionHandler } from '../../../CFNParser/resource-processors/appsync'; -import { CloudFormationResource } from '../../../CFNParser/stack/types'; -import { CloudFormationParseContext } from '../../../CFNParser/types'; - -describe('appSyncFunctionHandler', () => { - it('maps exposed attributes to properties that exist', () => { - const resource: CloudFormationResource = { - Type: 'AWS::AppSync::FunctionConfiguration', - Properties: { - Name: 'dummyFunction', - DataSourceName: 'dummyDataSource', - }, - }; - const cfnContext: CloudFormationParseContext = { - params: {}, - conditions: {}, - resources: {}, - exports: {}, - }; - const processedResource = appSyncFunctionHandler('', resource, cfnContext); - const exposedAttribute = processedResource.cfnExposedAttributes.FunctionArn; - expect(processedResource[exposedAttribute]).toBeDefined(); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/CFNParser/stack/index.test.ts b/packages/amplify-util-mock/src/__tests__/CFNParser/stack/index.test.ts deleted file mode 100644 index 9220545934..0000000000 --- a/packages/amplify-util-mock/src/__tests__/CFNParser/stack/index.test.ts +++ /dev/null @@ -1,721 +0,0 @@ -import { - mergeParameters, - processConditions, - sortResources, - filterResourcesBasedOnConditions, - processResources, - processOutputs, - processExports, - nestedStackHandler, - processCloudFormationStack, - CFN_PSEUDO_PARAMS, - getDependencyResources, -} from '../../../CFNParser/stack'; -import { - CloudFormationResources, - CloudFormationOutputs, - CloudFormationTemplate, - CloudFormationResource, - CloudFormationTemplateFetcher, -} from '../../../CFNParser/stack/types'; - -import { getResourceProcessorFor } from '../../../CFNParser/resource-processors'; - -jest.mock('../../../CFNParser/resource-processors'); - -describe('CloudFormation stack', () => { - describe('mergeParameters', () => { - it('should use the value from inputParameter when passed', () => { - expect( - mergeParameters( - { - test: { - Default: 'default test value', - Type: 'String', - Description: 'test description', - }, - }, - { - test: 'input from param', - }, - ), - ).toEqual({ ...CFN_PSEUDO_PARAMS, test: 'input from param' }); - }); - - it('should return the default value when the inputParameter is missing the param', () => { - expect( - mergeParameters( - { - test: { - Default: 'default test value', - Type: 'String', - Description: 'test description 1', - }, - }, - {}, - ), - ).toEqual({ ...CFN_PSEUDO_PARAMS, test: 'default test value' }); // ? - }); - it('should throw an error when the input is missing default value', () => { - expect(() => - mergeParameters( - { - test: { - Type: 'String', - Description: 'test description', - }, - }, - {}, - ), - ).toThrowError('missing default value'); - }); - }); - - describe('processConditions', () => { - it('should process the condition', () => { - expect( - processConditions( - { - CreateProdResources: { 'Fn::Equals': [{ Ref: 'EnvType' }, 'prod'] }, - VerboseLogs: { 'Fn::Not': [{ 'Fn::Equals': [{ Ref: 'EnvType' }, 'prod'] }] }, - }, - { EnvType: 'prod' }, - ), - ).toEqual({ CreateProdResources: true, VerboseLogs: false }); - }); - - it('should use ref key when no value found', () => { - expect( - processConditions( - { - CreateProdResources: { 'Fn::Equals': [{ Ref: 'EnvType' }, 'EnvType'] }, - }, - {}, - ), - ).toEqual({ CreateProdResources: true }); - }); - }); - - describe('sortResources', () => { - it('should sort resources on topological order', () => { - const resources: CloudFormationResources = { - resource1: { - Properties: {}, - DependsOn: ['resource2', 'resource3'], - Type: 'DummyResource', - }, - resource3: { - Properties: {}, - Type: 'DummyResource', - }, - resource2: { - Properties: {}, - DependsOn: ['resource3'], - Type: 'DummyResource', - }, - }; - expect(sortResources(resources, {})).toEqual(['resource3', 'resource2', 'resource1']); - }); - - it('should add Ref resource as dependency', () => { - const resources: CloudFormationResources = { - resource1: { - Properties: {}, - DependsOn: ['resource2', 'resource3'], - Type: 'DummyResource', - }, - resource3: { - Properties: { - Prop1: { Ref: 'resource2' }, - }, - Type: 'DummyResource', - }, - resource2: { - Properties: {}, - Type: 'DummyResource', - }, - }; - expect(sortResources(resources, {})).toEqual(['resource2', 'resource3', 'resource1']); - }); - - it('should add Fn::GetAtt resource as dependency', () => { - const resources: CloudFormationResources = { - resource1: { - Properties: {}, - DependsOn: ['resource2', 'resource3'], - Type: 'DummyResource', - }, - resource3: { - Properties: { - Prop1: { 'Fn::GetAtt': ['resource2', 'prop1'] }, - }, - Type: 'DummyResource', - }, - resource2: { - Properties: {}, - Type: 'DummyResource', - }, - }; - expect(sortResources(resources, {})).toEqual(['resource2', 'resource3', 'resource1']); - }); - - // it('should should throw error when intrinsic dependency has missing resource', () => { - // const resources: CloudFormationResources = { - - // resource3: { - // Properties: { - // Prop1: {'Ref': 'resource10'} - // }, - // Type: 'DummyResource', - // }, - // }; - // expect(() => sortResources(resources, {})).toThrowError('Resource resource3 has missing intrinsic dependency resource resource10'); - // }); - - it('should throw error when resource depends on non-existent resource', () => { - const resources: CloudFormationResources = { - resource1: { - Properties: {}, - DependsOn: ['resource2', 'resource3'], - Type: 'DummyResource', - }, - resource2: { - Properties: {}, - DependsOn: ['resource3'], - Type: 'DummyResource', - }, - }; - expect(() => sortResources(resources, {})).toThrowError('DependsOn a non-existent resource'); - }); - - it('should throw error when resource Depends on itself', () => { - const resources: CloudFormationResources = { - resource1: { - Properties: {}, - DependsOn: ['resource2', 'resource1'], - Type: 'DummyResource', - }, - resource2: { - Properties: {}, - DependsOn: ['resource3'], - Type: 'DummyResource', - }, - }; - expect(() => sortResources(resources, {})).toThrowError('Resource resource1 can not depend on itself'); - }); - }); - describe('filterResourcesBasedOnConditions', () => { - it("should remove resources that don't have condition set to true", () => { - const filteredResources = filterResourcesBasedOnConditions( - { - resource1: { - Properties: {}, - Condition: 'condition1', - Type: 'resource1type', - }, - resource2: { - Properties: {}, - Condition: 'condition2', - Type: 'resource1type', - }, - }, - { condition1: true, condition2: false }, - ); - expect(Object.keys(filteredResources)).toContain('resource1'); - expect(Object.keys(filteredResources)).not.toContain('resource2'); - }); - - it('should throw an error when condition is non-existent condition', () => { - expect(() => - filterResourcesBasedOnConditions( - { - resource1: { - Properties: {}, - Condition: 'non-existent-condition', - Type: 'resource1type', - }, - }, - {}, - ), - ).toThrowError('not defined in Condition block'); - }); - }); - - describe('processResources', () => { - const getResourceProcessorForMock = getResourceProcessorFor as jest.Mock; - const cfnResourceFetcher: CloudFormationTemplateFetcher = { - getCloudFormationStackTemplate: jest.fn(), - }; - const processedResource = { value: 'processed resource' }; - const processResourceMock = jest.fn(); - beforeEach(() => { - jest.resetAllMocks(); - - getResourceProcessorForMock.mockReturnValue(processResourceMock); - processResourceMock.mockImplementation(() => ({ ...processedResource })); - }); - - it('should process individual resources', () => { - const resources = { - dummyResource: { - Type: 'StackTest::DummyResource', - Properties: {}, - }, - }; - expect(processResources({}, {}, resources, {}, cfnResourceFetcher)).toEqual({ - resources: { - dummyResource: { - result: processedResource, - Type: 'StackTest::DummyResource', - }, - }, - stackExports: {}, - }); - expect(getResourceProcessorForMock).toHaveBeenCalledTimes(1); - }); - - it('should not process resources when condition is not met', () => { - const resources = { - dummyResource2: { - Type: 'StackTest::DummyResource', - Properties: {}, - Condition: 'alwaysFalse', - }, - }; - expect(processResources({}, { alwaysFalse: false }, resources, {}, cfnResourceFetcher)).toEqual({ resources: {}, stackExports: {} }); - expect(getResourceProcessorForMock).not.toHaveBeenCalled(); - }); - - it('should topographically sort resources', () => { - const resources = { - dummyResource1: { - Type: 'StackTest::DummyResource', - Properties: {}, - DependsOn: ['dummyResource2'], - }, - dummyResource2: { - Type: 'StackTest::DummyResourceType2', - Properties: {}, - }, - }; - expect(processResources({}, {}, resources, {}, cfnResourceFetcher)).toEqual({ - resources: { - dummyResource1: { - result: processedResource, - Type: 'StackTest::DummyResource', - }, - dummyResource2: { - result: processedResource, - Type: 'StackTest::DummyResourceType2', - }, - }, - stackExports: {}, - }); - expect(getResourceProcessorForMock).toHaveBeenCalledTimes(2); - - expect(getResourceProcessorForMock.mock.calls[0][0]).toEqual(resources.dummyResource2.Type); - expect(processResourceMock.mock.calls[0][0]).toEqual('dummyResource2'); - expect(processResourceMock.mock.calls[0][1]).toEqual(resources.dummyResource2); - - expect(getResourceProcessorForMock.mock.calls[1][0]).toEqual(resources.dummyResource1.Type); - expect(processResourceMock.mock.calls[1][0]).toEqual('dummyResource1'); - expect(processResourceMock.mock.calls[1][1]).toEqual(resources.dummyResource1); - }); - - it('should update the cfnContext to include previously processed resources', () => { - const resources = { - dummyResource1: { - Type: 'StackTest::DummyResource', - Properties: {}, - }, - dummyResource2: { - Type: 'StackTest::DummyResourceType2', - Properties: {}, - }, - }; - expect(processResources({}, {}, resources, {}, cfnResourceFetcher)).toEqual({ - resources: { - dummyResource1: { - result: processedResource, - Type: 'StackTest::DummyResource', - }, - dummyResource2: { - result: processedResource, - Type: 'StackTest::DummyResourceType2', - }, - }, - stackExports: {}, - }); - // signature of processResource(resourceName, resource, cfnContext, transformerContext) - const cfnContext = processResourceMock.mock.calls[1][2]; - expect(cfnContext.resources).toEqual({ - dummyResource1: { - result: processedResource, - Type: resources.dummyResource1.Type, - }, - }); - }); - - it('should support processing nested stack and collect exported value from nested stacks', () => { - const resources: CloudFormationResources = { - nestedStack1: { - Type: 'AWS::CloudFormation::Stack', - Properties: { - Parameters: { - Foo: 'Foo Value', - }, - TemplateURL: 'https://s3.amazonaws.com/${S3DeploymentBucket}/${S3DeploymentRootKey}/stacks/nested1.stack.cloudformation.json', - }, - }, - nestedStack2: { - Type: 'AWS::CloudFormation::Stack', - Properties: { - Parameters: { - Bar: 'Bar value', - }, - TemplateURL: 'https://s3.amazonaws.com/${S3DeploymentBucket}/${S3DeploymentRootKey}/stacks/nested2.stack.cloudformation.json', - }, - }, - }; - - const transformerOutput = { - stacks: { - 'nested1.stack.cloudformation.json': { - Parameters: { - Foo: { - Type: 'String', - Default: 'Foo default value', - }, - Bar: { - Type: 'Number', - Default: 10, - }, - }, - Resources: { - Nested1: { - Type: 'Foo:DummyResource', - Properties: {}, - }, - }, - Outputs: { - nested1StackOutput: { - Value: { - Ref: 'Bar', - }, - Export: { - Name: 'BarValueFromNestedStack1', - }, - }, - }, - }, - 'nested2.stack.cloudformation.json': { - Parameters: { - Bar: { - Type: 'String', - Default: 'Foo default value', - }, - }, - Resources: { - Nested1: { - Type: 'Foo:DummyResource', - Properties: {}, - }, - }, - Outputs: { - nested2StackOutput: { - Value: { - Ref: 'Bar', - }, - Export: { - Name: 'BarValueFromNestedStack2', - }, - }, - }, - }, - }, - }; - cfnResourceFetcher.getCloudFormationStackTemplate = jest.fn().mockImplementation((templateName) => { - const template = templateName.replace('https://s3.amazonaws.com/${S3DeploymentBucket}/${S3DeploymentRootKey}/stacks/', ''); - return transformerOutput.stacks[template] as CloudFormationTemplate; - }); - - const processedResources = processResources({}, {}, resources, {}, cfnResourceFetcher); - expect(processedResources.stackExports).toEqual({ - BarValueFromNestedStack1: 10, - BarValueFromNestedStack2: 'Bar value', - }); - }); - }); - - describe('processOutputs', () => { - const outputSection: CloudFormationOutputs = { - GraphQLAPIIdOutput: { - Description: 'Your GraphQL API ID with export.', - Value: { - 'Fn::GetAtt': ['GraphQLAPI', 'ApiId'], - }, - }, - }; - const resources = { - GraphQLAPI: { - result: { - cfnExposedAttributes: { ApiId: 'ApiId' }, - ApiId: 'fakeApiId', - }, - }, - }; - it('should process outputs', () => { - expect(processOutputs(outputSection, {}, {}, resources, {})).toEqual({ - GraphQLAPIIdOutput: 'fakeApiId', - }); - }); - }); - - describe('processExports', () => { - const outputSection: CloudFormationOutputs = { - GraphQLAPIIdOutput: { - Description: 'Your GraphQL API ID with export.', - Value: { - 'Fn::GetAtt': ['GraphQLAPI', 'ApiId'], - }, - Export: { - Name: { - 'Fn::Join': [ - ':', - [ - { - Ref: 'AWS::StackName', - }, - 'GraphQLApiId', - ], - ], - }, - }, - }, - GraphQLAPIIdOutputNoExport: { - Description: 'Your GraphQL API ID with export.', - Value: { - 'Fn::GetAtt': ['GraphQLAPI', 'ApiId'], - }, - }, - }; - const parameters = { - 'AWS::StackName': 'myStack', - }; - const resources = { - GraphQLAPI: { - result: { - cfnExposedAttributes: { ApiId: 'ApiId' }, - ApiId: 'fakeApiId', - }, - }, - }; - it('should generate exports when output has exports', () => { - expect(processExports(outputSection, parameters, {}, resources, {})).toEqual({ - 'myStack:GraphQLApiId': 'fakeApiId', - }); - }); - }); - - describe('nestedStackHandler', () => { - const nestedTemplate: CloudFormationTemplate = { - Parameters: { - Foo: { - Type: 'String', - Default: 'Foo value', - }, - }, - Resources: { - fooResource: { - Type: 'Dummy Resource', - Properties: {}, - }, - }, - Outputs: { - NestedStackExport: { - Description: 'Export test', - Value: { - Ref: 'Foo', - }, - Export: { - Name: 'NestedStack:FooValue', - }, - }, - }, - }; - - let cfnResourceFetcher: CloudFormationTemplateFetcher; - - const getResourceProcessorForMock = getResourceProcessorFor as jest.Mock; - const processedResource = { value: 'processed resource' }; - const processResourceMock = jest.fn(); - beforeEach(() => { - jest.resetAllMocks(); - - getResourceProcessorForMock.mockReturnValue(processResourceMock); - processResourceMock.mockImplementation(() => ({ ...processedResource })); - cfnResourceFetcher = { - getCloudFormationStackTemplate: jest.fn(() => nestedTemplate), - }; - }); - - it('should support nested stack', () => { - const resource: CloudFormationResource = { - Type: 'AWS::CloudFormation::Stack', - Properties: { - Parameters: { - Foo: 'FOO OVERRIDE', - }, - TemplateURL: 'https://s3.amazonaws.com/${S3DeploymentBucket}/${S3DeploymentRootKey}/stacks/stack1', - }, - }; - const processedStack = nestedStackHandler( - 'nestedStack', - resource, - { - conditions: {}, - exports: {}, - params: {}, - resources: {}, - }, - cfnResourceFetcher, - ); - expect(processedStack.stackExports).toEqual({ 'NestedStack:FooValue': 'FOO OVERRIDE' }); - expect(cfnResourceFetcher.getCloudFormationStackTemplate).toHaveBeenCalledWith(resource.Properties.TemplateURL); - }); - - it('should throw error if the exported value already exists', () => { - const resource: CloudFormationResource = { - Type: 'AWS::CloudFormation::Stack', - Properties: { - Parameters: { - Foo: 'FOO OVERRIDE', - }, - TemplateURL: 'https://s3.amazonaws.com/${S3DeploymentBucket}/${S3DeploymentRootKey}/stacks/stack1', - }, - }; - expect(() => - nestedStackHandler( - 'nestedStack', - resource, - { - conditions: {}, - exports: { 'NestedStack:FooValue': 'Existing value' }, - params: {}, - resources: {}, - }, - cfnResourceFetcher, - ), - ).toThrowError('is already exported in a different stack'); - }); - - it('should throw error if the nested stack resource does not have TemplateURL', () => { - const resource: CloudFormationResource = { - Type: 'AWS::CloudFormation::Stack', - Properties: {}, - }; - expect(() => - nestedStackHandler( - 'nestedStack', - resource, - { - conditions: {}, - exports: {}, - params: {}, - resources: {}, - }, - cfnResourceFetcher, - ), - ).toThrowError('Stack is missing required property TemplateURL'); - }); - }); - - describe('processCloudFormationStack', () => { - const getResourceProcessorForMock = getResourceProcessorFor as jest.Mock; - const processedResource = { value: 'processed resource' }; - const processResourceMock = jest.fn(); - beforeEach(() => { - jest.resetAllMocks(); - - getResourceProcessorForMock.mockReturnValue(processResourceMock); - processResourceMock.mockImplementation(() => ({ ...processedResource })); - }); - - it('should take a template and generate resources and exports', () => { - const template: CloudFormationTemplate = { - Parameters: { - Foo: { - Type: 'String', - Default: 'Foo Default value', - }, - }, - Conditions: { - AlwaysFalse: { - 'Fn::Equals': ['false', 'true'], - }, - }, - Resources: { - DummyResource: { - Type: 'Resource::Dummy', - Properties: {}, - }, - ShouldNotExistInProcessedResource: { - Type: 'Resource::Dummy', - Properties: {}, - Condition: 'AlwaysFalse', - }, - }, - Outputs: { - Output1: { - Value: { Ref: 'Foo' }, - Description: 'Some description', - Export: { - Name: 'ExportedValue', - }, - }, - }, - }; - const processedTemplate = processCloudFormationStack(template, {}, {}, { getCloudFormationStackTemplate: jest.fn() }); - expect(processedTemplate.resources).toBeDefined(); - expect(processedTemplate.resources.DummyResource).toEqual({ result: processedResource, Type: 'Resource::Dummy' }); - expect(processedTemplate.resources.ShouldNotExistInProcessedResource).not.toBeDefined(); - expect(processedTemplate.stackExports).toBeDefined(); - expect(processedTemplate.stackExports.ExportedValue).toEqual('Foo Default value'); - }); - }); - - describe('getDependencyResources', () => { - it('should get Ref name as a dependency', () => { - const propValue = { - Ref: 'Foo', - }; - expect(getDependencyResources(propValue, {})).toEqual(['Foo']); - }); - - it('should not include Ref if the Ref name is included in the Parameters', () => { - const propValue = { - Ref: 'Foo', - }; - expect(getDependencyResources(propValue, { Foo: 'FooValue' })).toEqual([]); - }); - it('should get Fn::GetAtt resource name as a dependency', () => { - const propValue = { - 'Fn::GetAtt': ['FooBar', 'AttName'], - }; - expect(getDependencyResources(propValue, {})).toEqual(['FooBar']); - }); - it('should support getting dependency from nested props', () => { - const propValue = { - Functions: [ - { - 'Fn::GetAtt': ['Fn1', 'FunctionId'], - }, - { - 'Fn::GetAtt': ['Fn2', 'FunctionId'], - }, - ], - }; - expect(getDependencyResources(propValue, {})).toEqual(['Fn1', 'Fn2']); - }); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/api/lambda-arn-to-config.test.ts b/packages/amplify-util-mock/src/__tests__/api/lambda-arn-to-config.test.ts deleted file mode 100644 index 343c3d86d9..0000000000 --- a/packages/amplify-util-mock/src/__tests__/api/lambda-arn-to-config.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { lambdaArnToConfig } from '../../api/lambda-arn-to-config'; -import { ProcessedLambdaFunction } from '../../CFNParser/stack/types'; -import { loadLambdaConfig } from '../../utils/lambda/load-lambda-config'; - -jest.mock('@aws-amplify/amplify-cli-core', () => ({ - pathManager: { - getAmplifyPackageLibDirPath: jest.fn().mockReturnValue('test/path'), - }, - ApiCategoryFacade: { - getTransformerVersion: jest.fn().mockReturnValue(2), - }, - getGraphQLTransformerFunctionDocLink: jest.fn().mockReturnValue('mockdocs'), - stateManager: { - getMeta: jest.fn().mockReturnValue({ - function: { - lambda1: { - service: 'Lambda', - }, - lambda2: { - service: 'Lambda', - }, - lambdalayer: { - service: 'LambdaLayer', - }, - }, - }), - }, -})); - -jest.mock('../../utils/lambda/load-lambda-config', () => ({ - loadLambdaConfig: jest.fn(), -})); -const loadLambdaConfig_mock = loadLambdaConfig as jest.MockedFunction; - -const expectedLambdaConfig = { name: 'mocklambda', handler: 'mock.handler', environment: {} } as ProcessedLambdaFunction; -loadLambdaConfig_mock.mockResolvedValue(expectedLambdaConfig); - -const context_stub = {} as $TSContext; - -describe('lambda arn to config', () => { - beforeEach(() => jest.clearAllMocks()); - // TODO need to create mocks for provisioned lambdas - it('resolves string arns', async () => { - const result = await lambdaArnToConfig(context_stub, `aws::arn::something::region::lambda1::otherstuff`); - expect(loadLambdaConfig_mock.mock.calls[0][1]).toEqual('lambda1'); - expect(result).toEqual(expectedLambdaConfig); - }); - - it('resolves Fn::Sub with params when lambda name is in template string', async () => { - const result = await lambdaArnToConfig(context_stub, { 'Fn::Sub': [`some::arn::lambda2::{withsubs}::stuff`, { withsubs: 'a value' }] }); - expect(loadLambdaConfig_mock.mock.calls[0][1]).toEqual('lambda2'); - expect(result).toEqual(expectedLambdaConfig); - }); - - it('resolves Fn::Sub strings when lambda name is in template string', async () => { - const result = await lambdaArnToConfig(context_stub, { 'Fn::Sub': `some::{sub}::string::with::lambda1::name` }); - expect(loadLambdaConfig_mock.mock.calls[0][1]).toEqual('lambda1'); - expect(result).toEqual(expectedLambdaConfig); - }); - - it('resolves Fn::GetAtt arns when lambda name is in resource name', async () => { - const result = await lambdaArnToConfig(context_stub, { 'Fn::GetAtt': [`functionlambda1resourcename`, 'arn'] }); - expect(loadLambdaConfig_mock.mock.calls[0][1]).toEqual('lambda1'); - expect(result).toEqual(expectedLambdaConfig); - }); - - it('throws on malformed arn refs', async () => { - expect(lambdaArnToConfig(context_stub, { 'Fn::Sub': { key: 'cant interpret this' } })).rejects.toThrowError(); - }); - - it('throws on unknown arn formats', async () => { - expect(lambdaArnToConfig(context_stub, ['dont know', 'what this is'])).rejects.toThrowError(); - }); - - it('throws when arn is valid but no matching lambda found in the project', async () => { - expect(lambdaArnToConfig(context_stub, 'validformat::but::no::matchinglambda')).rejects.toThrowError(); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/func/__snapshots__/index.test.ts.snap b/packages/amplify-util-mock/src/__tests__/func/__snapshots__/index.test.ts.snap deleted file mode 100644 index 892a2d7e3c..0000000000 --- a/packages/amplify-util-mock/src/__tests__/func/__snapshots__/index.test.ts.snap +++ /dev/null @@ -1,17 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`function start times out function execution at the default time 2`] = ` -[Error: Lambda execution timed out after 10 seconds. Press ctrl + C to exit the process. - To increase the lambda timeout use the --timeout parameter to set a value in seconds. - Note that the maximum Lambda execution time is 15 minutes: - https://aws.amazon.com/about-aws/whats-new/2018/10/aws-lambda-supports-functions-that-can-run-up-to-15-minutes/ -] -`; - -exports[`function start times out function execution at the specified time 1`] = ` -[Error: Lambda execution timed out after 1 seconds. Press ctrl + C to exit the process. - To increase the lambda timeout use the --timeout parameter to set a value in seconds. - Note that the maximum Lambda execution time is 15 minutes: - https://aws.amazon.com/about-aws/whats-new/2018/10/aws-lambda-supports-functions-that-can-run-up-to-15-minutes/ -] -`; diff --git a/packages/amplify-util-mock/src/__tests__/func/index.test.ts b/packages/amplify-util-mock/src/__tests__/func/index.test.ts deleted file mode 100644 index 8e282b8b88..0000000000 --- a/packages/amplify-util-mock/src/__tests__/func/index.test.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { getInvoker, getBuilder } from '@aws-amplify/amplify-category-function'; -import { stateManager } from '@aws-amplify/amplify-cli-core'; -import _ from 'lodash'; -import * as inquirer from 'inquirer'; -import { start } from '../../func'; - -jest.mock('../../utils/lambda/load-lambda-config', () => ({ - loadLambdaConfig: jest.fn(() => ({ handler: 'index.testHandle' })), -})); -jest.mock('@aws-amplify/amplify-cli-core', () => ({ - JSONUtilities: { - readJson: jest.fn(), - }, - pathManager: { - getBackendDirPath: () => 'fake-backend-path', - }, - stateManager: { - getMeta: jest.fn().mockReturnValue({}), - }, -})); -jest.mock('@aws-amplify/amplify-category-function', () => ({ - getInvoker: jest.fn().mockResolvedValue(() => new Promise((resolve) => setTimeout(() => resolve('lambda value'), 10))), - getBuilder: jest.fn().mockReturnValue(() => {}), - isMockable: jest.fn().mockReturnValue({ isMockable: true }), - category: 'function', -})); - -jest.mock('inquirer'); -const inquirer_mock = inquirer as jest.Mocked; - -const getInvoker_mock = getInvoker as jest.MockedFunction; -const getBuilder_mock = getBuilder as jest.MockedFunction; -const stateManager_mock = stateManager as jest.Mocked; - -const funcName = 'funcName'; - -describe('function start', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - const context_stub: any = { - input: { - subCommands: [funcName], - options: { - event: 'event.json', - timeout: 1, - }, - }, - amplify: { - inputValidation: () => () => true, - readJsonFile: jest.fn(), - getResourceStatus: () => ({ allResources: [] }), - getEnvInfo: () => ({ envName: 'testing' }), - }, - print: { - success: jest.fn(), - info: jest.fn(), - error: jest.fn(), - blue: jest.fn(), - }, - }; - - jest.setTimeout(1000 * 20); - - // NOTE: A warning from jest saying that async operations weren't stopped in the test is expected here - // because the mock function is designed to keep running after the timeout to ensure that the timeout works - it('times out function execution at the default time', async () => { - getInvoker_mock.mockResolvedValueOnce(() => new Promise((resolve) => setTimeout(() => resolve('lambda value'), 11000))); - context_stub.input.options.timeout = undefined; - await start(context_stub); - expect(context_stub.print.error.mock.calls[0][0]).toMatchInlineSnapshot(`"funcName failed with the following error:"`); - expect(context_stub.print.info.mock.calls[0][0]).toMatchSnapshot(); - context_stub.input.options.timeout = 1; - }); - - it('times out function execution at the specified time', async () => { - getInvoker_mock.mockResolvedValueOnce(() => new Promise((resolve) => setTimeout(() => resolve('lambda value'), 2000))); - await start(context_stub); - expect(context_stub.print.info.mock.calls[0][0]).toMatchSnapshot(); - }); - - it('triggers a dev build before invoking', async () => { - let isBuilt = false; - getBuilder_mock.mockReturnValueOnce(async () => { - isBuilt = true; - }); - getInvoker_mock.mockResolvedValueOnce(async () => { - if (!isBuilt) { - throw new Error('Build was not called before invoke'); - } - }); - - await start(context_stub); - expect(getBuilder_mock.mock.calls.length).toBe(1); - expect(getInvoker_mock.mock.calls.length).toBe(1); - }); - - it('mocks function name specified in command line params', async () => { - await start(context_stub); - expect(getBuilder_mock.mock.calls[0][1]).toBe(funcName); - }); - - it('mocks function if only one function in the project', async () => { - const context_stub_copy = _.merge({}, context_stub); - delete context_stub_copy.input.subCommands; - - stateManager_mock.getMeta.mockReturnValueOnce({ - function: { - func1: {}, - }, - }); - - await start(context_stub_copy); - - expect(getBuilder_mock.mock.calls[0][1]).toBe('func1'); - }); - - it('prompts for function name if none specified and project has multiple functions', async () => { - const context_stub_copy = _.merge({}, context_stub); - delete context_stub_copy.input.subCommands; - - stateManager_mock.getMeta.mockReturnValueOnce({ - function: { - func1: {}, - func2: {}, - func3: {}, - }, - }); - - inquirer_mock.prompt.mockResolvedValueOnce({ resourceName: 'func2' }); - - await start(context_stub_copy); - - expect(inquirer_mock.prompt.mock.calls[0][0][0].choices).toStrictEqual(['func1', 'func2', 'func3']); - expect(getBuilder_mock.mock.calls[0][1]).toBe('func2'); - }); - - it('handles no options specified', async () => { - const invoker = jest.fn().mockResolvedValue(null); - getInvoker_mock.mockResolvedValueOnce(invoker); - inquirer_mock.prompt.mockResolvedValueOnce({ eventName: 'event.json' }); - - const context_stub_copy = _.merge({}, context_stub); - context_stub_copy.input.options = undefined; - await start(context_stub_copy); - expect(invoker.mock.calls.length).toBe(1); - expect(context_stub_copy.print.error.mock.calls.length).toBe(0); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/utils/dynamo-db/helper.test.ts b/packages/amplify-util-mock/src/__tests__/utils/dynamo-db/helper.test.ts deleted file mode 100644 index e26fd9451b..0000000000 --- a/packages/amplify-util-mock/src/__tests__/utils/dynamo-db/helper.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -import * as AWSMock from 'aws-sdk-mock'; -import * as AWS from 'aws-sdk'; -import { DynamoDB } from 'aws-sdk'; -import { waitTillTableStateIsActive } from '../../../utils/dynamo-db/helpers'; - -describe('aitTillTableStateIsActive', () => { - const describeTableMock = jest.fn(); - beforeEach(() => { - jest.resetAllMocks(); - jest.useFakeTimers(); - AWSMock.setSDKInstance(AWS); - AWSMock.mock('DynamoDB', 'describeTable', describeTableMock); - }); - afterEach(() => { - jest.useRealTimers(); - }); - - it('should wait for table to be in active state', async () => { - describeTableMock.mockImplementation(({ TableName }, cb) => { - cb(null, { - Table: { - TableName, - TableStatus: 'ACTIVE', - }, - }); - }); - const dynamoDBClient = new DynamoDB(); - - const waitTillTableStateIsActivePromise = waitTillTableStateIsActive(dynamoDBClient, 'table1'); - jest.advanceTimersByTime(1000); - await waitTillTableStateIsActivePromise; - expect(describeTableMock.mock.calls[0][0]).toEqual({ TableName: 'table1' }); - }); - - it('should reject the promise when table does not become active for timeout period', async () => { - describeTableMock.mockImplementation(({ TableName }, cb) => { - cb(null, { - Table: { - TableName, - TableStatus: 'UPDATING', - }, - }); - }); - const dynamoDBClient = new DynamoDB(); - - const waitTillTableStateIsActivePromise = waitTillTableStateIsActive(dynamoDBClient, 'table1'); - jest.runOnlyPendingTimers(); - await expect(waitTillTableStateIsActivePromise).rejects.toMatchObject({ message: 'Waiting for table status to turn ACTIVE timed out' }); - expect(describeTableMock).toHaveBeenCalled(); - }); - - it('should periodically call check status', async () => { - let callCount = 0; - describeTableMock.mockImplementation(({ TableName }, cb) => { - callCount += 1; - cb(null, { - Table: { - TableName, - TableStatus: callCount === 3 ? 'ACTIVE' : 'UPDATING', - }, - }); - }); - const dynamoDBClient = new DynamoDB(); - - const waitTillTableStateIsActivePromise = waitTillTableStateIsActive(dynamoDBClient, 'table1'); - jest.advanceTimersByTime(3000); - await waitTillTableStateIsActivePromise; - expect(describeTableMock).toBeCalledTimes(4); - expect(describeTableMock.mock.calls[0][0]).toEqual({ TableName: 'table1' }); - expect(describeTableMock.mock.calls[1][0]).toEqual({ TableName: 'table1' }); - expect(describeTableMock.mock.calls[2][0]).toEqual({ TableName: 'table1' }); - expect(describeTableMock.mock.calls[3][0]).toEqual({ TableName: 'table1' }); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/utils/dynamo-db/index.test.ts b/packages/amplify-util-mock/src/__tests__/utils/dynamo-db/index.test.ts deleted file mode 100644 index d6400bc1df..0000000000 --- a/packages/amplify-util-mock/src/__tests__/utils/dynamo-db/index.test.ts +++ /dev/null @@ -1,135 +0,0 @@ -import * as AWSMock from 'aws-sdk-mock'; -import * as AWS from 'aws-sdk'; -import { DynamoDB } from 'aws-sdk'; - -import { CreateTableInput, GlobalSecondaryIndex } from 'aws-sdk/clients/dynamodb'; -import { createTables, describeTables, getUpdateTableInput, updateTables } from '../../../utils/dynamo-db/utils'; -import { createAndUpdateTable, MockDynamoDBConfig } from '../../../utils/dynamo-db'; - -jest.mock('../../../utils/dynamo-db/utils'); - -describe('createAndUpdateTable', () => { - const table1Input: CreateTableInput = { - TableName: 'table1', - AttributeDefinitions: [ - { - AttributeName: 'id', - AttributeType: 'S', - }, - { - AttributeName: 'name', - AttributeType: 'S', - }, - ], - KeySchema: [ - { - AttributeName: 'id', - KeyType: 'HASH', - }, - ], - }; - - const indexByName: GlobalSecondaryIndex = { - IndexName: 'byName', - KeySchema: [ - { - AttributeName: 'name', - KeyType: 'HASH', - }, - ], - - Projection: { - ProjectionType: 'ALL', - }, - }; - const indexByContent: GlobalSecondaryIndex = { - IndexName: 'index1', - KeySchema: [ - { - AttributeName: 'content', - KeyType: 'HASH', - }, - ], - - Projection: { - ProjectionType: 'ALL', - }, - }; - - const table2Input: CreateTableInput = { - ...table1Input, - AttributeDefinitions: [ - ...table1Input.AttributeDefinitions, - { - AttributeName: 'content', - AttributeType: 'S', - }, - ], - TableName: 'table2', - GlobalSecondaryIndexes: [indexByName, indexByContent], - }; - const listTablesMock = jest.fn(); - - beforeEach(() => { - jest.resetAllMocks(); - jest.useFakeTimers(); - AWSMock.setSDKInstance(AWS); - AWSMock.mock('DynamoDB', 'listTables', listTablesMock); - }); - - it('should create new tables when they are missing', async () => { - const mockDDBConfig: MockDynamoDBConfig = { - tables: [{ Properties: table1Input }], - }; - listTablesMock.mockImplementation((cb) => { - cb(null, { - TableNames: [], - }); - }); - (describeTables as jest.Mock).mockReturnValue({}); - const client = new DynamoDB(); - await createAndUpdateTable(client, mockDDBConfig); - expect(createTables).toHaveBeenCalledWith(client, [table1Input]); - expect(getUpdateTableInput).not.toHaveBeenCalled(); - expect(updateTables).toHaveBeenCalledWith(client, []); - }); - - it('should update existing table with new GSI', async () => { - const mockDDBConfig: MockDynamoDBConfig = { - tables: [{ Properties: table1Input }, { Properties: table2Input }], - }; - - listTablesMock.mockImplementation((cb) => { - cb(null, { - TableNames: [table1Input.TableName, table2Input.TableName], - }); - }); - - (describeTables as jest.Mock).mockReturnValue({ - [table1Input.TableName]: table1Input.TableName, - [table2Input.TableName]: { ...table2Input, GlobalSecondaryIndex: [] }, - }); - const getUpdateTableInputResult = [ - { - ...table2Input, - GlobalSecondaryUpdate: { - Create: [table2Input.GlobalSecondaryIndexes[0]], - }, - }, - { - ...table2Input, - GlobalSecondaryUpdate: { - Create: [table2Input.GlobalSecondaryIndexes[1]], - }, - }, - ]; - - (getUpdateTableInput as jest.Mock).mockImplementation((input) => (input === table2Input ? getUpdateTableInputResult : [])); - - const client = new DynamoDB(); - await createAndUpdateTable(client, mockDDBConfig); - expect(createTables).toHaveBeenCalledWith(client, []); - expect(getUpdateTableInput).toHaveBeenCalledWith(table2Input, { ...table2Input, GlobalSecondaryIndex: [] }); - expect(updateTables).toHaveBeenCalledWith(client, getUpdateTableInputResult); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/utils/dynamo-db/util.test.ts b/packages/amplify-util-mock/src/__tests__/utils/dynamo-db/util.test.ts deleted file mode 100644 index 7124d0edc0..0000000000 --- a/packages/amplify-util-mock/src/__tests__/utils/dynamo-db/util.test.ts +++ /dev/null @@ -1,348 +0,0 @@ -import * as AWSMock from 'aws-sdk-mock'; -import * as AWS from 'aws-sdk'; -import { DescribeTableOutput, CreateTableInput, UpdateTableInput, UpdateTableOutput, TableDescription } from 'aws-sdk/clients/dynamodb'; -import * as ddbUtils from '../../../utils/dynamo-db/utils'; -import { waitTillTableStateIsActive } from '../../../utils/dynamo-db/helpers'; - -jest.mock('../../../utils/dynamo-db/helpers'); - -describe('DynamoDB Utils', () => { - beforeEach(() => { - jest.resetAllMocks(); - AWSMock.setSDKInstance(AWS); - }); - - describe('describeTables', () => { - const describeTableMock = jest.fn(); - beforeEach(() => { - AWSMock.mock('DynamoDB', 'describeTable', describeTableMock); - }); - - it('should call call DynamoDB Clients describe table and collect the results', async () => { - const tableNames = ['table1', 'table2']; - const describeTableResult: Record = { - table1: { - Table: { - TableName: 'table1', - KeySchema: [ - { - AttributeName: 'id', - KeyType: 'HASH', - }, - { - AttributeName: 'createdAt', - KeyType: 'RANGE', - }, - ], - GlobalSecondaryIndexes: [ - { - IndexName: 'index1', - Projection: { - ProjectionType: 'ALL', - }, - }, - ], - }, - }, - table2: { - Table: { - TableName: 'table2', - KeySchema: [ - { - AttributeName: 'table2_id', - KeyType: 'HASH', - }, - { - AttributeName: 'createdAt', - KeyType: 'RANGE', - }, - ], - GlobalSecondaryIndexes: [ - { - IndexName: 'index2', - Projection: { - ProjectionType: 'ALL', - }, - }, - ], - }, - }, - }; - describeTableMock.mockImplementation((params, cb) => { - const tableName = params.TableName; - cb(null, describeTableResult[tableName]); - }); - const client = new AWS.DynamoDB(); - await expect(ddbUtils.describeTables(client, tableNames)).resolves.toEqual({ - table1: describeTableResult.table1.Table, - table2: describeTableResult.table2.Table, - }); - expect(describeTableMock).toHaveBeenCalledTimes(2); - expect(describeTableMock.mock.calls[0][0]).toEqual({ TableName: 'table1' }); - expect(describeTableMock.mock.calls[1][0]).toEqual({ TableName: 'table2' }); - }); - }); - - describe('createTables', () => { - const createTableMock = jest.fn(); - beforeEach(() => { - AWSMock.mock('DynamoDB', 'createTable', createTableMock); - }); - - it('should call createTable for each table', async () => { - createTableMock.mockImplementation((params, cb) => { - const tableName = params.TableName; - cb(null, null); - }); - - const tableInputs: CreateTableInput[] = [ - { - TableName: 'table1', - AttributeDefinitions: [ - { - AttributeName: 'id', - AttributeType: 'S', - }, - ], - KeySchema: [ - { - AttributeName: 'id', - KeyType: 'HASH', - }, - ], - }, - { - TableName: 'table2', - AttributeDefinitions: [ - { - AttributeName: 'id', - AttributeType: 'S', - }, - ], - KeySchema: [ - { - AttributeName: 'id', - KeyType: 'HASH', - }, - ], - }, - ]; - const client = new AWS.DynamoDB(); - await ddbUtils.createTables(client, tableInputs); - expect(createTableMock).toHaveBeenCalledTimes(2); - expect(createTableMock.mock.calls[0][0]).toEqual(tableInputs[0]); - expect(createTableMock.mock.calls[1][0]).toEqual(tableInputs[1]); - }); - }); - - describe('updateTables', () => { - const updateTableMock = jest.fn(); - const describeTableMock = jest.fn(); - beforeEach(() => { - AWSMock.mock('DynamoDB', 'updateTable', updateTableMock); - AWSMock.mock('DynamoDB', 'describeTable', describeTableMock); - }); - - it('should wait for table to be in ACTIVE state before updating', async () => { - const waitTillTableStateIsActiveMock = (waitTillTableStateIsActive as jest.Mock).mockResolvedValue(undefined); - updateTableMock.mockImplementation(({ TableName, AttributeDefinitions, GlobalSecondaryIndexUpdates }: UpdateTableInput, cb) => { - const response: UpdateTableOutput = { - TableDescription: { - TableName, - AttributeDefinitions, - GlobalSecondaryIndexes: GlobalSecondaryIndexUpdates.filter((update) => update.Create).map((gsi) => gsi.Update), - }, - }; - cb(null, response); - }); - const tables: UpdateTableInput[] = [ - { - TableName: 'table1', - AttributeDefinitions: [ - { - AttributeName: 'id', - AttributeType: 'S', - }, - ], - GlobalSecondaryIndexUpdates: [ - { - Create: { - IndexName: 'idx1', - KeySchema: [ - { - AttributeName: 'id', - KeyType: 'HASH', - }, - ], - Projection: { ProjectionType: 'ALL' }, - }, - }, - ], - }, - { - TableName: 'table1', - AttributeDefinitions: [ - { - AttributeName: 'id', - AttributeType: 'S', - }, - { - AttributeName: 'createdAt', - AttributeType: 'S', - }, - ], - GlobalSecondaryIndexUpdates: [ - { - Create: { - IndexName: 'byCreatedDate', - KeySchema: [ - { - AttributeName: 'id', - KeyType: 'HASH', - }, - { - AttributeName: 'createdAt', - KeyType: 'SORT', - }, - ], - Projection: { ProjectionType: 'ALL' }, - }, - }, - ], - }, - ]; - const client = new AWS.DynamoDB(); - const updatePromise = ddbUtils.updateTables(client, tables); - await updatePromise; - - expect(updateTableMock).toHaveBeenCalledTimes(2); - expect(updateTableMock.mock.calls[0][0]).toEqual(tables[0]); - expect(updateTableMock.mock.calls[1][0]).toEqual(tables[1]); - - expect(waitTillTableStateIsActiveMock).toHaveBeenCalledTimes(2); - expect(waitTillTableStateIsActiveMock).toHaveBeenNthCalledWith(1, client, tables[0].TableName); - expect(waitTillTableStateIsActiveMock).toHaveBeenNthCalledWith(2, client, tables[1].TableName); - }); - }); - - describe('getUpdateTableInput', () => { - const baseSchema = { - TableName: 'table1', - AttributeDefinitions: [ - { - AttributeName: 'id', - AttributeType: 'S', - }, - { - AttributeName: 'Name', - AttributeType: 'S', - }, - { - AttributeName: 'Address', - AttributeType: 'S', - }, - ], - KeySchema: [ - { - AttributeName: 'id', - KeyType: 'HASH', - }, - ], - }; - const existingIndex = { - IndexName: 'existingIndex', - KeySchema: [ - { - AttributeName: 'address', - KeyType: 'HASH', - }, - ], - Projection: { - ProjectionType: 'ALL', - }, - }; - const newIndex = { - IndexName: 'newIndex1', - KeySchema: [ - { - AttributeName: 'name', - KeyType: 'HASH', - }, - ], - Projection: { - ProjectionType: 'ALL', - }, - }; - it('should add a new index', () => { - const createTableInput: CreateTableInput = { - ...baseSchema, - GlobalSecondaryIndexes: [newIndex, existingIndex], - }; - const existingTableConfig: TableDescription = { - ...baseSchema, - GlobalSecondaryIndexes: [existingIndex], - }; - - const updateInput = ddbUtils.getUpdateTableInput(createTableInput, existingTableConfig); - expect(updateInput).toHaveLength(1); - expect(updateInput[0].TableName).toEqual(baseSchema.TableName); - expect(updateInput[0].AttributeDefinitions).toEqual(baseSchema.AttributeDefinitions); - expect(updateInput[0].GlobalSecondaryIndexUpdates).toEqual([ - { - Create: newIndex, - }, - ]); - }); - it('should delete a new index', () => { - const createTableInput: CreateTableInput = { - ...baseSchema, - }; - const existingTableConfig: TableDescription = { - ...baseSchema, - GlobalSecondaryIndexes: [existingIndex], - }; - const updateInput = ddbUtils.getUpdateTableInput(createTableInput, existingTableConfig); - expect(updateInput[0].GlobalSecondaryIndexUpdates).toEqual([ - { - Delete: { IndexName: existingIndex.IndexName }, - }, - ]); - }); - - it('should throw error if the table names dont match', () => { - const createTableInput: CreateTableInput = { - ...baseSchema, - TableName: 'different-name', - }; - const existingTableConfig: TableDescription = { - ...baseSchema, - GlobalSecondaryIndexes: [existingIndex], - }; - expect(() => ddbUtils.getUpdateTableInput(createTableInput, existingTableConfig)).toThrowError('Invalid input, table name mismatch'); - }); - - it('should generate sepearate inputs when there is an addition and deletion of index', () => { - const createTableInput: CreateTableInput = { - ...baseSchema, - GlobalSecondaryIndexes: [newIndex], - }; - const existingTableConfig: TableDescription = { - ...baseSchema, - GlobalSecondaryIndexes: [existingIndex], - }; - const updateInput = ddbUtils.getUpdateTableInput(createTableInput, existingTableConfig); - expect(updateInput).toHaveLength(2); - expect(updateInput[0].GlobalSecondaryIndexUpdates).toEqual([ - { - Delete: { IndexName: existingIndex.IndexName }, - }, - ]); - - expect(updateInput[1].GlobalSecondaryIndexUpdates).toEqual([ - { - Create: newIndex, - }, - ]); - }); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/utils/index.test.ts b/packages/amplify-util-mock/src/__tests__/utils/index.test.ts deleted file mode 100644 index 474cbb8f80..0000000000 --- a/packages/amplify-util-mock/src/__tests__/utils/index.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { fail } from 'assert'; -import { describe } from 'jest-circus'; -import semver = require('semver/preload'); -import { _isUnsupportedJavaVersion } from '../../utils'; - -type JavaCondition = { - name: string; - unsupported: boolean; - javaOpts: string | null; - versionString: string | null; -}; - -describe('isUnsupportedJavaVersion', () => { - const javas: Array = [ - { - javaOpts: null, - name: '7u79', - unsupported: true, - versionString: `java version "1.7.0_79" -Java(TM) SE Runtime Environment (build 1.7.0_79-b15) -Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode)`, - }, - { - javaOpts: null, - name: '8u131', - unsupported: false, - versionString: `java version "1.8.0_131" -Java(TM) SE Runtime Environment (build 1.8.0_131-b11) -Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)`, - }, - { - javaOpts: 'Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8', - name: '8u131', - unsupported: false, - versionString: `java version "1.8.0_131" -Java(TM) SE Runtime Environment (build 1.8.0_131-b11) -Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)`, - }, - { - javaOpts: null, - name: '8.0.265-amzn', - unsupported: false, - versionString: `openjdk version "1.8.0_265" -OpenJDK Runtime Environment Corretto-8.265.01.1 (build 1.8.0_265-b01) -OpenJDK 64-Bit Server VM Corretto-8.265.01.1 (build 25.265-b01, mixed mode)`, - }, - { - javaOpts: null, - name: '11.0.0-open', - unsupported: false, - versionString: `openjdk version "11" 2018-09-25 -OpenJDK Runtime Environment 18.9 (build 11+28) -OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)`, - }, - { - javaOpts: 'Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8', - name: '11.0.0-open', - unsupported: false, - versionString: `openjdk version "11" 2018-09-25 -OpenJDK Runtime Environment 18.9 (build 11+28) -OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)`, - }, - { - javaOpts: null, - name: '11.0.0-librca', - unsupported: false, - versionString: `openjdk version "11-BellSoft" 2018-09-25 -OpenJDK Runtime Environment (build 11-BellSoft+0) -OpenJDK 64-Bit Server VM (build 11-BellSoft+0, mixed mode)`, - }, - { - javaOpts: null, - name: '11.0.3-librca', - unsupported: false, - versionString: `openjdk version "11.0.3-BellSoft" 2019-04-16 -LibericaJDK Runtime Environment (build 11.0.3-BellSoft+12) -LibericaJDK 64-Bit Server VM (build 11.0.3-BellSoft+12, mixed mode)`, - }, - { - javaOpts: null, - name: 'uninstalled', - unsupported: true, - versionString: null, - }, - ]; - - javas.forEach((java) => { - it(`should return ${java.unsupported} on java ${java.name} with JAVA_OPTS: ${java.javaOpts != null}`, () => { - const stderr: string = [java.javaOpts, java.versionString].filter((text) => text != null).join('\n'); - const actual = _isUnsupportedJavaVersion(stderr === '' ? null : stderr); - expect(actual).toBe(java.unsupported); - }); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/utils/lambda/populate-cfn-params.test.ts b/packages/amplify-util-mock/src/__tests__/utils/lambda/populate-cfn-params.test.ts deleted file mode 100644 index bd748d900a..0000000000 --- a/packages/amplify-util-mock/src/__tests__/utils/lambda/populate-cfn-params.test.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { stateManager } from '@aws-amplify/amplify-cli-core'; -import _ from 'lodash'; -import { populateCfnParams } from '../../../utils/lambda/populate-cfn-params'; - -jest.mock('@aws-amplify/amplify-cli-core'); -jest.mock('../../../api/api', () => ({ - GRAPHQL_API_ENDPOINT_OUTPUT: 'GraphQLAPIEndpointOutput', - GRAPHQL_API_KEY_OUTPUT: 'GraphQLAPIKeyOutput', - MOCK_API_KEY: 'da2-fakeApiId123456', - MOCK_API_PORT: '666', -})); - -const stateManager_mock = stateManager as jest.Mocked; - -stateManager_mock.getLocalEnvInfo.mockReturnValue({ - envName: 'test', -}); - -const teamProviderParam = { - anotherCfnParam: 'testValue', -}; -stateManager_mock.getTeamProviderInfo.mockReturnValue({ - test: { - awscloudformation: { - Region: 'test-region', - StackId: 'arn:aws:cloudformation:us-test-1:1234:stack/my-test-stack', - StackName: 'test-stack-name', - }, - categories: { - function: { - func1: teamProviderParam, - }, - }, - }, -}); - -const meta_stub = { - function: { - func1: { - dependsOn: [ - { - category: 'storage', - resourceName: 'mytable', - attributes: ['tableName', 'tableArn'], - }, - { - category: 'api', - resourceName: 'myApi', - attributes: ['apiName'], - }, - ], - }, - }, - storage: { - mytable: { - output: { - tableName: 'testTableName', - tableArn: 'testTableArn', - }, - }, - }, - api: { - myApi: { - output: { - apiName: 'testApiName', - apiEndpoint: 'testApiEndpoint', - }, - }, - }, -}; - -describe('populate cfn params', () => { - it('includes CFN pseudo parameters', () => { - expect(populateCfnParams({} as any, undefined)).toMatchObject({ - env: 'test', - 'AWS::Region': 'test-region', - 'AWS::AccountId': '1234', - 'AWS::StackId': 'arn:aws:cloudformation:us-test-1:1234:stack/my-test-stack', - 'AWS::StackName': 'test-stack-name', - 'AWS::URLSuffix': 'amazonaws.com', - }); - }); - - it('falls back to default pseudo params when not in team provider', () => { - stateManager_mock.getTeamProviderInfo.mockReturnValueOnce({ - test: { - awscloudformation: {}, - }, - }); - - expect(populateCfnParams({} as any, undefined)).toMatchObject({ - env: 'test', - 'AWS::Region': 'us-test-1', - 'AWS::AccountId': '12345678910', - 'AWS::StackId': 'fake-stack-id', - 'AWS::StackName': 'local-testing', - 'AWS::URLSuffix': 'amazonaws.com', - }); - }); - - it('gets dependsOn params from amplify-meta', () => { - stateManager_mock.getMeta.mockReturnValueOnce(meta_stub); - expect(populateCfnParams({} as any, 'func1')).toMatchObject({ - apimyApiapiName: 'testApiName', - storagemytabletableName: 'testTableName', - storagemytabletableArn: 'testTableArn', - }); - }); - - it('overwrites api endpoint url when specified', () => { - const meta_stub_copy = _.cloneDeep(meta_stub); - meta_stub_copy.function.func1.dependsOn[1].attributes.push('GraphQLAPIEndpointOutput'); - stateManager_mock.getMeta.mockReturnValueOnce(meta_stub_copy); - expect(populateCfnParams({ warning: jest.fn() } as any, 'func1', true)).toMatchObject({ - apimyApiGraphQLAPIEndpointOutput: `http://localhost:666/graphql`, - }); - }); - - it('overwrites api key when specified', () => { - const meta_stub_copy = _.cloneDeep(meta_stub); - meta_stub_copy.function.func1.dependsOn[1].attributes.push('GraphQLAPIKeyOutput'); - stateManager_mock.getMeta.mockReturnValueOnce(meta_stub_copy); - expect(populateCfnParams({ warning: jest.fn() } as any, 'func1', true)).toMatchObject({ - apimyApiGraphQLAPIKeyOutput: 'da2-fakeApiId123456', - }); - }); - - it('prints warning when no value found', () => { - const meta_stub_copy = _.cloneDeep(meta_stub); - meta_stub_copy.function.func1.dependsOn[1].attributes.push('GraphQLAPIEndpointOutput'); - stateManager_mock.getMeta.mockReturnValueOnce(meta_stub_copy); - const warningMock = jest.fn(); - const result = populateCfnParams({ warning: warningMock } as any, 'func1'); - expect(typeof result).toBe('object'); - expect(result.apimyApiGraphQLAPIEndpointOutput).toBeUndefined(); - expect(warningMock.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - "No output found for attribute 'GraphQLAPIEndpointOutput' on resource 'myApi' in category 'api'", - ], - Array [ - "This attribute will be undefined in the mock environment until you run \`amplify push\`", - ], - ] - `); - }); - - it('includes params from parameters.json', () => { - const expectedMap = { - someOtherParam: 'this is the value', - }; - stateManager_mock.getResourceParametersJson.mockReturnValueOnce(expectedMap); - expect(populateCfnParams({} as any, 'func1')).toMatchObject(expectedMap); - }); - - it('includes params from team-provider-info.json', () => { - expect(populateCfnParams({} as any, 'func1')).toMatchObject(teamProviderParam); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/utils/lambda/populate-lambda-mock-env-vars.test.ts b/packages/amplify-util-mock/src/__tests__/utils/lambda/populate-lambda-mock-env-vars.test.ts deleted file mode 100644 index 253fc74099..0000000000 --- a/packages/amplify-util-mock/src/__tests__/utils/lambda/populate-lambda-mock-env-vars.test.ts +++ /dev/null @@ -1,90 +0,0 @@ -import * as path from 'path'; -import { loadConfigurationForEnv } from '@aws-amplify/amplify-provider-awscloudformation'; -import { stateManager, pathManager, $TSContext } from '@aws-amplify/amplify-cli-core'; -import * as dotenv from 'dotenv'; -import { ProcessedLambdaFunction } from '../../../CFNParser/stack/types'; -import { populateLambdaMockEnvVars } from '../../../utils/lambda/populate-lambda-mock-env-vars'; - -jest.mock('@aws-amplify/amplify-provider-awscloudformation'); -jest.mock('@aws-amplify/amplify-cli-core'); -jest.mock('dotenv'); - -const loadConfigurationForEnv_mock = loadConfigurationForEnv as jest.MockedFunction; -loadConfigurationForEnv_mock.mockResolvedValue({ - accessKeyId: 'testaccesskey', - secretAccessKey: 'testsecretaccesskey', - sessionToken: 'testsessiontoken', - region: 'test-region', -}); - -const stateManager_mock = stateManager as jest.Mocked; -stateManager_mock.getLocalEnvInfo.mockReturnValue({ envName: 'test' }); - -const pathManager_mock = pathManager as jest.Mocked; -pathManager_mock.getBackendDirPath.mockReturnValue('backend/path'); - -const dotenv_mock = dotenv as jest.Mocked; - -describe('populate labmda mock env vars', () => { - beforeEach(() => jest.clearAllMocks()); - it('populates AWS credential variables', async () => { - const processedLambda: ProcessedLambdaFunction = { - cfnExposedAttributes: {}, - name: 'testLambda', - handler: 'test.handler', - environment: {}, - }; - - await populateLambdaMockEnvVars({} as $TSContext, processedLambda); - expect(processedLambda.environment).toMatchObject({ - AWS_ACCESS_KEY_ID: 'testaccesskey', - AWS_SECRET_ACCESS_KEY: 'testsecretaccesskey', - AWS_SESSION_TOKEN: 'testsessiontoken', - }); - }); - - it('loads dynamic defaults', async () => { - const processedLambda: ProcessedLambdaFunction = { - cfnExposedAttributes: {}, - name: 'testLambda', - handler: 'test.handler', - environment: {}, - }; - stateManager_mock.getTeamProviderInfo.mockReturnValueOnce({ - test: { - awscloudformation: { - Region: 'test-region', - }, - }, - }); - const expectedPath = path.join('backend/path', 'function', processedLambda.name); - - await populateLambdaMockEnvVars({} as $TSContext, processedLambda); - expect(processedLambda.environment).toMatchObject({ - _HANDLER: processedLambda.handler, - AWS_REGION: 'test-region', - AWS_LAMBDA_FUNCTION_NAME: processedLambda.name, - LAMBDA_TASK_ROOT: expectedPath, - LAMBDA_RUNTIME_DIR: expectedPath, - }); - }); - - it('loads dot env values', async () => { - const processedLambda: ProcessedLambdaFunction = { - cfnExposedAttributes: {}, - name: 'testLambda', - handler: 'test.handler', - environment: {}, - }; - const expectedMap = { - CUSTOM_MOCK_ENV_VAR: 'some value', - }; - pathManager_mock.getBackendDirPath.mockReturnValueOnce('backend/path'); - dotenv_mock.config.mockReturnValueOnce({ - parsed: expectedMap, - }); - - await populateLambdaMockEnvVars({} as $TSContext, processedLambda); - expect(processedLambda.environment).toMatchObject(expectedMap); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/velocity/acm-resolver-auth.test.ts b/packages/amplify-util-mock/src/__tests__/velocity/acm-resolver-auth.test.ts deleted file mode 100644 index d3d50da283..0000000000 --- a/packages/amplify-util-mock/src/__tests__/velocity/acm-resolver-auth.test.ts +++ /dev/null @@ -1,282 +0,0 @@ -import { AuthProvider, AuthStrategy, AuthTransformer, ModelOperation } from '@aws-amplify/graphql-auth-transformer'; -import { AppSyncGraphQLExecutionContext } from '@aws-amplify/amplify-appsync-simulator/lib/utils/graphql-runner'; -import { AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; -import { testTransform } from '@aws-amplify/graphql-transformer-test-utils'; -import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; -import { AmplifyAppSyncSimulatorAuthenticationType } from '@aws-amplify/amplify-appsync-simulator'; -import { plurality } from 'graphql-transformer-common'; -import { PrimaryKeyTransformer } from '@aws-amplify/graphql-index-transformer'; -import { AppSyncVTLContext, getGenericToken, getIAMToken, getJWTToken, VelocityTemplateSimulator } from '../../velocity'; - -const USER_POOL_ID = 'us-fake-1ID'; - -const authConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { authenticationType: 'AWS_IAM' }, - { authenticationType: 'API_KEY' }, - { - authenticationType: 'OPENID_CONNECT', - openIDConnectConfig: { - name: 'myOIDCProvider', - issuerUrl: 'https://some-oidc-provider/auth', - clientId: 'my-sample-client-id', - }, - }, - { - authenticationType: 'AWS_LAMBDA', - lambdaAuthorizerConfig: { - lambdaFunction: 'authorize', - ttlSeconds: 600, - }, - }, - ], -}; -const strategyProviders: Record = { - public: ['apiKey', 'iam'], - owner: ['userPools', 'oidc'], - private: ['userPools', 'oidc', 'iam'], - groups: ['userPools', 'oidc'], - custom: ['function'], -}; - -const generateUser = (provider: AuthProvider, strategy: AuthStrategy): AppSyncGraphQLExecutionContext => { - switch (provider) { - case 'apiKey': - return generateAPIKeyContext(); - case 'iam': - return generateIAMContext(strategy); - case 'oidc': - return generateOIDCContext(); - case 'userPools': - return generateUserPoolsContext(); - default: - throw new Error(`'${provider}' auth provider not supported for this test`); - } -}; - -const generateAPIKeyContext = (): AppSyncGraphQLExecutionContext => ({ - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.API_KEY, - headers: { 'x-api-key': 'da-fake-key' }, - appsyncErrors: [], -}); - -const generateIAMContext = (strategy: AuthStrategy): AppSyncGraphQLExecutionContext => ({ - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AWS_IAM, - iamToken: getIAMToken(strategy === 'private' ? 'authRole' : 'unauthRole', { - cognitoIdentityAuthProvider: `cognito-idp.us-fake1.amazonaws.com/${USER_POOL_ID}`, - cognitoIdentityAuthType: strategy === 'private' ? 'authenticated' : 'unauthenticated', - cognitoIdentityPoolId: `${USER_POOL_ID}:000-111-222`, - cognitoIdentityId: 'us-fake-1:000', - }), - headers: {}, -}); - -const generateOIDCContext = (): AppSyncGraphQLExecutionContext => ({ - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.OPENID_CONNECT, - jwt: getGenericToken('user1', 'user1@test.com', ['admins']), - headers: {}, -}); - -const generateUserPoolsContext = (): AppSyncGraphQLExecutionContext => ({ - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user1', 'user1@test.com', ['admins']), - headers: {}, -}); - -const generateInvalidUserPoolsContext = (context: AppSyncGraphQLExecutionContext): AppSyncGraphQLExecutionContext => { - const invalidMode = Object.values(AmplifyAppSyncSimulatorAuthenticationType).find((it) => it !== context.requestAuthorizationMode); - return { - requestAuthorizationMode: invalidMode, - headers: {}, - }; -}; - -const getOperationRelatedTemplates = (operation: ModelOperation, modelName: string): string[] => { - switch (operation) { - case 'create': - return [`Mutation.${operation}${modelName}.auth.1.req.vtl`]; - case 'delete': - case 'update': - return [`Mutation.${operation}${modelName}.auth.1.res.vtl`]; - case 'list': - return [`Query.list${plurality(modelName, true)}.auth.1.req.vtl`]; - case 'get': - return [`Query.get${modelName}.auth.1.req.vtl`]; - default: - throw new Error(`'${operation}' auth operation not supported for this test`); - } -}; - -const generateAuthDirective = (authStrategy: AuthStrategy, authProvider: AuthProvider, operation?: ModelOperation): string => `@auth ( - rules: [ - { - allow: ${authStrategy}, - operations: [${operation ?? ''}], - provider: ${authProvider}, - ${authStrategy === 'groups' ? 'groupsField: "groups",' : ''} - ${authStrategy === 'groups' && authProvider === 'oidc' ? 'groupClaim: "groups",' : ''} - }, - ] - )`; - -const getInputContext = (operation: ModelOperation, authStrategy: AuthStrategy, authProvider: AuthProvider): AppSyncVTLContext => { - const context: AppSyncVTLContext = {}; - switch (operation) { - case 'create': { - Object.assign(context, { - arguments: { - input: { - profileId: '001', - title: 'sample', - firstName: 'Amplify', - lastName: 'CLI', - groups: 'admins', - }, - }, - }); - break; - } - case 'update': { - Object.assign(context, { - result: { - profileId: '001', - title: 'updated', - firstName: 'Amplify', - lastName: 'CLI', - owner: 'user1', - groups: 'admins', - }, - }); - break; - } - case 'delete': { - Object.assign(context, { - result: { - profileId: '001', - firstName: 'Amplify', - lastName: 'CLI', - owner: 'user1', - groups: 'admins', - }, - }); - break; - } - case 'list': - case 'get': - break; - default: - throw new Error(`'${operation}' operation is not supported for this test case`); - } - - if (authProvider === 'iam') { - Object.assign( - context, - authStrategy === 'private' - ? { stash: { authRole: 'arn:aws:sts::123456789012:assumed-role/authRole/CognitoIdentityCredentials' } } - : { stash: { unauthRole: 'arn:aws:sts::123456789012:assumed-role/unauthRole/CognitoIdentityCredentials' } }, - ); - } - - return context; -}; - -const validateRenderTemplate = ( - template: string, - context: AppSyncGraphQLExecutionContext, - operation: ModelOperation, - authStrategy: AuthStrategy, - authProvider: AuthProvider, - hasPartialAccess: boolean, -): void => { - const vtlTemplate: VelocityTemplateSimulator = new VelocityTemplateSimulator({ authConfig }); - const inputContext = getInputContext(operation, authStrategy, authProvider); - - const authorizedRequest = vtlTemplate.render(template, { context: inputContext, requestParameters: context }); - expect(authorizedRequest).toBeDefined(); - expect(authorizedRequest.stash.hasAuth).toEqual(true); - expect(authorizedRequest.args).toBeDefined(); - - // delete should fail all the time if there is partial access to the model - expect(authorizedRequest.hadException).toEqual(!!(hasPartialAccess && operation === 'delete')); - - try { - const unauthorizedRequest = vtlTemplate.render(template, { - context: inputContext, - requestParameters: generateInvalidUserPoolsContext(context), - }); - expect(unauthorizedRequest).toBeDefined(); - expect(unauthorizedRequest.stash.hasAuth).toEqual(true); - expect(unauthorizedRequest.args).toBeDefined(); - expect(unauthorizedRequest.hadException).toEqual(true); - } catch (_) { - // for public apiKey render throws exception - expect(true).toEqual(true); - } -}; - -const testResolverLogic = ( - authStrategy: AuthStrategy, - authProvider: AuthProvider, - context: AppSyncGraphQLExecutionContext, - operation: ModelOperation, - hasPartialAccess = false, - hasCustomPrimaryKey = false, -): void => { - const authRuleDirective = generateAuthDirective(authStrategy, authProvider, operation); - const authRuleDirectiveNoOps = generateAuthDirective(authStrategy, authProvider); - - const validSchema = ` - type Profile @model ${authRuleDirective} { - profileId: ID! ${hasCustomPrimaryKey ? '@primaryKey(sortKeyFields: ["firstName", "lastName"])' : ''} - firstName: String! - lastName: String! - title: String - groups: [String] - ${hasPartialAccess ? `noAccessField: String ${authRuleDirectiveNoOps}` : ''} - }`; - - const out = testTransform({ - schema: validSchema, - authConfig, - transformers: [new ModelTransformer(), new PrimaryKeyTransformer(), new AuthTransformer()], - }); - - const templates = getOperationRelatedTemplates(operation, 'Profile'); - - templates.forEach((templateName) => { - const template = out.resolvers[templateName]; - validateRenderTemplate(template, context, operation, authStrategy, authProvider, hasPartialAccess); - }); -}; - -describe('acm resolver tests', () => { - const authStrategies: AuthStrategy[] = ['owner', 'groups', 'public', 'private']; - authStrategies.forEach((authStrategy) => { - const providers = strategyProviders[authStrategy]; - - providers.forEach((provider) => { - const userContext = generateUser(provider, authStrategy); - const operations: ModelOperation[] = ['create', 'get', 'list', 'update', 'delete']; - operations.forEach((operation) => { - it(`should generate auth resolver logic that passes as expected for '${authStrategy}' strategy using '${provider}' provider running '${operation}' operation`, () => { - testResolverLogic(authStrategy, provider, userContext, operation); - }); - - it(`should generate auth resolver logic that passes as expected for '${authStrategy}' strategy using '${provider}' provider running '${operation}' operation: partial access`, () => { - testResolverLogic(authStrategy, provider, userContext, operation, true); - }); - - it(`should generate auth resolver logic that passes as expected for '${authStrategy}' strategy using '${provider}' provider running '${operation}' operation: custom primary key`, () => { - testResolverLogic(authStrategy, provider, userContext, operation, false, true); - }); - - it(`should generate auth resolver logic that passes as expected for '${authStrategy}' strategy using '${provider}' provider running '${operation}' operation: partial access and custom primary key`, () => { - testResolverLogic(authStrategy, provider, userContext, operation, true, true); - }); - }); - }); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/velocity/admin-auth.test.ts b/packages/amplify-util-mock/src/__tests__/velocity/admin-auth.test.ts deleted file mode 100644 index 32027819f9..0000000000 --- a/packages/amplify-util-mock/src/__tests__/velocity/admin-auth.test.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer'; -import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; -import { AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; -import { AmplifyAppSyncSimulatorAuthenticationType, AppSyncGraphQLExecutionContext } from '@aws-amplify/amplify-appsync-simulator'; -import { testTransform, DeploymentResources } from '@aws-amplify/graphql-transformer-test-utils'; -import { VelocityTemplateSimulator, AppSyncVTLContext, getIAMToken } from '../../velocity'; - -type TestTransform = { - transform: (schema: string) => DeploymentResources; -}; - -jest.mock('@aws-amplify/amplify-prompts'); - -describe('admin roles query checks', () => { - const ADMIN_UI_ROLE = 'us-fake-1_uuid_Full-access/CognitoIdentityCredentials'; - const MOCK_BEFORE_TEMPLATE = `$util.qr($ctx.stash.put("adminRoles", ["${ADMIN_UI_ROLE}"]))`; - - let vtlTemplate: VelocityTemplateSimulator; - let transformer: TestTransform; - const adminFullAccessRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AWS_IAM, - iamToken: getIAMToken('us-fake-1_uuid_Full-access'), - headers: {}, - }; - - beforeEach(() => { - const authConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }; - transformer = { - transform: (schema: string) => - testTransform({ - schema, - authConfig, - synthParameters: { adminRoles: [ADMIN_UI_ROLE] }, - transformers: [new ModelTransformer(), new AuthTransformer()], - }), - }; - - vtlTemplate = new VelocityTemplateSimulator({ authConfig }); - }); - - test('schema with field auth', () => { - const validSchema = ` - type Student @model @auth(rules: [{ allow: groups, groups: ["staff"] }, { allow: owner }]) { - id: ID! - name: String - description: String - secretValue: String @auth(rules: [{ allow: owner }]) - }`; - const out = transformer.transform(validSchema); - - // field resolver - const secretValueTemplate = [MOCK_BEFORE_TEMPLATE, out.resolvers['Student.secretValue.req.vtl']].join('\n'); - const iamFieldContext: AppSyncVTLContext = { - source: { - secretValue: 'secretValue001', - }, - }; - - const secretValueResponse = vtlTemplate.render(secretValueTemplate, { - context: iamFieldContext, - requestParameters: adminFullAccessRequest, - }); - expect(secretValueResponse.hadException).toEqual(false); - expect(secretValueResponse.result).toEqual('secretValue001'); - - // mutation resolver - const createStudentTemplate = [MOCK_BEFORE_TEMPLATE, out.resolvers['Mutation.createStudent.auth.1.req.vtl']].join('\n'); - const iamCreateContext: AppSyncVTLContext = { - arguments: { - input: { - id: '001', - name: 'student0', - owner: 'student0', - }, - }, - }; - const createStudentResponse = vtlTemplate.render(createStudentTemplate, { - context: iamCreateContext, - requestParameters: adminFullAccessRequest, - }); - - expect(createStudentResponse.hadException).toEqual(false); - // we can exit early with a object since the next function will run the mutation request - expect(createStudentResponse.result).toEqual('{}'); - }); -}); - -describe('identity claim feature flag disabled', () => { - describe('admin roles query checks', () => { - const ADMIN_UI_ROLE = 'us-fake-1_uuid_Full-access/CognitoIdentityCredentials'; - const MOCK_BEFORE_TEMPLATE = `$util.qr($ctx.stash.put("adminRoles", ["${ADMIN_UI_ROLE}"]))`; - - let vtlTemplate: VelocityTemplateSimulator; - let transformer: TestTransform; - const adminFullAccessRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AWS_IAM, - iamToken: getIAMToken('us-fake-1_uuid_Full-access'), - headers: {}, - }; - - beforeEach(() => { - const authConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }; - transformer = { - transform: (schema: string) => - testTransform({ - schema, - authConfig, - synthParameters: { adminRoles: [ADMIN_UI_ROLE] }, - transformers: [new ModelTransformer(), new AuthTransformer()], - }), - }; - - vtlTemplate = new VelocityTemplateSimulator({ authConfig }); - }); - - test('schema with field auth', () => { - const validSchema = ` - type Student @model @auth(rules: [{ allow: groups, groups: ["staff"] }, { allow: owner }]) { - id: ID! - name: String - description: String - secretValue: String @auth(rules: [{ allow: owner }]) - }`; - const out = transformer.transform(validSchema); - - // field resolver - const secretValueTemplate = [MOCK_BEFORE_TEMPLATE, out.resolvers['Student.secretValue.req.vtl']].join('\n'); - const iamFieldContext: AppSyncVTLContext = { - source: { - secretValue: 'secretValue001', - }, - }; - - const secretValueResponse = vtlTemplate.render(secretValueTemplate, { - context: iamFieldContext, - requestParameters: adminFullAccessRequest, - }); - expect(secretValueResponse.hadException).toEqual(false); - expect(secretValueResponse.result).toEqual('secretValue001'); - - // mutation resolver - const createStudentTemplate = [MOCK_BEFORE_TEMPLATE, out.resolvers['Mutation.createStudent.auth.1.req.vtl']].join('\n'); - const iamCreateContext: AppSyncVTLContext = { - arguments: { - input: { - id: '001', - name: 'student0', - owner: 'student0', - }, - }, - }; - const createStudentResponse = vtlTemplate.render(createStudentTemplate, { - context: iamCreateContext, - requestParameters: adminFullAccessRequest, - }); - - expect(createStudentResponse.hadException).toEqual(false); - // we can exit early with a object since the next function will run the mutation request - expect(createStudentResponse.result).toEqual('{}'); - }); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/velocity/model-auth.test.ts b/packages/amplify-util-mock/src/__tests__/velocity/model-auth.test.ts deleted file mode 100644 index 864d83ab71..0000000000 --- a/packages/amplify-util-mock/src/__tests__/velocity/model-auth.test.ts +++ /dev/null @@ -1,1629 +0,0 @@ -import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer'; -import { IndexTransformer, PrimaryKeyTransformer } from '@aws-amplify/graphql-index-transformer'; -import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; -import { AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; -import { AmplifyAppSyncSimulatorAuthenticationType, AppSyncGraphQLExecutionContext } from '@aws-amplify/amplify-appsync-simulator'; -import { DeploymentResources, testTransform } from '@aws-amplify/graphql-transformer-test-utils'; -import { VelocityTemplateSimulator, AppSyncVTLContext, getJWTToken } from '../../velocity'; - -type TestTransform = { - transform: (schema: string) => DeploymentResources; -}; - -jest.mock('@aws-amplify/amplify-prompts'); - -const USER_POOL_ID = 'us-fake-1ID'; - -describe('@model owner mutation checks', () => { - let vtlTemplate: VelocityTemplateSimulator; - let transformer: TestTransform; - const ownerRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user1', 'user1@test.com'), - headers: {}, - sourceIp: '', - }; - - beforeEach(() => { - const authConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }; - transformer = { - transform: (schema: string) => - testTransform({ - schema, - authConfig, - transformers: [new ModelTransformer(), new AuthTransformer()], - }), - }; - vtlTemplate = new VelocityTemplateSimulator({ authConfig }); - }); - - test('implicit owner with default owner field', () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner }]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - }`; - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // create the owner type - const ownerContext: AppSyncVTLContext = { - arguments: { input: { id: '001', title: 'sample' } }, - }; - - // expect the query resolver to contain a filter for the owner - const queryTemplate = out.resolvers['Query.listPosts.auth.1.req.vtl']; - const queryResponse = vtlTemplate.render(queryTemplate, { context: {}, requestParameters: ownerRequest }); - expect(queryResponse).toBeDefined(); - expect(queryResponse.stash.hasAuth).toEqual(true); - expect(queryResponse.stash.authFilter).toEqual( - expect.objectContaining({ - or: [{ owner: { eq: `${ownerRequest.jwt.sub}::user1` } }, { owner: { eq: `${ownerRequest.jwt.sub}` } }, { owner: { eq: 'user1' } }], - }), - ); - - const createRequestTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const createVTLRequest = vtlTemplate.render(createRequestTemplate, { context: ownerContext, requestParameters: ownerRequest }); - expect(createVTLRequest).toBeDefined(); - expect(createVTLRequest.stash.hasAuth).toEqual(true); - expect(createVTLRequest.args).toBeDefined(); - expect(createVTLRequest.hadException).toEqual(false); - // since we have an owner rule we expect the owner field to be defined in the argument input - expect(createVTLRequest.args.input.owner).toEqual(`${ownerRequest.jwt.sub}::user1`); - - const updateRequestTemplate = out.resolvers['Mutation.updatePost.auth.1.req.vtl']; - const updateVTLRequest = vtlTemplate.render(updateRequestTemplate, { context: ownerContext, requestParameters: ownerRequest }); - expect(updateVTLRequest).toBeDefined(); - // here we expect a get item payload to verify the owner making the update request is valid - expect(updateVTLRequest.result).toEqual( - expect.objectContaining({ - key: { id: { S: '001' } }, - operation: 'GetItem', - version: '2018-05-29', - }), - ); - // atm there is there is nothing in the stash yet - expect(updateVTLRequest.stash).toEqual({}); - const updateResponseTemplate = out.resolvers['Mutation.updatePost.auth.1.res.vtl']; - // response where the owner is indeed the owner - const updateVTLResponse = vtlTemplate.render(updateResponseTemplate, { - context: { ...ownerContext, result: { id: '001', owner: 'user1' } }, - requestParameters: ownerRequest, - }); - expect(updateVTLResponse).toBeDefined(); - - expect(updateVTLResponse.hadException).toEqual(false); - expect(updateVTLResponse.stash.hasAuth).toEqual(true); - // response where there is an error - const updateVTLWithError = vtlTemplate.render(updateResponseTemplate, { - context: { ...ownerContext, result: { id: '001', owner: 'user2' } }, - requestParameters: ownerRequest, - }); - expect(updateVTLWithError).toBeDefined(); - expect(updateVTLWithError.hadException).toEqual(true); - expect(updateVTLWithError.errors).toHaveLength(1); - expect(updateVTLWithError.errors[0]).toEqual( - expect.objectContaining({ - errorType: 'Unauthorized', - message: expect.stringContaining('Unauthorized on $util.unauthorized()'), - }), - ); - }); - - test('implicit owner with custom field', () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner, ownerField: "editor" }]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - }`; - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // create context and request - const ownerContext: AppSyncVTLContext = { - arguments: { input: { id: '001', title: 'sample' } }, - }; - - const createRequestTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const createVTLRequest = vtlTemplate.render(createRequestTemplate, { context: ownerContext, requestParameters: ownerRequest }); - expect(createVTLRequest).toBeDefined(); - expect(createVTLRequest.stash.hasAuth).toEqual(true); - expect(createVTLRequest.args).toBeDefined(); - expect(createVTLRequest.hadException).toEqual(false); - // since we have an owner rule we expect the owner field to be defined in the argument input - expect(createVTLRequest.args.input.editor).toEqual(`${ownerRequest.jwt.sub}::user1`); - }); - - test('explicit owner with default field', () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner }]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - owner: String - }`; - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // create context and request - const ownerContext: AppSyncVTLContext = { - arguments: { input: { id: '001', title: 'sample' } }, - }; - - const createRequestTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const createVTLRequest = vtlTemplate.render(createRequestTemplate, { context: ownerContext, requestParameters: ownerRequest }); - expect(createVTLRequest).toBeDefined(); - expect(createVTLRequest.stash.hasAuth).toEqual(true); - expect(createVTLRequest.args).toBeDefined(); - expect(createVTLRequest.hadException).toEqual(false); - // since we have an owner rule we expect the owner field to be defined in the argument input - expect(createVTLRequest.args.input.owner).toEqual(`${ownerRequest.jwt.sub}::user1`); - }); - - test('explicit owner with custom field', () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner, ownerField: "editor" }]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - editor: String - }`; - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // create context and request - const ownerContext: AppSyncVTLContext = { - arguments: { input: { id: '001', title: 'sample' } }, - }; - - const createRequestTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const createVTLRequest = vtlTemplate.render(createRequestTemplate, { context: ownerContext, requestParameters: ownerRequest }); - expect(createVTLRequest).toBeDefined(); - expect(createVTLRequest.stash.hasAuth).toEqual(true); - expect(createVTLRequest.args).toBeDefined(); - expect(createVTLRequest.hadException).toEqual(false); - // since we have an owner rule we expect the owner field to be defined in the argument input - expect(createVTLRequest.args.input.editor).toEqual(`${ownerRequest.jwt.sub}::user1`); - - const differentOwnerContext: AppSyncVTLContext = { arguments: { input: { id: '001', title: 'sample', editor: 'user2' } } }; - const createVTLRequestWithErrors = vtlTemplate.render(createRequestTemplate, { - context: differentOwnerContext, - requestParameters: ownerRequest, - }); - expect(createVTLRequestWithErrors).toBeDefined(); - expect(createVTLRequestWithErrors.hadException).toEqual(true); - expect(createVTLRequestWithErrors.errors).toHaveLength(1); - // should fail since the owner in the input is different than what is in the - expect(createVTLRequestWithErrors.errors[0]).toEqual( - expect.objectContaining({ - errorType: 'Unauthorized', - message: expect.stringContaining('Unauthorized on $util.unauthorized()'), - }), - ); - }); - - test('explicit owner using a custom list field', () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner, ownerField: "editors" }]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - editors: [String] - }`; - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // create context and request - const ownerContext: AppSyncVTLContext = { - arguments: { input: { id: '001', title: 'sample' } }, - }; - - const createRequestTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - expect(createRequestTemplate).toBeDefined(); - const createVTLRequest = vtlTemplate.render(createRequestTemplate, { context: ownerContext, requestParameters: ownerRequest }); - expect(createVTLRequest).toBeDefined(); - expect(createVTLRequest.stash.hasAuth).toEqual(true); - expect(createVTLRequest.args).toBeDefined(); - expect(createVTLRequest.hadException).toEqual(false); - // since we have an owner rule we expect the owner field to be defined in the argument input - expect(createVTLRequest.args.input.editors).toEqual([`${ownerRequest.jwt.sub}::user1`]); - - // should fail if the list of users does not contain the currently signed user - const failedCreateVTLRequest = vtlTemplate.render(createRequestTemplate, { - context: { - arguments: { input: { id: '001', title: 'sample', editors: ['user2'] } }, - }, - requestParameters: ownerRequest, - }); - expect(failedCreateVTLRequest.hadException).toEqual(true); - // should fail since the owner in the input is different than what is in the - expect(failedCreateVTLRequest.errors[0]).toEqual( - expect.objectContaining({ - errorType: 'Unauthorized', - message: expect.stringContaining('Unauthorized on $util.unauthorized()'), - }), - ); - }); -}); - -describe('@model operations', () => { - let vtlTemplate: VelocityTemplateSimulator; - let transformer: TestTransform; - const ownerRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user1', 'user1@test.com'), - headers: {}, - sourceIp: '', - }; - const adminGroupRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user2', 'user2@test.com', ['admin']), - headers: {}, - sourceIp: '', - }; - const editorGroupRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user3', 'user3@test.com', ['editor']), - headers: {}, - sourceIp: '', - }; - const createPostInput = (owner?: string): AppSyncVTLContext => ({ - arguments: { - input: { - id: '001', - name: 'sample', - owner, - }, - }, - }); - - beforeEach(() => { - const authConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }; - transformer = { - transform: (schema: string) => - testTransform({ - schema, - authConfig, - transformers: [new ModelTransformer(), new AuthTransformer()], - }), - }; - vtlTemplate = new VelocityTemplateSimulator({ authConfig }); - }); - - test('explicit operations where create/delete restricted', () => { - const validSchema = ` - type Post @model @auth(rules: [ - { allow: owner, operations: [create, read] }, - { allow: groups, groups: ["admin"] }]) { - id: ID - name: String - owner: String - }`; - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // load vtl templates - const createRequestTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const readRequestTemplate = out.resolvers['Query.listPosts.auth.1.req.vtl']; - const updateResponseTemplate = out.resolvers['Mutation.updatePost.auth.1.res.vtl']; - const deleteResponseTemplate = out.resolvers['Mutation.deletePost.auth.1.res.vtl']; - - // run create request as owner and admin - // even though they are not the owner it will still pass as they one making the request is in the admin group - const createRequestAsAdmin = vtlTemplate.render(createRequestTemplate, { - context: createPostInput('owner2'), - requestParameters: adminGroupRequest, - }); - expect(createRequestAsAdmin).toBeDefined(); - expect(createRequestAsAdmin.hadException).toEqual(false); - expect(createRequestAsAdmin.stash.hasAuth).toEqual(true); - // run the create request as owner should fail if the input is different the signed in owner - const createRequestAsOwner = vtlTemplate.render(createRequestTemplate, { - context: createPostInput('user2'), - requestParameters: ownerRequest, - }); - expect(createRequestAsOwner.hadException).toEqual(true); - expect(createRequestAsOwner.errors[0]).toEqual( - expect.objectContaining({ - errorType: 'Unauthorized', - message: expect.stringContaining('Unauthorized on $util.unauthorized()'), - }), - ); - // read request for admin should not contain the filter - const readRequestAsAdmin = vtlTemplate.render(readRequestTemplate, { context: {}, requestParameters: adminGroupRequest }); - expect(readRequestAsAdmin.stash.hasAuth).toEqual(true); - expect(readRequestAsAdmin.stash.authFilter).not.toBeDefined(); - const readRequestAsOwner = vtlTemplate.render(readRequestTemplate, { context: {}, requestParameters: ownerRequest }); - expect(readRequestAsOwner.stash.hasAuth).toEqual(true); - expect(readRequestAsOwner.stash.authFilter).toEqual( - expect.objectContaining({ - or: [{ owner: { eq: `${ownerRequest.jwt.sub}::user1` } }, { owner: { eq: `${ownerRequest.jwt.sub}` } }, { owner: { eq: 'user1' } }], - }), - ); - const ddbResponseResult: AppSyncVTLContext = { result: { id: '001', title: 'sample', owner: 'user1' } }; - // update should pass for admin even if they are not the owner of the record - const updateResponseAsAdmin = vtlTemplate.render(updateResponseTemplate, { - context: ddbResponseResult, - requestParameters: adminGroupRequest, - }); - expect(updateResponseAsAdmin.hadException).toEqual(false); - expect(updateResponseAsAdmin.stash.hasAuth).toEqual(true); - // update should fail for owner even though they are the owner of the record - const updateResponseAsOwner = vtlTemplate.render(updateResponseTemplate, { - context: ddbResponseResult, - requestParameters: ownerRequest, - }); - expect(updateResponseAsOwner.hadException).toEqual(true); - // delete should pass for admin even if they are not the owner of the record - const deleteResponseAsAdmin = vtlTemplate.render(deleteResponseTemplate, { - context: ddbResponseResult, - requestParameters: adminGroupRequest, - }); - expect(deleteResponseAsAdmin.hadException).toEqual(false); - // delete should fail for owner even though they are the owner of the record - const deleteResponseAsOwner = vtlTemplate.render(deleteResponseTemplate, { - context: ddbResponseResult, - requestParameters: ownerRequest, - }); - expect(deleteResponseAsOwner.hadException).toEqual(true); - }); - - test('owner restricts create/read and group restricts read/update/delete', () => { - // NOTE: this means that you can only create a record for the same owner - // you can't create a record for other owners even if your in the editor group - const validSchema = ` - type Post @model @auth(rules: [ - { allow: owner, operations: [create, read] }, - { allow: groups, groups: ["editor"], operations: [read, update, delete] }]) { - id: ID - name: String - owner: String - } - `; - const out = transformer.transform(validSchema); - // load vtl templates - const createRequestTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const readRequestTemplate = out.resolvers['Query.listPosts.auth.1.req.vtl']; - const updateResponseTemplate = out.resolvers['Mutation.updatePost.auth.1.res.vtl']; - const deleteResponseTemplate = out.resolvers['Mutation.deletePost.auth.1.res.vtl']; - - // check that a editor member can't create a post under another owner - const createPostAsEditor = vtlTemplate.render(createRequestTemplate, { - context: createPostInput('user1'), - requestParameters: editorGroupRequest, - }); - expect(createPostAsEditor.hadException).toEqual(true); - // check that editor can read posts with no filter - const readPostsAsEditor = vtlTemplate.render(readRequestTemplate, { context: {}, requestParameters: editorGroupRequest }); - expect(readPostsAsEditor.hadException).toEqual(false); - expect(readPostsAsEditor.stash.authFilter).not.toBeDefined(); - // expect owner can read but with an auth filter - const readPostsAsOwner = vtlTemplate.render(readRequestTemplate, { context: {}, requestParameters: ownerRequest }); - expect(readPostsAsOwner.hadException).toEqual(false); - expect(readPostsAsOwner.stash.authFilter).toEqual( - expect.objectContaining({ - or: [{ owner: { eq: `${ownerRequest.jwt.sub}::user1` } }, { owner: { eq: `${ownerRequest.jwt.sub}` } }, { owner: { eq: 'user1' } }], - }), - ); - // expect owner can't run update or delete - const updateResponseAsOwner = vtlTemplate.render(updateResponseTemplate, { - context: createPostInput('user1'), - requestParameters: ownerRequest, - }); - expect(updateResponseAsOwner.hadException).toEqual(true); - const deleteResponseAsOwner = vtlTemplate.render(deleteResponseTemplate, { - context: createPostInput('user1'), - requestParameters: ownerRequest, - }); - expect(deleteResponseAsOwner.hadException).toEqual(true); - // expect editor to be able to run update and delete - const updateResponseAsEditor = vtlTemplate.render(updateResponseTemplate, { - context: createPostInput('user1'), - requestParameters: editorGroupRequest, - }); - expect(updateResponseAsEditor.hadException).toEqual(false); - const deleteResponseAsEditor = vtlTemplate.render(deleteResponseTemplate, { - context: createPostInput('user1'), - requestParameters: editorGroupRequest, - }); - expect(deleteResponseAsEditor.hadException).toEqual(false); - }); - - test('explicit operations where update restricted', () => { - const validSchema = ` - type Post @model @auth(rules: [ - { allow: owner, operations: [create, read, delete] }, - ]) { - id: ID - name: String - owner: String - }`; - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // load vtl templates - const createRequestTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const readRequestTemplate = out.resolvers['Query.listPosts.auth.1.req.vtl']; - const updateResponseTemplate = out.resolvers['Mutation.updatePost.auth.1.res.vtl']; - const deleteResponseTemplate = out.resolvers['Mutation.deletePost.auth.1.res.vtl']; - - // run the create request as owner should fail if the input is different the signed in owner - const createRequestAsNonOwner = vtlTemplate.render(createRequestTemplate, { - context: createPostInput('user2'), - requestParameters: ownerRequest, - }); - expect(createRequestAsNonOwner.hadException).toEqual(true); - - const createRequestAsOwner = vtlTemplate.render(createRequestTemplate, { - context: createPostInput('user1'), - requestParameters: ownerRequest, - }); - expect(createRequestAsOwner.hadException).toEqual(false); - - // read should have filter - const readRequestAsOwner = vtlTemplate.render(readRequestTemplate, { context: {}, requestParameters: ownerRequest }); - expect(readRequestAsOwner.stash.hasAuth).toEqual(true); - expect(readRequestAsOwner.stash.authFilter).toEqual( - expect.objectContaining({ - or: [{ owner: { eq: `${ownerRequest.jwt.sub}::user1` } }, { owner: { eq: `${ownerRequest.jwt.sub}` } }, { owner: { eq: 'user1' } }], - }), - ); - - // read should have filter - const readRequestAsNonOwner = vtlTemplate.render(readRequestTemplate, { context: {}, requestParameters: adminGroupRequest }); - expect(readRequestAsNonOwner.stash.authFilter).toEqual( - expect.objectContaining({ - or: [ - { owner: { eq: `${adminGroupRequest.jwt.sub}::user2` } }, - { owner: { eq: `${adminGroupRequest.jwt.sub}` } }, - { owner: { eq: 'user2' } }, - ], - }), - ); - - // update should fail for owner - const ddbUpdateResult: AppSyncVTLContext = { - result: { id: '001', name: 'sample', owner: 'user1' }, - arguments: { - input: { - id: '001', - name: 'sample', - }, - }, - }; - const updateResponseAsOwner = vtlTemplate.render(updateResponseTemplate, { - context: ddbUpdateResult, - requestParameters: ownerRequest, - }); - expect(updateResponseAsOwner.hadException).toEqual(true); - - // update should fail for NON owner - const updateResponseAsNonOwner = vtlTemplate.render(updateResponseTemplate, { - context: ddbUpdateResult, - requestParameters: adminGroupRequest, - }); - expect(updateResponseAsNonOwner.hadException).toEqual(true); - - // delete should fail for non owner - const ddbDeleteResult: AppSyncVTLContext = { - result: { id: '001', name: 'sample', owner: 'user1' }, - }; - const deleteResponseAsNonOwner = vtlTemplate.render(deleteResponseTemplate, { - context: ddbDeleteResult, - requestParameters: adminGroupRequest, - }); - expect(deleteResponseAsNonOwner.hadException).toEqual(true); - - // delete should pass for owner - const deleteResponseAsOwner = vtlTemplate.render(deleteResponseTemplate, { - context: ddbDeleteResult, - requestParameters: ownerRequest, - }); - expect(deleteResponseAsOwner.hadException).toEqual(false); - expect(deleteResponseAsOwner.stash.hasAuth).toEqual(true); - }); -}); - -describe('@model field auth', () => { - let vtlTemplate: VelocityTemplateSimulator; - let transformer: TestTransform; - const ownerRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user1', 'user1@test.com'), - headers: {}, - sourceIp: '', - }; - const adminGroupRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user2', 'user2@test.com', ['admin']), - headers: {}, - sourceIp: '', - }; - beforeEach(() => { - const authConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }; - transformer = { - transform: (schema: string) => - testTransform({ - schema, - authConfig, - transformers: [new ModelTransformer(), new AuthTransformer()], - }), - }; - vtlTemplate = new VelocityTemplateSimulator({ authConfig }); - }); - - test('object level group auth + field level owner auth', () => { - const validSchema = ` - type Student @model @auth(rules:[{ allow: groups, groups: ["admin"] }]) { - id: ID @auth(rules: [{ allow: groups, groups: ["admin"] }, { allow: owner, operations: [read, update], identityClaim: "username" }]) - name: String - email: String! @auth(rules: [{ allow: groups, groups: ["admin"] }, { allow: owner, operations: [read, update], identityClaim: "username" }]) - ssn: String - }`; - const out = transformer.transform(validSchema); - const updateResponseTemplate = out.resolvers['Mutation.updateStudent.auth.1.res.vtl']; - const updateContext: AppSyncVTLContext = { - arguments: { - input: { - id: '001', - email: 'myNewEmail', - name: 'newName', - }, - }, - result: { - id: '001', - email: 'user1@test.com', - name: 'samplename', // eslint-disable-line - owner: 'user1', - }, - }; - const updateContextOwnerPass: AppSyncVTLContext = { - ...updateContext, - arguments: { - input: { - id: '001', - email: 'newEmail@user1.com', - }, - }, - }; - // update request should fail - const updateResponseAsOwnerFailed = vtlTemplate.render(updateResponseTemplate, { - context: updateContext, - requestParameters: ownerRequest, - }); - expect(updateResponseAsOwnerFailed.hadException).toEqual(true); - expect(updateResponseAsOwnerFailed.errors[0].extensions).toEqual( - expect.objectContaining({ - errorType: 'Unauthorized', - message: 'Unauthorized on [name]', - }), - ); - // update request should pass if the owner is only modifying the allowed fields - const updateResponseAsOwner = vtlTemplate.render(updateResponseTemplate, { - context: updateContextOwnerPass, - requestParameters: ownerRequest, - }); - expect(updateResponseAsOwner.hadException).toEqual(false); - // update request should pass for admin user - const updateResponseAsAdmin = vtlTemplate.render(updateResponseTemplate, { - context: updateContext, - requestParameters: adminGroupRequest, - }); - expect(updateResponseAsAdmin.hadException).toEqual(false); - - // field read checks - const readFieldContext: AppSyncVTLContext = { - source: { - id: '001', - owner: 'user1', - name: 'nameSample', - ssn: '000111111', - }, - }; - ['name', 'ssn'].forEach((field) => { - // expect owner to get denied on these fields - const readFieldTemplate = out.resolvers[`Student.${field}.req.vtl`]; - const ownerReadResponse = vtlTemplate.render(readFieldTemplate, { context: readFieldContext, requestParameters: ownerRequest }); - expect(ownerReadResponse.hadException).toEqual(true); - // expect admin to be allowed - const adminReadResponse = vtlTemplate.render(readFieldTemplate, { context: readFieldContext, requestParameters: adminGroupRequest }); - expect(adminReadResponse.hadException).toEqual(false); - }); - - ['id', 'email'].forEach((field) => { - // since the only two roles have access to these fields there are no field resolvers - expect(out.resolvers?.[`Student.${field}.req.vtl`]).not.toBeDefined(); - }); - }); - - test('should allow setting name to null field', () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner, operations: [create, read] }]) { - id: ID @auth(rules: [{ allow: owner, operations: [create, read, update, delete] }]) - name: String @auth(rules: [{ allow: owner, operations: [create, read, delete] }]) - } - `; - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - // load vtl templates - const createPostTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const updatePostTemplate = out.resolvers['Mutation.updatePost.auth.1.res.vtl']; - - const createPostContext = { - arguments: { - input: { - id: '001', - name: 'sample', - }, - }, - }; - const createPostRequest = vtlTemplate.render(createPostTemplate, { - context: createPostContext, - requestParameters: ownerRequest, - }); - expect(createPostRequest.hadException).toEqual(false); - - const updatePostContext = { - result: { - id: '001', - name: null, - owner: 'user1', - }, - }; - const updatePostRequest = vtlTemplate.render(updatePostTemplate, { - context: updatePostContext, - requestParameters: ownerRequest, - }); - expect(updatePostRequest.hadException).toEqual(false); - }); - - test('should allow owner to update', () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner, operations: [create, update, read] }]) { - id: ID! - name: String! - } - `; - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - // load vtl templates - const createPostTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const updatePostTemplate = out.resolvers['Mutation.updatePost.auth.1.res.vtl']; - - const createPostContext = { - arguments: { - input: { - id: '001', - name: 'sample', - }, - }, - }; - const createPostRequest = vtlTemplate.render(createPostTemplate, { - context: createPostContext, - requestParameters: ownerRequest, - }); - expect(createPostRequest.hadException).toEqual(false); - - const updatePostContext = { - result: { - id: '001', - name: 'updated', - owner: 'user1', - }, - }; - const updatePostRequest = vtlTemplate.render(updatePostTemplate, { - context: updatePostContext, - requestParameters: ownerRequest, - }); - expect(updatePostRequest.hadException).toEqual(false); - }); -}); - -describe('@model @primaryIndex @index auth', () => { - let vtlTemplate: VelocityTemplateSimulator; - let transformer: TestTransform; - - const ownerRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user1', 'user1@test.com'), - headers: {}, - sourceIp: '', - }; - - beforeEach(() => { - const authConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }; - transformer = { - transform: (schema: string) => - testTransform({ - schema, - authConfig, - transformers: [new ModelTransformer(), new PrimaryKeyTransformer(), new IndexTransformer(), new AuthTransformer()], - }), - }; - vtlTemplate = new VelocityTemplateSimulator({ authConfig }); - }); - - test('listX operations', () => { - const validSchema = ` - type FamilyMember @model @auth(rules: [ - { allow: owner, ownerField: "parent", operations: [read] }, - { allow: owner, ownerField: "child", operations: [read] } - ]){ - parent: ID! @primaryKey(sortKeyFields: ["child"]) @index(name: "byParent", queryField: "byParent") - child: ID! @index(name: "byChild", queryField: "byChild") - createdAt: AWSDateTime - updatedAt: AWSDateTime - }`; - - expect(() => { - transformer.transform(validSchema); - }).toThrow( - "The primary key's sort key type 'child' cannot be used as an owner @auth field too. Please use another field for the sort key.", - ); - }); -}); - -describe('with identity claim feature flag disabled', () => { - describe('@model owner mutation checks', () => { - let vtlTemplate: VelocityTemplateSimulator; - let transformer: TestTransform; - const ownerRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user1', 'user1@test.com'), - headers: {}, - sourceIp: '', - }; - - beforeEach(() => { - const authConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }; - transformer = { - transform: (schema: string) => - testTransform({ - schema, - authConfig, - transformers: [new ModelTransformer(), new AuthTransformer()], - transformParameters: { - useSubUsernameForDefaultIdentityClaim: false, - }, - }), - }; - vtlTemplate = new VelocityTemplateSimulator({ authConfig }); - }); - - test('implicit owner with default owner field', () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner }]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - }`; - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // create the owner type - const ownerContext: AppSyncVTLContext = { - arguments: { input: { id: '001', title: 'sample' } }, - }; - - // expect the query resolver to contain a filter for the owner - const queryTemplate = out.resolvers['Query.listPosts.auth.1.req.vtl']; - const queryResponse = vtlTemplate.render(queryTemplate, { context: {}, requestParameters: ownerRequest }); - expect(queryResponse).toBeDefined(); - expect(queryResponse.stash.hasAuth).toEqual(true); - expect(queryResponse.stash.authFilter).toEqual( - expect.objectContaining({ - or: [{ owner: { eq: 'user1' } }], - }), - ); - - const createRequestTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const createVTLRequest = vtlTemplate.render(createRequestTemplate, { context: ownerContext, requestParameters: ownerRequest }); - expect(createVTLRequest).toBeDefined(); - expect(createVTLRequest.stash.hasAuth).toEqual(true); - expect(createVTLRequest.args).toBeDefined(); - expect(createVTLRequest.hadException).toEqual(false); - // since we have an owner rule we expect the owner field to be defined in the argument input - expect(createVTLRequest.args.input.owner).toEqual('user1'); - - const updateRequestTemplate = out.resolvers['Mutation.updatePost.auth.1.req.vtl']; - const updateVTLRequest = vtlTemplate.render(updateRequestTemplate, { context: ownerContext, requestParameters: ownerRequest }); - expect(updateVTLRequest).toBeDefined(); - // here we expect a get item payload to verify the owner making the update request is valid - expect(updateVTLRequest.result).toEqual( - expect.objectContaining({ - key: { id: { S: '001' } }, - operation: 'GetItem', - version: '2018-05-29', - }), - ); - // atm there is there is nothing in the stash yet - expect(updateVTLRequest.stash).toEqual({}); - const updateResponseTemplate = out.resolvers['Mutation.updatePost.auth.1.res.vtl']; - // response where the owner is indeed the owner - const updateVTLResponse = vtlTemplate.render(updateResponseTemplate, { - context: { ...ownerContext, result: { id: '001', owner: 'user1' } }, - requestParameters: ownerRequest, - }); - expect(updateVTLResponse).toBeDefined(); - expect(updateVTLResponse.hadException).toEqual(false); - expect(updateVTLResponse.stash.hasAuth).toEqual(true); - // response where there is an error - const updateVTLWithError = vtlTemplate.render(updateResponseTemplate, { - context: { ...ownerContext, result: { id: '001', owner: 'user2' } }, - requestParameters: ownerRequest, - }); - expect(updateVTLWithError).toBeDefined(); - expect(updateVTLWithError.hadException).toEqual(true); - expect(updateVTLWithError.errors).toHaveLength(1); - expect(updateVTLWithError.errors[0]).toEqual( - expect.objectContaining({ - errorType: 'Unauthorized', - message: expect.stringContaining('Unauthorized on $util.unauthorized()'), - }), - ); - }); - - test('implicit owner with custom field', () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner, ownerField: "editor" }]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - }`; - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // create context and request - const ownerContext: AppSyncVTLContext = { - arguments: { input: { id: '001', title: 'sample' } }, - }; - - const createRequestTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const createVTLRequest = vtlTemplate.render(createRequestTemplate, { context: ownerContext, requestParameters: ownerRequest }); - expect(createVTLRequest).toBeDefined(); - expect(createVTLRequest.stash.hasAuth).toEqual(true); - expect(createVTLRequest.args).toBeDefined(); - expect(createVTLRequest.hadException).toEqual(false); - // since we have an owner rule we expect the owner field to be defined in the argument input - expect(createVTLRequest.args.input.editor).toEqual('user1'); - }); - - test('explicit owner with default field', () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner }]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - owner: String - }`; - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // create context and request - const ownerContext: AppSyncVTLContext = { - arguments: { input: { id: '001', title: 'sample' } }, - }; - - const createRequestTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const createVTLRequest = vtlTemplate.render(createRequestTemplate, { context: ownerContext, requestParameters: ownerRequest }); - expect(createVTLRequest).toBeDefined(); - expect(createVTLRequest.stash.hasAuth).toEqual(true); - expect(createVTLRequest.args).toBeDefined(); - expect(createVTLRequest.hadException).toEqual(false); - // since we have an owner rule we expect the owner field to be defined in the argument input - expect(createVTLRequest.args.input.owner).toEqual('user1'); - }); - - test('explicit owner with custom field', () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner, ownerField: "editor" }]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - editor: String - }`; - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // create context and request - const ownerContext: AppSyncVTLContext = { - arguments: { input: { id: '001', title: 'sample' } }, - }; - - const createRequestTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const createVTLRequest = vtlTemplate.render(createRequestTemplate, { context: ownerContext, requestParameters: ownerRequest }); - expect(createVTLRequest).toBeDefined(); - expect(createVTLRequest.stash.hasAuth).toEqual(true); - expect(createVTLRequest.args).toBeDefined(); - expect(createVTLRequest.hadException).toEqual(false); - // since we have an owner rule we expect the owner field to be defined in the argument input - expect(createVTLRequest.args.input.editor).toEqual('user1'); - - const differentOwnerContext: AppSyncVTLContext = { arguments: { input: { id: '001', title: 'sample', editor: 'user2' } } }; - const createVTLRequestWithErrors = vtlTemplate.render(createRequestTemplate, { - context: differentOwnerContext, - requestParameters: ownerRequest, - }); - expect(createVTLRequestWithErrors).toBeDefined(); - expect(createVTLRequestWithErrors.hadException).toEqual(true); - expect(createVTLRequestWithErrors.errors).toHaveLength(1); - // should fail since the owner in the input is different than what is in the - expect(createVTLRequestWithErrors.errors[0]).toEqual( - expect.objectContaining({ - errorType: 'Unauthorized', - message: expect.stringContaining('Unauthorized on $util.unauthorized()'), - }), - ); - }); - - test('explicit owner using a custom list field', () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner, ownerField: "editors" }]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - editors: [String] - }`; - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // create context and request - const ownerContext: AppSyncVTLContext = { - arguments: { input: { id: '001', title: 'sample' } }, - }; - - const createRequestTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - expect(createRequestTemplate).toBeDefined(); - const createVTLRequest = vtlTemplate.render(createRequestTemplate, { context: ownerContext, requestParameters: ownerRequest }); - expect(createVTLRequest).toBeDefined(); - expect(createVTLRequest.stash.hasAuth).toEqual(true); - expect(createVTLRequest.args).toBeDefined(); - expect(createVTLRequest.hadException).toEqual(false); - // since we have an owner rule we expect the owner field to be defined in the argument input - expect(createVTLRequest.args.input.editors).toEqual(['user1']); - - // should fail if the list of users does not contain the currently signed user - const failedCreateVTLRequest = vtlTemplate.render(createRequestTemplate, { - context: { - arguments: { input: { id: '001', title: 'sample', editors: ['user2'] } }, - }, - requestParameters: ownerRequest, - }); - expect(failedCreateVTLRequest.hadException).toEqual(true); - // should fail since the owner in the input is different than what is in the - expect(failedCreateVTLRequest.errors[0]).toEqual( - expect.objectContaining({ - errorType: 'Unauthorized', - message: expect.stringContaining('Unauthorized on $util.unauthorized()'), - }), - ); - }); - }); - - describe('@model operations', () => { - let vtlTemplate: VelocityTemplateSimulator; - let transformer: { transform: (schema: string) => DeploymentResources }; - const ownerRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user1', 'user1@test.com'), - headers: {}, - sourceIp: '', - }; - const adminGroupRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user2', 'user2@test.com', ['admin']), - headers: {}, - sourceIp: '', - }; - const editorGroupRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user3', 'user3@test.com', ['editor']), - headers: {}, - sourceIp: '', - }; - const createPostInput = (owner?: string): AppSyncVTLContext => ({ - arguments: { - input: { - id: '001', - name: 'sample', - owner, - }, - }, - }); - - beforeEach(() => { - const authConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }; - transformer = { - transform: (schema: string) => - testTransform({ - schema, - authConfig, - transformers: [new ModelTransformer(), new AuthTransformer()], - transformParameters: { - useSubUsernameForDefaultIdentityClaim: false, - }, - }), - }; - vtlTemplate = new VelocityTemplateSimulator({ authConfig }); - }); - - test('explicit operations where create/delete restricted', () => { - const validSchema = ` - type Post @model @auth(rules: [ - { allow: owner, operations: [create, read] }, - { allow: groups, groups: ["admin"] }]) { - id: ID - name: String - owner: String - }`; - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // load vtl templates - const createRequestTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const readRequestTemplate = out.resolvers['Query.listPosts.auth.1.req.vtl']; - const updateResponseTemplate = out.resolvers['Mutation.updatePost.auth.1.res.vtl']; - const deleteResponseTemplate = out.resolvers['Mutation.deletePost.auth.1.res.vtl']; - - // run create request as owner and admin - // even though they are not the owner it will still pass as they one making the request is in the admin group - const createRequestAsAdmin = vtlTemplate.render(createRequestTemplate, { - context: createPostInput('owner2'), - requestParameters: adminGroupRequest, - }); - expect(createRequestAsAdmin).toBeDefined(); - expect(createRequestAsAdmin.hadException).toEqual(false); - expect(createRequestAsAdmin.stash.hasAuth).toEqual(true); - // run the create request as owner should fail if the input is different the signed in owner - const createRequestAsOwner = vtlTemplate.render(createRequestTemplate, { - context: createPostInput('user2'), - requestParameters: ownerRequest, - }); - expect(createRequestAsOwner.hadException).toEqual(true); - expect(createRequestAsOwner.errors[0]).toEqual( - expect.objectContaining({ - errorType: 'Unauthorized', - message: expect.stringContaining('Unauthorized on $util.unauthorized()'), - }), - ); - // read request for admin should not contain the filter - const readRequestAsAdmin = vtlTemplate.render(readRequestTemplate, { context: {}, requestParameters: adminGroupRequest }); - expect(readRequestAsAdmin.stash.hasAuth).toEqual(true); - expect(readRequestAsAdmin.stash.authFilter).not.toBeDefined(); - const readRequestAsOwner = vtlTemplate.render(readRequestTemplate, { context: {}, requestParameters: ownerRequest }); - expect(readRequestAsOwner.stash.hasAuth).toEqual(true); - expect(readRequestAsOwner.stash.authFilter).toEqual( - expect.objectContaining({ - or: [{ owner: { eq: 'user1' } }], - }), - ); - const ddbResponseResult: AppSyncVTLContext = { result: { id: '001', title: 'sample', owner: 'user1' } }; - // update should pass for admin even if they are not the owner of the record - const updateResponseAsAdmin = vtlTemplate.render(updateResponseTemplate, { - context: ddbResponseResult, - requestParameters: adminGroupRequest, - }); - expect(updateResponseAsAdmin.hadException).toEqual(false); - expect(updateResponseAsAdmin.stash.hasAuth).toEqual(true); - // update should fail for owner even though they are the owner of the record - const updateResponseAsOwner = vtlTemplate.render(updateResponseTemplate, { - context: ddbResponseResult, - requestParameters: ownerRequest, - }); - expect(updateResponseAsOwner.hadException).toEqual(true); - // delete should pass for admin even if they are not the owner of the record - const deleteResponseAsAdmin = vtlTemplate.render(deleteResponseTemplate, { - context: ddbResponseResult, - requestParameters: adminGroupRequest, - }); - expect(deleteResponseAsAdmin.hadException).toEqual(false); - // delete should fail for owner even though they are the owner of the record - const deleteResponseAsOwner = vtlTemplate.render(deleteResponseTemplate, { - context: ddbResponseResult, - requestParameters: ownerRequest, - }); - expect(deleteResponseAsOwner.hadException).toEqual(true); - }); - - test('owner restricts create/read and group restricts read/update/delete', () => { - // NOTE: this means that you can only create a record for the same owner - // you can't create a record for other owners even if your in the editor group - const validSchema = ` - type Post @model @auth(rules: [ - { allow: owner, operations: [create, read] }, - { allow: groups, groups: ["editor"], operations: [read, update, delete] }]) { - id: ID - name: String - owner: String - } - `; - const out = transformer.transform(validSchema); - // load vtl templates - const createRequestTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const readRequestTemplate = out.resolvers['Query.listPosts.auth.1.req.vtl']; - const updateResponseTemplate = out.resolvers['Mutation.updatePost.auth.1.res.vtl']; - const deleteResponseTemplate = out.resolvers['Mutation.deletePost.auth.1.res.vtl']; - - // check that a editor member can't create a post under another owner - const createPostAsEditor = vtlTemplate.render(createRequestTemplate, { - context: createPostInput('user1'), - requestParameters: editorGroupRequest, - }); - expect(createPostAsEditor.hadException).toEqual(true); - // check that editor can read posts with no filter - const readPostsAsEditor = vtlTemplate.render(readRequestTemplate, { context: {}, requestParameters: editorGroupRequest }); - expect(readPostsAsEditor.hadException).toEqual(false); - expect(readPostsAsEditor.stash.authFilter).not.toBeDefined(); - // expect owner can read but with an auth filter - const readPostsAsOwner = vtlTemplate.render(readRequestTemplate, { context: {}, requestParameters: ownerRequest }); - expect(readPostsAsOwner.hadException).toEqual(false); - expect(readPostsAsOwner.stash.authFilter).toEqual( - expect.objectContaining({ - or: [{ owner: { eq: 'user1' } }], - }), - ); - // expect owner can't run update or delete - const updateResponseAsOwner = vtlTemplate.render(updateResponseTemplate, { - context: createPostInput('user1'), - requestParameters: ownerRequest, - }); - expect(updateResponseAsOwner.hadException).toEqual(true); - const deleteResponseAsOwner = vtlTemplate.render(deleteResponseTemplate, { - context: createPostInput('user1'), - requestParameters: ownerRequest, - }); - expect(deleteResponseAsOwner.hadException).toEqual(true); - // expect editor to be able to run update and delete - const updateResponseAsEditor = vtlTemplate.render(updateResponseTemplate, { - context: createPostInput('user1'), - requestParameters: editorGroupRequest, - }); - expect(updateResponseAsEditor.hadException).toEqual(false); - const deleteResponseAsEditor = vtlTemplate.render(deleteResponseTemplate, { - context: createPostInput('user1'), - requestParameters: editorGroupRequest, - }); - expect(deleteResponseAsEditor.hadException).toEqual(false); - }); - - test('explicit operations where update restricted', () => { - const validSchema = ` - type Post @model @auth(rules: [ - { allow: owner, operations: [create, read, delete] }, - ]) { - id: ID - name: String - owner: String - }`; - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // load vtl templates - const createRequestTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const readRequestTemplate = out.resolvers['Query.listPosts.auth.1.req.vtl']; - const updateResponseTemplate = out.resolvers['Mutation.updatePost.auth.1.res.vtl']; - const deleteResponseTemplate = out.resolvers['Mutation.deletePost.auth.1.res.vtl']; - - // run the create request as owner should fail if the input is different the signed in owner - const createRequestAsNonOwner = vtlTemplate.render(createRequestTemplate, { - context: createPostInput('user2'), - requestParameters: ownerRequest, - }); - expect(createRequestAsNonOwner.hadException).toEqual(true); - - const createRequestAsOwner = vtlTemplate.render(createRequestTemplate, { - context: createPostInput('user1'), - requestParameters: ownerRequest, - }); - expect(createRequestAsOwner.hadException).toEqual(false); - - // read should have filter - const readRequestAsOwner = vtlTemplate.render(readRequestTemplate, { context: {}, requestParameters: ownerRequest }); - expect(readRequestAsOwner.stash.hasAuth).toEqual(true); - expect(readRequestAsOwner.stash.authFilter).toEqual( - expect.objectContaining({ - or: [{ owner: { eq: 'user1' } }], - }), - ); - - // read should have filter - const readRequestAsNonOwner = vtlTemplate.render(readRequestTemplate, { context: {}, requestParameters: adminGroupRequest }); - expect(readRequestAsNonOwner.stash.authFilter).toEqual( - expect.objectContaining({ - or: [{ owner: { eq: 'user2' } }], - }), - ); - - // update should fail for owner - const ddbUpdateResult: AppSyncVTLContext = { - result: { id: '001', name: 'sample', owner: 'user1' }, - arguments: { - input: { - id: '001', - name: 'sample', - }, - }, - }; - const updateResponseAsOwner = vtlTemplate.render(updateResponseTemplate, { - context: ddbUpdateResult, - requestParameters: ownerRequest, - }); - expect(updateResponseAsOwner.hadException).toEqual(true); - - // update should fail for NON owner - const updateResponseAsNonOwner = vtlTemplate.render(updateResponseTemplate, { - context: ddbUpdateResult, - requestParameters: adminGroupRequest, - }); - expect(updateResponseAsNonOwner.hadException).toEqual(true); - - // delete should fail for non owner - const ddbDeleteResult: AppSyncVTLContext = { - result: { id: '001', name: 'sample', owner: 'user1' }, - }; - const deleteResponseAsNonOwner = vtlTemplate.render(deleteResponseTemplate, { - context: ddbDeleteResult, - requestParameters: adminGroupRequest, - }); - expect(deleteResponseAsNonOwner.hadException).toEqual(true); - - // delete should pass for owner - const deleteResponseAsOwner = vtlTemplate.render(deleteResponseTemplate, { - context: ddbDeleteResult, - requestParameters: ownerRequest, - }); - expect(deleteResponseAsOwner.hadException).toEqual(false); - expect(deleteResponseAsOwner.stash.hasAuth).toEqual(true); - }); - }); - - describe('@model field auth', () => { - let vtlTemplate: VelocityTemplateSimulator; - let transformer: TestTransform; - const ownerRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user1', 'user1@test.com'), - headers: {}, - sourceIp: '', - }; - const adminGroupRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user2', 'user2@test.com', ['admin']), - headers: {}, - sourceIp: '', - }; - beforeEach(() => { - const authConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }; - transformer = { - transform: (schema: string) => - testTransform({ - schema, - authConfig, - transformers: [new ModelTransformer(), new AuthTransformer()], - }), - }; - vtlTemplate = new VelocityTemplateSimulator({ authConfig }); - }); - - test('object level group auth + field level owner auth', () => { - const validSchema = ` - type Student @model @auth(rules:[{ allow: groups, groups: ["admin"] }]) { - id: ID @auth(rules: [{ allow: groups, groups: ["admin"] }, { allow: owner, operations: [read, update] }]) - name: String - email: String! @auth(rules: [{ allow: groups, groups: ["admin"] }, { allow: owner, operations: [read, update] }]) - ssn: String - }`; - const out = transformer.transform(validSchema); - const updateResponseTemplate = out.resolvers['Mutation.updateStudent.auth.1.res.vtl']; - const updateContext: AppSyncVTLContext = { - arguments: { - input: { - id: '001', - email: 'myNewEmail', - name: 'newName', - }, - }, - result: { - id: '001', - email: 'user1@test.com', - name: 'samplename', // eslint-disable-line - owner: 'user1', - }, - }; - const updateContextOwnerPass: AppSyncVTLContext = { - ...updateContext, - arguments: { - input: { - id: '001', - email: 'newEmail@user1.com', - }, - }, - }; - // update request should fail - const updateResponseAsOwnerFailed = vtlTemplate.render(updateResponseTemplate, { - context: updateContext, - requestParameters: ownerRequest, - }); - expect(updateResponseAsOwnerFailed.hadException).toEqual(true); - expect(updateResponseAsOwnerFailed.errors[0].extensions).toEqual( - expect.objectContaining({ - errorType: 'Unauthorized', - message: 'Unauthorized on [name]', - }), - ); - // update request should pass if the owner is only modifying the allowed fields - const updateResponseAsOwner = vtlTemplate.render(updateResponseTemplate, { - context: updateContextOwnerPass, - requestParameters: ownerRequest, - }); - expect(updateResponseAsOwner.hadException).toEqual(false); - // update request should pass for admin user - const updateResponseAsAdmin = vtlTemplate.render(updateResponseTemplate, { - context: updateContext, - requestParameters: adminGroupRequest, - }); - expect(updateResponseAsAdmin.hadException).toEqual(false); - - // field read checks - const readFieldContext: AppSyncVTLContext = { - source: { - id: '001', - owner: 'user1', - name: 'nameSample', - ssn: '000111111', - }, - }; - ['name', 'ssn'].forEach((field) => { - // expect owner to get denied on these fields - const readFieldTemplate = out.resolvers[`Student.${field}.req.vtl`]; - const ownerReadResponse = vtlTemplate.render(readFieldTemplate, { context: readFieldContext, requestParameters: ownerRequest }); - expect(ownerReadResponse.hadException).toEqual(true); - // expect admin to be allowed - const adminReadResponse = vtlTemplate.render(readFieldTemplate, { - context: readFieldContext, - requestParameters: adminGroupRequest, - }); - expect(adminReadResponse.hadException).toEqual(false); - }); - - ['id', 'email'].forEach((field) => { - // since the only two roles have access to these fields there are no field resolvers - expect(out.resolvers?.[`Student.${field}.req.vtl`]).not.toBeDefined(); - }); - }); - - test('should allow setting name to null field', () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner, operations: [create, read] }]) { - id: ID @auth(rules: [{ allow: owner, operations: [create, read, update, delete] }]) - name: String @auth(rules: [{ allow: owner, operations: [create, read, delete] }]) - } - `; - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - // load vtl templates - const createPostTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const updatePostTemplate = out.resolvers['Mutation.updatePost.auth.1.res.vtl']; - - const createPostContext = { - arguments: { - input: { - id: '001', - name: 'sample', - }, - }, - }; - const createPostRequest = vtlTemplate.render(createPostTemplate, { - context: createPostContext, - requestParameters: ownerRequest, - }); - expect(createPostRequest.hadException).toEqual(false); - - const updatePostContext = { - result: { - id: '001', - name: null, - owner: 'user1', - }, - }; - const updatePostRequest = vtlTemplate.render(updatePostTemplate, { - context: updatePostContext, - requestParameters: ownerRequest, - }); - expect(updatePostRequest.hadException).toEqual(false); - }); - - test('should allow owner to update', () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner, operations: [create, update, read] }]) { - id: ID! - name: String! - } - `; - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - // load vtl templates - const createPostTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const updatePostTemplate = out.resolvers['Mutation.updatePost.auth.1.res.vtl']; - - const createPostContext = { - arguments: { - input: { - id: '001', - name: 'sample', - }, - }, - }; - const createPostRequest = vtlTemplate.render(createPostTemplate, { - context: createPostContext, - requestParameters: ownerRequest, - }); - expect(createPostRequest.hadException).toEqual(false); - - const updatePostContext = { - result: { - id: '001', - name: 'updated', - owner: 'user1', - }, - }; - const updatePostRequest = vtlTemplate.render(updatePostTemplate, { - context: updatePostContext, - requestParameters: ownerRequest, - }); - expect(updatePostRequest.hadException).toEqual(false); - }); - }); - - describe('@model @primaryIndex @index auth', () => { - let vtlTemplate: VelocityTemplateSimulator; - let transformer: TestTransform; - - const ownerRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user1', 'user1@test.com'), - headers: {}, - sourceIp: '', - }; - - beforeEach(() => { - const authConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }; - transformer = { - transform: (schema: string) => - testTransform({ - schema, - authConfig, - transformParameters: { - useSubUsernameForDefaultIdentityClaim: false, - }, - transformers: [new ModelTransformer(), new PrimaryKeyTransformer(), new IndexTransformer(), new AuthTransformer()], - }), - }; - vtlTemplate = new VelocityTemplateSimulator({ authConfig }); - }); - - test('listX operations', () => { - const validSchema = ` - type FamilyMember @model @auth(rules: [ - { allow: owner, ownerField: "parent", operations: [read] }, - { allow: owner, ownerField: "child", operations: [read] } - ]){ - parent: ID! @primaryKey(sortKeyFields: ["child"]) @index(name: "byParent", queryField: "byParent") - child: ID! @index(name: "byChild", queryField: "byChild") - createdAt: AWSDateTime - updatedAt: AWSDateTime - }`; - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - // should expect no errors and there should be an auth filter - const listAuthRequestTemplate = out.resolvers['Query.listFamilyMembers.auth.1.req.vtl']; - expect(listAuthRequestTemplate).toBeDefined(); - let listAuthVTLRequest = vtlTemplate.render(listAuthRequestTemplate, { - context: {}, - requestParameters: ownerRequest, - }); - expect(listAuthVTLRequest.hadException).toEqual(false); - expect(listAuthVTLRequest.stash.authFilter).toEqual( - expect.objectContaining({ - or: expect.arrayContaining([ - expect.objectContaining({ child: { in: expect.arrayContaining([ownerRequest.jwt['cognito:username']]) } }), - expect.objectContaining({ parent: { in: expect.arrayContaining([ownerRequest.jwt['cognito:username']]) } }), - ]), - }), - ); - - // should still change model query expression if the partition key is provided - // adding the modelQueryExpression and arg to simulate partition key being added - listAuthVTLRequest = vtlTemplate.render(listAuthRequestTemplate, { - context: { - arguments: { - parent: 'user10', - }, - stash: { - modelQueryExpression: { - expression: '#parent = :parent', - expressionNames: { - '#parent': 'parent', - }, - expressionValues: { - ':parent': { - S: '$ctx.args.parent', - }, - }, - }, - }, - }, - requestParameters: ownerRequest, - }); - expect(listAuthVTLRequest.hadException).toEqual(false); - expect(listAuthVTLRequest.stash.authFilter).not.toBeDefined(); - // the $ctx.args.parent is not resolving in mock vtl engine - // not an issue in the service the index e2e tests this scenario - expect(listAuthVTLRequest.stash.modelQueryExpression).toMatchInlineSnapshot(` - Object { - "expression": "#parent = :parent AND #child = :child", - "expressionNames": Object { - "#child": "child", - "#parent": "parent", - }, - "expressionValues": Object { - ":child": Object { - "S": "user1", - }, - ":parent": Object { - "S": "$ctx.args.parent", - }, - }, - } - `); - }); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/velocity/multi-auth.test.ts b/packages/amplify-util-mock/src/__tests__/velocity/multi-auth.test.ts deleted file mode 100644 index 4eab7f4cd3..0000000000 --- a/packages/amplify-util-mock/src/__tests__/velocity/multi-auth.test.ts +++ /dev/null @@ -1,236 +0,0 @@ -import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer'; -import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; -import { AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; -import { AmplifyAppSyncSimulatorAuthenticationType, AppSyncGraphQLExecutionContext } from '@aws-amplify/amplify-appsync-simulator'; -import { testTransform, DeploymentResources } from '@aws-amplify/graphql-transformer-test-utils'; -import { VelocityTemplateSimulator, AppSyncVTLContext, getGenericToken } from '../../velocity'; - -type TestTransform = { - transform: (schema: string) => DeploymentResources; -}; - -jest.mock('@aws-amplify/amplify-prompts'); - -// oidc needs claim values to know where to check in the token otherwise it will use cognito defaults precendence order below -// - owner: 'username' -> 'cognito:username' -> default to null -// - group: 'cognito:groups' -> default to null or empty list -describe('@model + @auth with oidc provider', () => { - let vtlTemplate: VelocityTemplateSimulator; - let transformer: TestTransform; - const subIdUser: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.OPENID_CONNECT, - jwt: getGenericToken('randomIdUser', 'random@user.com'), - headers: {}, - }; - const editorGroupMember: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.OPENID_CONNECT, - jwt: getGenericToken('editorUser', 'editor0@user.com', ['Editor']), - headers: {}, - }; - - beforeEach(() => { - const authConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'OPENID_CONNECT', - openIDConnectConfig: { - name: 'myOIDCProvider', - issuerUrl: 'https://some-oidc-provider/auth', - clientId: 'my-sample-client-id', - }, - }, - additionalAuthenticationProviders: [], - }; - transformer = { - transform: (schema: string) => - testTransform({ - schema, - authConfig, - transformers: [new ModelTransformer(), new AuthTransformer()], - }), - }; - vtlTemplate = new VelocityTemplateSimulator({ authConfig }); - }); - - test('oidc default', () => { - const validSchema = ` - # owner authorization with provider override - type Profile @model @auth(rules: [{ allow: owner, provider: oidc, identityClaim: "sub" }]) { - id: ID! - displayName: String! - }`; - - const createProfileInput: AppSyncVTLContext = { - arguments: { - input: { - id: '001', - displayName: 'FooBar', - }, - }, - }; - - const out = transformer.transform(validSchema); - const createRequestTemplate = out.resolvers['Mutation.createProfile.auth.1.req.vtl']; - const createRequestAsSubOwner = vtlTemplate.render(createRequestTemplate, { - context: createProfileInput, - requestParameters: subIdUser, - }); - expect(createRequestAsSubOwner.hadException).toEqual(false); - expect(createRequestAsSubOwner.args.input).toEqual( - expect.objectContaining({ - id: '001', - displayName: 'FooBar', - owner: expect.any(String), // since its a uuid we just need to know the owner was added - }), - ); - }); - - test('oidc static groups', () => { - const validSchema = ` - type Comment @model @auth(rules: [{ allow: groups, groups: ["Editor"], groupClaim: "groups", provider: oidc }]) { - id: ID - content: String - }`; - const createCommentInput: AppSyncVTLContext = { - arguments: { - input: { - id: '001', - content: 'Foobar', - }, - }, - }; - const getCommentArgs: AppSyncVTLContext = { - arguments: { - id: '001', - }, - }; - const out = transformer.transform(validSchema); - const createRequestTemplate = out.resolvers['Mutation.createComment.auth.1.req.vtl']; - const getRequestTemplate = out.resolvers['Query.getComment.auth.1.req.vtl']; - // mutations - const createRequestAsEditor = vtlTemplate.render(createRequestTemplate, { - context: createCommentInput, - requestParameters: editorGroupMember, - }); - expect(createRequestAsEditor.hadException).toEqual(false); - const createRequestAsUser = vtlTemplate.render(createRequestTemplate, { context: createCommentInput, requestParameters: subIdUser }); - expect(createRequestAsUser.hadException).toEqual(true); - // queries - const getRequestAsEditor = vtlTemplate.render(getRequestTemplate, { context: getCommentArgs, requestParameters: editorGroupMember }); - expect(getRequestAsEditor.hadException).toEqual(false); - const getRequestAsOwner = vtlTemplate.render(getRequestTemplate, { context: getCommentArgs, requestParameters: subIdUser }); - expect(getRequestAsOwner.hadException).toEqual(true); - }); -}); - -describe('with identity claim feature flag disabled', () => { - describe('@model + @auth with oidc provider', () => { - let vtlTemplate: VelocityTemplateSimulator; - let transformer: TestTransform; - const subIdUser: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.OPENID_CONNECT, - jwt: getGenericToken('randomIdUser', 'random@user.com'), - headers: {}, - }; - const editorGroupMember: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.OPENID_CONNECT, - jwt: getGenericToken('editorUser', 'editor0@user.com', ['Editor']), - headers: {}, - }; - - beforeEach(() => { - const authConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'OPENID_CONNECT', - openIDConnectConfig: { - name: 'myOIDCProvider', - issuerUrl: 'https://some-oidc-provider/auth', - clientId: 'my-sample-client-id', - }, - }, - additionalAuthenticationProviders: [], - }; - transformer = { - transform: (schema: string) => - testTransform({ - schema, - authConfig, - transformers: [new ModelTransformer(), new AuthTransformer()], - transformParameters: { - useSubUsernameForDefaultIdentityClaim: false, - }, - }), - }; - vtlTemplate = new VelocityTemplateSimulator({ authConfig }); - }); - - test('oidc default', () => { - const validSchema = ` - # owner authorization with provider override - type Profile @model @auth(rules: [{ allow: owner, provider: oidc, identityClaim: "sub" }]) { - id: ID! - displayName: String! - }`; - - const createProfileInput: AppSyncVTLContext = { - arguments: { - input: { - id: '001', - displayName: 'FooBar', - }, - }, - }; - - const out = transformer.transform(validSchema); - const createRequestTemplate = out.resolvers['Mutation.createProfile.auth.1.req.vtl']; - const createRequestAsSubOwner = vtlTemplate.render(createRequestTemplate, { - context: createProfileInput, - requestParameters: subIdUser, - }); - expect(createRequestAsSubOwner.hadException).toEqual(false); - expect(createRequestAsSubOwner.args.input).toEqual( - expect.objectContaining({ - id: '001', - displayName: 'FooBar', - owner: expect.any(String), // since its a uuid we just need to know the owner was added - }), - ); - }); - - test('oidc static groups', () => { - const validSchema = ` - type Comment @model @auth(rules: [{ allow: groups, groups: ["Editor"], groupClaim: "groups", provider: oidc }]) { - id: ID - content: String - }`; - const createCommentInput: AppSyncVTLContext = { - arguments: { - input: { - id: '001', - content: 'Foobar', - }, - }, - }; - const getCommentArgs: AppSyncVTLContext = { - arguments: { - id: '001', - }, - }; - const out = transformer.transform(validSchema); - const createRequestTemplate = out.resolvers['Mutation.createComment.auth.1.req.vtl']; - const getRequestTemplate = out.resolvers['Query.getComment.auth.1.req.vtl']; - // mutations - const createRequestAsEditor = vtlTemplate.render(createRequestTemplate, { - context: createCommentInput, - requestParameters: editorGroupMember, - }); - expect(createRequestAsEditor.hadException).toEqual(false); - const createRequestAsUser = vtlTemplate.render(createRequestTemplate, { context: createCommentInput, requestParameters: subIdUser }); - expect(createRequestAsUser.hadException).toEqual(true); - // queries - const getRequestAsEditor = vtlTemplate.render(getRequestTemplate, { context: getCommentArgs, requestParameters: editorGroupMember }); - expect(getRequestAsEditor.hadException).toEqual(false); - const getRequestAsOwner = vtlTemplate.render(getRequestTemplate, { context: getCommentArgs, requestParameters: subIdUser }); - expect(getRequestAsOwner.hadException).toEqual(true); - }); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/velocity/relational-auth.test.ts b/packages/amplify-util-mock/src/__tests__/velocity/relational-auth.test.ts deleted file mode 100644 index 5e046f46eb..0000000000 --- a/packages/amplify-util-mock/src/__tests__/velocity/relational-auth.test.ts +++ /dev/null @@ -1,665 +0,0 @@ -import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer'; -import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; -import { PrimaryKeyTransformer, IndexTransformer } from '@aws-amplify/graphql-index-transformer'; -import { HasManyTransformer, HasOneTransformer, BelongsToTransformer } from '@aws-amplify/graphql-relational-transformer'; -import { AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; -import { AmplifyAppSyncSimulatorAuthenticationType, AppSyncGraphQLExecutionContext } from '@aws-amplify/amplify-appsync-simulator'; -import { testTransform, DeploymentResources } from '@aws-amplify/graphql-transformer-test-utils'; -import { VelocityTemplateSimulator, getJWTToken, getIAMToken } from '../../velocity'; - -type TestTransform = { - transform: (schema: string) => DeploymentResources; -}; - -jest.mock('@aws-amplify/amplify-prompts'); - -const USER_POOL_ID = 'us-fake-1ID'; - -describe('relational tests', () => { - let vtlTemplate: VelocityTemplateSimulator; - let transformer: TestTransform; - const ownerRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user1', 'user1@test.com'), - headers: {}, - }; - const adminGroupRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user2', 'user2@test.com', ['admin']), - headers: {}, - }; - const iamAuthRole: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AWS_IAM, - iamToken: getIAMToken('authRole', { - cognitoIdentityAuthProvider: `cognito-idp.us-fake1.amazonaws.com/${USER_POOL_ID}`, - cognitoIdentityAuthType: 'authenticated', - cognitoIdentityPoolId: `${USER_POOL_ID}:000-111-222`, - cognitoIdentityId: 'us-fake-1:000', - }), - headers: {}, - }; - - beforeEach(() => { - const authConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }; - transformer = { - transform: (schema: string) => - testTransform({ - schema, - authConfig, - transformers: [ - new ModelTransformer(), - new AuthTransformer(), - new PrimaryKeyTransformer(), - new IndexTransformer(), - new HasManyTransformer(), - new HasOneTransformer(), - new BelongsToTransformer(), - ], - }), - }; - vtlTemplate = new VelocityTemplateSimulator({ authConfig }); - }); - - test('1:1 nested auth read', () => { - // public signed user pools should only be able to read - // blogs and they can't see the editor - const validSchema = ` - type Blog @model @auth(rules: [{ allow: private, operations: [read], provider: userPools }]) { - id: ID! - name: String - title: String - editor: Editor @hasOne(fields: ["id", "name"]) - } - - type Editor @model @auth(rules: [{ allow: owner }]) { - id: ID! @primaryKey(sortKeyFields: ["name"]) - name: String! - email: AWSEmail - }`; - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const listBlogTemplate = out.resolvers['Query.listBlogs.auth.1.req.vtl']; - const blogEditor = out.resolvers['Blog.editor.auth.1.req.vtl']; - - // signed in as a cognito user should not yield unauthorized - const upResponse = vtlTemplate.render(listBlogTemplate, { context: {}, requestParameters: ownerRequest }); - expect(upResponse.hadException).toBe(false); - - // signed in via iam will yield unauthorized - const iamResponse = vtlTemplate.render(listBlogTemplate, { context: {}, requestParameters: iamAuthRole }); - expect(iamResponse.hadException).toBe(true); - expect(iamResponse.errors[0].errorType).toEqual('Unauthorized'); - - // query for blogEditor should have an owner rule filter - const ownerFieldResponse = vtlTemplate.render(blogEditor, { context: {}, requestParameters: ownerRequest }); - expect(ownerFieldResponse.hadException).toBe(false); - expect(ownerFieldResponse.stash.authFilter).toEqual( - expect.objectContaining({ - or: [{ owner: { eq: `${ownerRequest.jwt.sub}::user1` } }, { owner: { eq: `${ownerRequest.jwt.sub}` } }, { owner: { eq: 'user1' } }], - }), - ); - }); - - test('1:M nested auth read', () => { - // checking for the following cases - // don't apply the authFilter if the owner is not in any valid groups - // remove auth filter if the primaryRole (ex. the owner rule) condition is met - // pass the auth filter if the primaryRole condition is not met - - const validSchema = ` - type Post @model @auth(rules: [{allow: owner}, { allow: groups, groupsField: "editors" }]) { - id: ID! - title: String! - editors: [String] - author: User @belongsTo(fields: ["owner"]) - owner: ID! @index(name: "byOwner", sortKeyFields: ["id"]) - } - - type User @model @auth(rules: [{ allow: owner }]) { - id: ID! - name: String - posts: [Post] @hasMany(indexName: "byOwner", fields: ["id"]) - }`; - const out = transformer.transform(validSchema); - const userPostTemplate = out.resolvers['User.posts.auth.1.req.vtl']; - - // request as admin editor where the user is not the user in the record so therefore the auth filter is applied - const adminWithFilterResponse = vtlTemplate.render(userPostTemplate, { - context: { - source: { id: 'user1' }, - }, - requestParameters: adminGroupRequest, - }); - expect(adminWithFilterResponse.hadException).toEqual(false); - expect(adminWithFilterResponse.stash.authFilter).toEqual( - expect.objectContaining({ - or: [{ editors: { contains: 'admin' } }], - }), - ); - - // response where the editor member is the owner therefore the auth filter does not need to be applied - const adminWithNoFilterResponse = vtlTemplate.render(userPostTemplate, { - context: { - source: { id: 'user2' }, - }, - requestParameters: adminGroupRequest, - }); - expect(adminWithNoFilterResponse.hadException).toEqual(false); - expect(adminWithNoFilterResponse.stash.authFilter).toBeNull(); - - // request as a user that is neither the owner nor has any valid groups - // therefore the request is changed to include the current user to ensure they are only seeing their correct records - // NOTE: will only really happen in the group claim rule is different than that of the related type therefore - // the owner rule should still be enforced - const ownerWithNoFilter = vtlTemplate.render(userPostTemplate, { - context: { - source: { id: 'user3' }, - }, - requestParameters: ownerRequest, - }); - expect(ownerWithNoFilter.hadException).toEqual(false); - expect(ownerWithNoFilter.stash.authFilter).not.toBeDefined(); - }); - - test('has one and partial type access', () => { - const validSchema = ` - type ModelA @model @auth(rules: [{ allow: owner }]) { - id: ID! - name: String - description: String @auth(rules: [{ allow: owner, operations: [read] }]) - child: ModelB @hasOne - } - - type ModelB @model @auth(rules: [{ allow: owner }]) { - id: ID! - name: String - } - `; - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - // load vtl templates - const createModelATemplate = out.resolvers['Mutation.createModelA.auth.1.req.vtl']; - const createModelBTemplate = out.resolvers['Mutation.createModelB.auth.1.req.vtl']; - - const createModelBContext = { - arguments: { - input: { - id: '001', - name: 'sample', - }, - }, - }; - const createModelBRequest = vtlTemplate.render(createModelBTemplate, { - context: createModelBContext, - requestParameters: ownerRequest, - }); - expect(createModelBRequest.hadException).toEqual(false); - - const createModelAContext = { - arguments: { - input: { - id: '001', - name: 'sample', - modelAChildId: '001', - }, - }, - }; - const createModelARequest = vtlTemplate.render(createModelATemplate, { - context: createModelAContext, - requestParameters: ownerRequest, - }); - expect(createModelARequest.hadException).toEqual(false); - }); - - test('should allow update with has one with multiple fields and multiple sort key fields', () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner, operations: [create, read, update] }]) { - id: ID! - name: String - comment: Comment @hasOne(fields: ["partOneId", "partTwoId", "partThreeId"]) - partOneId: ID! - partTwoId: ID! - partThreeId: ID! - } - - type Comment @model @auth(rules: [{ allow: owner, operations: [create, read, update] }]) { - id: ID! @primaryKey(sortKeyFields: ["partTwoId", "partThreeId"]) - partTwoId: ID! - partThreeId: ID! - name: String - } - `; - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - // load vtl templates - const createPostTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const createCommentTemplate = out.resolvers['Mutation.createComment.auth.1.req.vtl']; - - const createCommentContext = { - arguments: { - input: { - id: '001', - name: 'sample', - }, - }, - }; - const createCommentRequest = vtlTemplate.render(createCommentTemplate, { - context: createCommentContext, - requestParameters: ownerRequest, - }); - expect(createCommentRequest.hadException).toEqual(false); - - const createPostContext = { - arguments: { - input: { - id: '001', - name: 'sample', - partOneId: '001', - partTwoId: '001', - }, - }, - }; - const createPostRequest = vtlTemplate.render(createPostTemplate, { - context: createPostContext, - requestParameters: ownerRequest, - }); - expect(createPostRequest.hadException).toEqual(false); - - const updatePostTemplate = out.resolvers['Mutation.updatePost.auth.1.res.vtl']; - const updateCommentTemplate = out.resolvers['Mutation.updateComment.auth.1.res.vtl']; - - const updateCommentContext = { - result: { - id: '001', - name: 'updated', - owner: 'user1', - }, - }; - const updateCommentRequest = vtlTemplate.render(updateCommentTemplate, { - context: updateCommentContext, - requestParameters: ownerRequest, - }); - expect(updateCommentRequest.hadException).toEqual(false); - - const updatePostContext = { - result: { - id: '001', - name: 'updated', - owner: 'user1', - }, - }; - const updatePostRequest = vtlTemplate.render(updatePostTemplate, { - context: updatePostContext, - requestParameters: ownerRequest, - }); - expect(updatePostRequest.hadException).toEqual(false); - - const deletePostTemplate = out.resolvers['Mutation.deletePost.auth.1.res.vtl']; - const deleteCommentTemplate = out.resolvers['Mutation.deleteComment.auth.1.res.vtl']; - - const deleteCommentContext = { - result: { - id: '001', - owner: 'user1', - }, - }; - const deleteCommentRequest = vtlTemplate.render(deleteCommentTemplate, { - context: deleteCommentContext, - requestParameters: ownerRequest, - }); - expect(deleteCommentRequest.hadException).toEqual(true); - - const deletePostContext = { - result: { - id: '001', - owner: 'user1', - }, - }; - const deletePostRequest = vtlTemplate.render(deletePostTemplate, { - context: deletePostContext, - requestParameters: ownerRequest, - }); - expect(deletePostRequest.hadException).toEqual(true); - }); -}); - -describe('with identity claim feature flag disabled', () => { - describe('relational tests', () => { - let vtlTemplate: VelocityTemplateSimulator; - let transformer: TestTransform; - const ownerRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user1', 'user1@test.com'), - headers: {}, - }; - const adminGroupRequest: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AMAZON_COGNITO_USER_POOLS, - jwt: getJWTToken(USER_POOL_ID, 'user2', 'user2@test.com', ['admin']), - headers: {}, - }; - const iamAuthRole: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.AWS_IAM, - iamToken: getIAMToken('authRole', { - cognitoIdentityAuthProvider: `cognito-idp.us-fake1.amazonaws.com/${USER_POOL_ID}`, - cognitoIdentityAuthType: 'authenticated', - cognitoIdentityPoolId: `${USER_POOL_ID}:000-111-222`, - cognitoIdentityId: 'us-fake-1:000', - }), - headers: {}, - }; - - beforeEach(() => { - const authConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }; - transformer = { - transform: (schema: string) => - testTransform({ - schema, - authConfig, - transformers: [ - new ModelTransformer(), - new AuthTransformer(), - new PrimaryKeyTransformer(), - new IndexTransformer(), - new HasManyTransformer(), - new HasOneTransformer(), - new BelongsToTransformer(), - ], - transformParameters: { - useSubUsernameForDefaultIdentityClaim: false, - }, - }), - }; - vtlTemplate = new VelocityTemplateSimulator({ authConfig }); - }); - - test('1:1 nested auth read', () => { - // public signed user pools should only be able to read - // blogs and they can't see the editor - const validSchema = ` - type Blog @model @auth(rules: [{ allow: private, operations: [read], provider: userPools }]) { - id: ID! - name: String - title: String - editor: Editor @hasOne(fields: ["id", "name"]) - } - - type Editor @model @auth(rules: [{ allow: owner }]) { - id: ID! @primaryKey(sortKeyFields: ["name"]) - name: String! - email: AWSEmail - }`; - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const listBlogTemplate = out.resolvers['Query.listBlogs.auth.1.req.vtl']; - const blogEditor = out.resolvers['Blog.editor.auth.1.req.vtl']; - - // signed in as a cognito user should not yield unauthorized - const upResponse = vtlTemplate.render(listBlogTemplate, { context: {}, requestParameters: ownerRequest }); - expect(upResponse.hadException).toBe(false); - - // signed in via iam will yield unauthorized - const iamResponse = vtlTemplate.render(listBlogTemplate, { context: {}, requestParameters: iamAuthRole }); - expect(iamResponse.hadException).toBe(true); - expect(iamResponse.errors[0].errorType).toEqual('Unauthorized'); - - // query for blogEditor should have an owner rule filter - const ownerFieldResponse = vtlTemplate.render(blogEditor, { context: {}, requestParameters: ownerRequest }); - expect(ownerFieldResponse.hadException).toBe(false); - expect(ownerFieldResponse.stash.authFilter).toEqual( - expect.objectContaining({ - or: [{ owner: { eq: 'user1' } }], - }), - ); - }); - - test('1:M nested auth read', () => { - // checking for the following cases - // don't apply the authFilter if the owner is not in any valid groups - // remove auth filter if the primaryRole (ex. the owner rule) condition is met - // pass the auth filter if the primaryRole condition is not met - - const validSchema = ` - type Post @model @auth(rules: [{allow: owner}, { allow: groups, groupsField: "editors" }]) { - id: ID! - title: String! - editors: [String] - author: User @belongsTo(fields: ["owner"]) - owner: ID! @index(name: "byOwner", sortKeyFields: ["id"]) - } - - type User @model @auth(rules: [{ allow: owner }]) { - id: ID! - name: String - posts: [Post] @hasMany(indexName: "byOwner", fields: ["id"]) - }`; - const out = transformer.transform(validSchema); - const userPostTemplate = out.resolvers['User.posts.auth.1.req.vtl']; - - // request as admin editor where the user is not the user in the record so therefore the auth filter is applied - const adminWithFilterResponse = vtlTemplate.render(userPostTemplate, { - context: { - source: { id: 'user1' }, - }, - requestParameters: adminGroupRequest, - }); - expect(adminWithFilterResponse.hadException).toEqual(false); - expect(adminWithFilterResponse.stash.authFilter).toEqual( - expect.objectContaining({ - or: [{ editors: { contains: 'admin' } }], - }), - ); - - // response where the editor member is the owner therefore the auth filter does not need to be applied - const adminWithNoFilterResponse = vtlTemplate.render(userPostTemplate, { - context: { - source: { id: 'user2' }, - }, - requestParameters: adminGroupRequest, - }); - expect(adminWithNoFilterResponse.hadException).toEqual(false); - expect(adminWithNoFilterResponse.stash.authFilter).toBeNull(); - - // request as a user that is neither the owner nor has any valid groups - // therefore the request is changed to include the current user to ensure they are only seeing their correct records - // NOTE: will only really happen in the group claim rule is different than that of the related type therefore the - // owner rule should still be enforced - const ownerWithNoFilter = vtlTemplate.render(userPostTemplate, { - context: { - source: { id: 'user3' }, - }, - requestParameters: ownerRequest, - }); - expect(ownerWithNoFilter.hadException).toEqual(false); - expect(ownerWithNoFilter.stash.authFilter).not.toBeDefined(); - }); - - test('has one and partial type access', () => { - const validSchema = ` - type ModelA @model @auth(rules: [{ allow: owner }]) { - id: ID! - name: String - description: String @auth(rules: [{ allow: owner, operations: [read] }]) - child: ModelB @hasOne - } - - type ModelB @model @auth(rules: [{ allow: owner }]) { - id: ID! - name: String - } - `; - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - // load vtl templates - const createModelATemplate = out.resolvers['Mutation.createModelA.auth.1.req.vtl']; - const createModelBTemplate = out.resolvers['Mutation.createModelB.auth.1.req.vtl']; - - const createModelBContext = { - arguments: { - input: { - id: '001', - name: 'sample', - }, - }, - }; - const createModelBRequest = vtlTemplate.render(createModelBTemplate, { - context: createModelBContext, - requestParameters: ownerRequest, - }); - expect(createModelBRequest.hadException).toEqual(false); - - const createModelAContext = { - arguments: { - input: { - id: '001', - name: 'sample', - modelAChildId: '001', - }, - }, - }; - const createModelARequest = vtlTemplate.render(createModelATemplate, { - context: createModelAContext, - requestParameters: ownerRequest, - }); - expect(createModelARequest.hadException).toEqual(false); - }); - - test('should allow update with has one with multiple fields and multiple sort key fields', () => { - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner, operations: [create, read, update] }]) { - id: ID! - name: String - comment: Comment @hasOne(fields: ["partOneId", "partTwoId", "partThreeId"]) - partOneId: ID! - partTwoId: ID! - partThreeId: ID! - } - - type Comment @model @auth(rules: [{ allow: owner, operations: [create, read, update] }]) { - id: ID! @primaryKey(sortKeyFields: ["partTwoId", "partThreeId"]) - partTwoId: ID! - partThreeId: ID! - name: String - } - `; - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - // load vtl templates - const createPostTemplate = out.resolvers['Mutation.createPost.auth.1.req.vtl']; - const createCommentTemplate = out.resolvers['Mutation.createComment.auth.1.req.vtl']; - - const createCommentContext = { - arguments: { - input: { - id: '001', - name: 'sample', - }, - }, - }; - const createCommentRequest = vtlTemplate.render(createCommentTemplate, { - context: createCommentContext, - requestParameters: ownerRequest, - }); - expect(createCommentRequest.hadException).toEqual(false); - - const createPostContext = { - arguments: { - input: { - id: '001', - name: 'sample', - partOneId: '001', - partTwoId: '001', - }, - }, - }; - const createPostRequest = vtlTemplate.render(createPostTemplate, { - context: createPostContext, - requestParameters: ownerRequest, - }); - expect(createPostRequest.hadException).toEqual(false); - - const updatePostTemplate = out.resolvers['Mutation.updatePost.auth.1.res.vtl']; - const updateCommentTemplate = out.resolvers['Mutation.updateComment.auth.1.res.vtl']; - - const updateCommentContext = { - result: { - id: '001', - name: 'updated', - owner: 'user1', - }, - }; - const updateCommentRequest = vtlTemplate.render(updateCommentTemplate, { - context: updateCommentContext, - requestParameters: ownerRequest, - }); - expect(updateCommentRequest.hadException).toEqual(false); - - const updatePostContext = { - result: { - id: '001', - name: 'updated', - owner: 'user1', - }, - }; - const updatePostRequest = vtlTemplate.render(updatePostTemplate, { - context: updatePostContext, - requestParameters: ownerRequest, - }); - expect(updatePostRequest.hadException).toEqual(false); - - const deletePostTemplate = out.resolvers['Mutation.deletePost.auth.1.res.vtl']; - const deleteCommentTemplate = out.resolvers['Mutation.deleteComment.auth.1.res.vtl']; - - const deleteCommentContext = { - result: { - id: '001', - owner: 'user1', - }, - }; - const deleteCommentRequest = vtlTemplate.render(deleteCommentTemplate, { - context: deleteCommentContext, - requestParameters: ownerRequest, - }); - expect(deleteCommentRequest.hadException).toEqual(true); - - const deletePostContext = { - result: { - id: '001', - owner: 'user1', - }, - }; - const deletePostRequest = vtlTemplate.render(deletePostTemplate, { - context: deletePostContext, - requestParameters: ownerRequest, - }); - expect(deletePostRequest.hadException).toEqual(true); - }); - }); -}); diff --git a/packages/amplify-util-mock/src/__tests__/velocity/vtl-behavior.test.ts b/packages/amplify-util-mock/src/__tests__/velocity/vtl-behavior.test.ts deleted file mode 100644 index 9fd8dce8c1..0000000000 --- a/packages/amplify-util-mock/src/__tests__/velocity/vtl-behavior.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; -import { AmplifyAppSyncSimulatorAuthenticationType, AppSyncGraphQLExecutionContext } from '@aws-amplify/amplify-appsync-simulator'; -import { VelocityTemplateSimulator, AppSyncVTLContext } from '../../velocity'; - -describe('VTL behavior', () => { - let vtlTemplate: VelocityTemplateSimulator; - - beforeEach(() => { - const authConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }; - vtlTemplate = new VelocityTemplateSimulator({ authConfig }); - }); - - test('Integer.parseInt()', () => { - const context: AppSyncVTLContext = { arguments: { input: { value: '42' } } }; - const request: AppSyncGraphQLExecutionContext = { - requestAuthorizationMode: AmplifyAppSyncSimulatorAuthenticationType.API_KEY, - headers: {}, - }; - - const template = ` - #set( $value = 1 ) - $util.toJson($value.parseInt($ctx.args.input.value)) - `; - const output = vtlTemplate.render(template, { context, requestParameters: request }); - - expect(output.result).toEqual(42); - expect(output.errors).toEqual([]); - expect(output.isReturn).toEqual(false); - expect(output.hadException).toEqual(false); - }); -}); diff --git a/packages/amplify-util-mock/src/amplify-plugin-index.ts b/packages/amplify-util-mock/src/amplify-plugin-index.ts deleted file mode 100644 index e9e309eefd..0000000000 --- a/packages/amplify-util-mock/src/amplify-plugin-index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import * as path from 'path'; - -const pluginName = 'mock'; - -export async function executeAmplifyCommand(context: any) { - const commandPath = path.normalize(path.join(__dirname, 'commands', pluginName, context.input.command)); - const commandModule = await import(commandPath); - await commandModule.run(context); -} - -export async function handleAmplifyEvent(context: any, args: any) { - context.print.info(`${pluginName} handleAmplifyEvent to be implemented`); - context.print.info(`Received event args ${args}`); -} diff --git a/packages/amplify-util-mock/src/api/api.ts b/packages/amplify-util-mock/src/api/api.ts deleted file mode 100644 index 304e9c0c6f..0000000000 --- a/packages/amplify-util-mock/src/api/api.ts +++ /dev/null @@ -1,352 +0,0 @@ -import * as path from 'path'; -import * as fs from 'fs-extra'; -import * as dynamoEmulator from 'amplify-category-api-dynamodb-simulator'; -import { AmplifyAppSyncSimulator, AmplifyAppSyncSimulatorConfig } from '@aws-amplify/amplify-appsync-simulator'; -import { add, generate, isCodegenConfigured, switchToSDLSchema } from 'amplify-codegen'; -import * as chokidar from 'chokidar'; - -import { getInvoker } from '@aws-amplify/amplify-category-function'; -import { getAmplifyMeta, getMockDataDirectory, checkJavaVersion } from '../utils'; -import { processAppSyncResources } from '../CFNParser'; -import { ConfigOverrideManager } from '../utils/config-override'; -import { configureDDBDataSource, createAndUpdateTable } from '../utils/dynamo-db'; -import { getMockConfig } from '../utils/mock-config-file'; -import { timeConstrainedInvoker } from '../func'; -import { lambdaArnToConfig } from './lambda-arn-to-config'; -import { ResolverOverrides } from './resolver-overrides'; -import { runTransformer } from './run-graphql-transformer'; - -export const GRAPHQL_API_ENDPOINT_OUTPUT = 'GraphQLAPIEndpointOutput'; -export const GRAPHQL_API_KEY_OUTPUT = 'GraphQLAPIKeyOutput'; -export const MOCK_API_KEY = 'da2-fakeApiId123456'; -export const MOCK_API_PORT = 20002; - -export class APITest { - private apiName: string; - - private transformerResult: any; - - private ddbClient; - - private appSyncSimulator: AmplifyAppSyncSimulator; - - private resolverOverrideManager: ResolverOverrides; - - private watcher: chokidar.FSWatcher; - - private ddbEmulator; - - private configOverrideManager: ConfigOverrideManager; - - private apiParameters: object = {}; - - private userOverriddenSlots: string[] = []; - - async start(context, port: number = MOCK_API_PORT, wsPort: number = 20003) { - try { - context.amplify.addCleanUpTask(async (context) => { - await this.stop(context); - }); - this.configOverrideManager = await ConfigOverrideManager.getInstance(context); - // check java version - await checkJavaVersion(context); - this.apiName = await this.getAppSyncAPI(context); - this.ddbClient = await this.startDynamoDBLocalServer(context); - const resolverDirectory = await this.getResolverTemplateDirectory(context); - this.resolverOverrideManager = new ResolverOverrides(resolverDirectory); - this.apiParameters = await this.loadAPIParameters(context); - this.appSyncSimulator = new AmplifyAppSyncSimulator({ - port, - wsPort, - }); - await this.appSyncSimulator.start(); - await this.resolverOverrideManager.start(); - await this.watch(context); - const appSyncConfig: AmplifyAppSyncSimulatorConfig = await this.runTransformer(context, this.apiParameters); - this.appSyncSimulator.init(appSyncConfig); - - await this.generateTestFrontendExports(context); - await this.generateCode(context, appSyncConfig); - - context.print.info(`AppSync Mock endpoint is running at ${this.appSyncSimulator.url}`); - } catch (e) { - context.print.error(`Failed to start API Mock endpoint ${e}`); - } - } - - async stop(context) { - this.ddbClient = null; - if (this.watcher) { - await this.watcher.close(); - this.watcher = null; - } - try { - if (this.ddbEmulator) { - await this.ddbEmulator.terminate(); - this.ddbEmulator = null; - } - } catch (e) { - // failed to stop DDB emulator - context.print.error(`Failed to stop DynamoDB Local Server ${e.message}`); - } - - await this.appSyncSimulator.stop(); - this.resolverOverrideManager.stop(); - } - - private async runTransformer(context, parameters = {}) { - const { transformerOutput } = await runTransformer(context); - let config: any = processAppSyncResources(transformerOutput, parameters); - await this.ensureDDBTables(config); - config = this.configureDDBDataSource(config); - this.transformerResult = await this.configureLambdaDataSource(context, config); - this.userOverriddenSlots = transformerOutput.userOverriddenSlots; - const overriddenTemplates = await this.resolverOverrideManager.sync(this.transformerResult.mappingTemplates, this.userOverriddenSlots); - return { ...this.transformerResult, mappingTemplates: overriddenTemplates }; - } - - private async generateCode(context: any, config: AmplifyAppSyncSimulatorConfig = null) { - try { - context.print.info('Running GraphQL codegen'); - const { projectPath } = context.amplify.getEnvInfo(); - const schemaPath = path.join(projectPath, 'amplify', 'backend', 'api', this.apiName, 'build', 'schema.graphql'); - if (config && config.schema) { - fs.writeFileSync(schemaPath, config.schema.content); - } - if (!isCodegenConfigured(context, this.apiName)) { - await add(context); - } else { - switchToSDLSchema(context, this.apiName); - await generate(context); - } - } catch (e) { - context.print.info(`Failed to run GraphQL codegen with following error:\n${e.message}`); - } - } - - private async reload(context, filePath, action) { - const apiDir = await this.getAPIBackendDirectory(context); - const inputSchemaPath = path.join(apiDir, 'schema'); - const customStackPath = path.join(apiDir, 'stacks'); - const parameterFilePath = await this.getAPIParameterFilePath(context); - try { - let shouldReload; - if (this.resolverOverrideManager.isTemplateFile(filePath, action === 'unlink')) { - switch (action) { - case 'add': - shouldReload = this.resolverOverrideManager.onAdd(filePath); - break; - case 'change': - shouldReload = this.resolverOverrideManager.onChange(filePath); - break; - case 'unlink': - shouldReload = this.resolverOverrideManager.onUnlink(filePath); - break; - } - - if (shouldReload) { - context.print.info('Mapping template change detected. Reloading...'); - const mappingTemplates = this.resolverOverrideManager.sync(this.transformerResult.mappingTemplates, this.userOverriddenSlots); - await this.appSyncSimulator.reload({ - ...this.transformerResult, - mappingTemplates, - }); - } - } else if (filePath.includes(inputSchemaPath)) { - context.print.info('GraphQL Schema change detected. Reloading...'); - const config: AmplifyAppSyncSimulatorConfig = await this.runTransformer(context, this.apiParameters); - await this.appSyncSimulator.reload(config); - await this.generateCode(context, config); - } else if (filePath.includes(parameterFilePath)) { - const apiParameters = await this.loadAPIParameters(context); - if (JSON.stringify(apiParameters) !== JSON.stringify(this.apiParameters)) { - context.print.info('API Parameter change detected. Reloading...'); - this.apiParameters = apiParameters; - const config = await this.runTransformer(context, this.apiParameters); - await this.appSyncSimulator.reload(config); - await this.generateCode(context, config); - } - } else if (filePath.includes(customStackPath)) { - context.print.info('Custom stack change detected. Reloading...'); - const config = await this.runTransformer(context, this.apiParameters); - await this.appSyncSimulator.reload(config); - await this.generateCode(context, config); - } - } catch (e) { - context.print.info(`Reloading failed with error\n${e}`); - } - } - - private async generateTestFrontendExports(context) { - await this.generateFrontendExports(context, { - endpoint: `${this.appSyncSimulator.url}/graphql`, - name: this.apiName, - GraphQLAPIKeyOutput: this.transformerResult.appSync.apiKey, - additionalAuthenticationProviders: [], - securityType: this.transformerResult.appSync.authenticationType, - testMode: true, - }); - } - - private async ensureDDBTables(config) { - const tables = config.tables.map((t) => t.Properties); - await createAndUpdateTable(this.ddbClient, config); - } - - private async configureLambdaDataSource(context, config) { - const lambdaDataSources = config.dataSources.filter((d) => d.type === 'AWS_LAMBDA'); - if (lambdaDataSources.length === 0) { - return config; - } - return { - ...config, - dataSources: await Promise.all( - config.dataSources.map(async (d) => { - if (d.type !== 'AWS_LAMBDA') { - return d; - } - const lambdaConfig = await lambdaArnToConfig(context, d.LambdaFunctionArn); - const invoker = await getInvoker(context, { - resourceName: lambdaConfig.name, - handler: lambdaConfig.handler, - envVars: lambdaConfig.environment, - }); - return { - ...d, - invoke: (payload) => { - return timeConstrainedInvoker( - invoker({ - event: payload, - }), - context.input.options, - ); - }, - }; - }), - ), - }; - } - - private async watch(context) { - this.watcher = await this.registerWatcher(context); - this.watcher - .on('add', (path) => { - this.reload(context, path, 'add'); - }) - .on('change', (path) => { - this.reload(context, path, 'change'); - }) - .on('unlink', (path) => { - this.reload(context, path, 'unlink'); - }); - } - - private configureDDBDataSource(config) { - const ddbConfig = this.ddbClient.config; - return configureDDBDataSource(config, ddbConfig); - } - - private async getAppSyncAPI(context) { - const currentMeta = await getAmplifyMeta(context); - const { api: apis = {} } = currentMeta; - let appSyncApi = null; - let name = null; - Object.entries(apis).some((entry: any) => { - if (entry[1].service === 'AppSync' && entry[1].providerPlugin === 'awscloudformation') { - appSyncApi = entry[1]; - name = entry[0]; - return true; - } - }); - if (!name) { - throw new Error('No AppSync API is added to the project'); - } - return name; - } - - private async startDynamoDBLocalServer(context) { - const dbPath = path.join(await getMockDataDirectory(context), 'dynamodb'); - fs.ensureDirSync(dbPath); - const mockConfig = await getMockConfig(context); - this.ddbEmulator = await dynamoEmulator.launch({ - dbPath, - port: null, - ...mockConfig, - }); - return dynamoEmulator.getClient(this.ddbEmulator); - } - - private async getAPIBackendDirectory(context) { - const { projectPath } = context.amplify.getEnvInfo(); - return path.join(projectPath, 'amplify', 'backend', 'api', this.apiName); - } - - private async getAPIParameterFilePath(context): Promise { - const backendPath = await this.getAPIBackendDirectory(context); - return path.join(backendPath, 'parameters.json'); - } - - private async loadAPIParameters(context): Promise { - const paramPath = await this.getAPIParameterFilePath(context); - if (!fs.existsSync(paramPath)) { - return {}; - } - try { - return JSON.parse(fs.readFileSync(paramPath, 'utf8')); - } catch (e) { - e.message = `Failed to load API parameters.json \n ${e.message}`; - throw e; - } - } - - private async getResolverTemplateDirectory(context) { - const apiDirectory = await this.getAPIBackendDirectory(context); - return apiDirectory; - } - - private async registerWatcher(context: any): Promise { - const watchDir = await this.getAPIBackendDirectory(context); - return chokidar.watch(watchDir, { - interval: 100, - ignoreInitial: true, - followSymlinks: false, - ignored: '**/build/**', - awaitWriteFinish: true, - }); - } - - private async generateFrontendExports( - context: any, - localAppSyncDetails: { - name: string; - endpoint: string; - securityType: string; - additionalAuthenticationProviders: string[]; - GraphQLAPIKeyOutput?: string; - region?: string; - testMode: boolean; - }, - ) { - const currentMeta = await getAmplifyMeta(context); - const override = currentMeta.api || {}; - if (localAppSyncDetails) { - const appSyncApi = override[localAppSyncDetails.name] || { output: {} }; - override[localAppSyncDetails.name] = { - service: 'AppSync', - ...appSyncApi, - output: { - ...appSyncApi.output, - GraphQLAPIEndpointOutput: localAppSyncDetails.endpoint, - projectRegion: localAppSyncDetails.region, - aws_appsync_authenticationType: localAppSyncDetails.securityType, - GraphQLAPIKeyOutput: localAppSyncDetails.GraphQLAPIKeyOutput, - }, - testMode: localAppSyncDetails.testMode, - lastPushTimeStamp: new Date(), - }; - } - - this.configOverrideManager.addOverride('api', override); - await this.configOverrideManager.generateOverriddenFrontendExports(context); - } -} diff --git a/packages/amplify-util-mock/src/api/index.ts b/packages/amplify-util-mock/src/api/index.ts deleted file mode 100644 index 960c05dec1..0000000000 --- a/packages/amplify-util-mock/src/api/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { addMockDataToGitIgnore } from '../utils'; -import { APITest } from './api'; - -export async function start(context) { - const testApi = new APITest(); - try { - addMockDataToGitIgnore(context); - await testApi.start(context); - } catch (e) { - console.log(e); - // Sending term signal so we clean up after ourselves - process.kill(process.pid, 'SIGTERM'); - } -} diff --git a/packages/amplify-util-mock/src/api/lambda-arn-to-config.ts b/packages/amplify-util-mock/src/api/lambda-arn-to-config.ts deleted file mode 100644 index d010d11757..0000000000 --- a/packages/amplify-util-mock/src/api/lambda-arn-to-config.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { keys } from 'lodash'; -import { $TSContext, stateManager, getGraphQLTransformerFunctionDocLink, ApiCategoryFacade } from '@aws-amplify/amplify-cli-core'; -import _ = require('lodash'); -import { ServiceName } from '@aws-amplify/amplify-category-function'; -import { loadLambdaConfig } from '../utils/lambda/load-lambda-config'; -import { ProcessedLambdaFunction } from '../CFNParser/stack/types'; - -/** - * Attempts to match an arn object against the array of lambdas configured in the project - */ -export const lambdaArnToConfig = async (context: $TSContext, arn: any): Promise => { - const version = await ApiCategoryFacade.getTransformerVersion(context); - const doclink = getGraphQLTransformerFunctionDocLink(version); - const errorSuffix = `\nSee ${doclink} for information on how to configure Lambda resolvers.`; - let searchString = ''; - if (typeof arn === 'string') { - searchString = arn; - } else if (typeof arn === 'object' && keys(arn).length === 1) { - const value = arn['Fn::GetAtt'] || arn['Fn::Sub']; - if (Array.isArray(value) && value.length > 0) { - searchString = value[0]; - } else if (typeof value === 'string') { - searchString = value; - } else { - throw new Error(`Malformed Lambda ARN [${JSON.stringify(arn)}]${errorSuffix}`); - } - } else { - throw new Error(`Cannot interpret Lambda ARN [${JSON.stringify(arn)}]${errorSuffix}`); - } - const lambdaNames = _.entries<{ service: string }>(_.get(stateManager.getMeta(), ['function'])) - .filter(([_, funcMeta]) => funcMeta.service === ServiceName.LambdaFunction) - .map(([key]) => key); - const foundLambdaName = lambdaNames.find((name) => searchString.includes(name)); - if (!foundLambdaName) { - throw new Error( - `Did not find a Lambda matching ARN [${JSON.stringify( - arn, - )}] in the project. Local mocking only supports Lambdas that are configured in the project.${errorSuffix}`, - ); - } - // lambdaArnToConfig is only called in the context of initializing a mock API, so setting overrideApiToLocal to true here - return loadLambdaConfig(context, foundLambdaName, true); -}; diff --git a/packages/amplify-util-mock/src/api/resolver-overrides.ts b/packages/amplify-util-mock/src/api/resolver-overrides.ts deleted file mode 100644 index 8fc15b89d2..0000000000 --- a/packages/amplify-util-mock/src/api/resolver-overrides.ts +++ /dev/null @@ -1,190 +0,0 @@ -import * as path from 'path'; -import * as fs from 'fs-extra'; -import * as chokidar from 'chokidar'; - -export class ResolverOverrides { - private overrides: Set; - - private contentMap: Map; - - constructor( - private _rootFolder: string, - private _foldersToWatch: string[] = ['resolvers', 'pipelineFunctions', 'functions'], - private fileExtensions: string[] = ['.vtl'], - ) { - this.overrides = new Set(); - this.contentMap = new Map(); - this.start(); - } - - start() { - this._foldersToWatch - .map((folder) => path.join(this._rootFolder, folder)) - .forEach((folder) => { - if (fs.existsSync(folder) && fs.lstatSync(folder).isDirectory()) { - fs.readdirSync(folder) - .map((f) => path.join(folder, f)) - .filter((f) => this.isTemplateFile(f)) - .forEach((f) => { - this.updateContentMap(f); - }); - } - }); - } - - onFileChange(filePath: string) { - if (!this.isTemplateFile(filePath)) { - return false; - } - return this.updateContentMap(filePath); - } - - sync(transformerResolvers: { path: string; content: string }[], userOverriddenSlots: string[]) { - const filesToWrite: Map = new Map(); - const filesToDelete: Set = new Set(); - const result: { - path: string; - content: string; - }[] = transformerResolvers.map((resolver) => { - const r = { ...resolver }; - const normalizedPath = path.normalize(resolver.path); - // Step 1: Check if the file is in the override map and if it really is - // different from transformer generated file or its here because it was not - // deleted from last execution - if (this.overrides.has(normalizedPath)) { - const overriddenContent = this.contentMap.get(normalizedPath); - if (overriddenContent === resolver.content && !userOverriddenSlots.includes(path.basename(normalizedPath))) { - this.overrides.delete(normalizedPath); - } else { - r.content = overriddenContent; - } - } else { - // Step 2. The file is not in content map. Its a new created by transformer - if (this.contentMap.has(normalizedPath)) { - // existing file, not a newly created file - const diskFileContent = this.contentMap.get(normalizedPath); - if (diskFileContent !== resolver.content) { - filesToWrite.set(normalizedPath, resolver.content); - } - } else { - // new resolver created by transformer - filesToWrite.set(normalizedPath, resolver.content); - } - r.content = resolver.content; - } - return r; - }); - - // Populate the list of files that needs to be deleted - const generatedResolverPath = transformerResolvers.map((r) => r.path); - this.contentMap.forEach((val, resolverPath) => { - if (!this.overrides.has(resolverPath) && !generatedResolverPath.includes(resolverPath)) { - filesToDelete.add(resolverPath); - } - }); - - // Files that are in the disk used by resolvers created by custom stack will exist in resolver folder - // include them in the resolver output - const resolversCreatedByTransformer = result.map((r) => r.path); - const customResolverTemplates = Array.from(this.overrides.values()).filter((o) => !resolversCreatedByTransformer.includes(o)); - customResolverTemplates.forEach((templateName) => { - result.push({ - path: templateName, - content: this.contentMap.get(templateName), - }); - }); - - // Write files to disk - filesToWrite.forEach((content, filePath) => { - // Update the content in the map - this.contentMap.set(filePath, content); - const abPath = this.getAbsPath(filePath); - fs.ensureFileSync(abPath); - fs.writeFileSync(abPath, content); - }); - - // Delete the files that are no longer needed - filesToDelete.forEach((filePath) => { - this.contentMap.delete(filePath); - fs.unlinkSync(this.getAbsPath(filePath)); - }); - return result; - } - - /** - * Stop synchronizing resolver content. This will delete all the resolvers except for - * the ones which are not overridden - */ - stop() { - this.contentMap.forEach((val, filePath) => { - if (!this.overrides.has(filePath)) { - fs.unlinkSync(this.getAbsPath(filePath)); - } - }); - } - - isTemplateFile(filePath: string, isDelete: boolean = false): boolean { - if (!this.fileExtensions.includes(path.extname(filePath))) { - return false; - } - const isInWatchedDir = this._foldersToWatch.some((folder) => { - const absFolder = path.join(this._rootFolder, folder); - return filePath.includes(absFolder); - }); - - if (!isInWatchedDir) { - return false; - } - - // When a file is unlinked, checking if the path is a file does not make sense - if (isDelete) { - return true; - } - - if (fs.lstatSync(filePath).isFile()) { - return true; - } - return false; - } - - private updateContentMap(filePath: string) { - const relativePath = this.getRelativePath(filePath); - const content = fs.readFileSync(filePath).toString(); - if (content.trim() !== '' && this.contentMap.get(relativePath) !== content) { - this.contentMap.set(relativePath, content); - this.overrides.add(relativePath); - return true; - } - return false; - } - - private getRelativePath(filePath: string) { - return path.relative(this.resolverTemplateRoot, filePath); - } - - private getAbsPath(filename: string) { - return path.normalize(path.join(this.resolverTemplateRoot, filename)); - } - - onAdd(path: string): boolean { - return this.onFileChange(path); - } - - onChange(path: string): boolean { - return this.onFileChange(path); - } - - onUnlink(path: string): boolean { - const relativePath = this.getRelativePath(path); - this.contentMap.delete(relativePath); - if (this.overrides.has(relativePath)) { - this.overrides.delete(relativePath); - return true; - } - return false; - } - - get resolverTemplateRoot() { - return this._rootFolder; - } -} diff --git a/packages/amplify-util-mock/src/api/run-graphql-transformer.ts b/packages/amplify-util-mock/src/api/run-graphql-transformer.ts deleted file mode 100644 index ad5eac4d2c..0000000000 --- a/packages/amplify-util-mock/src/api/run-graphql-transformer.ts +++ /dev/null @@ -1,11 +0,0 @@ -export async function runTransformer(context: any) { - const transformerOutput = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { - noConfig: true, - forceCompile: true, - dryRun: true, - disableResolverOverrides: true, - disableFunctionOverrides: true, - disablePipelineFunctionOverrides: true, - }); - return { transformerOutput }; -} diff --git a/packages/amplify-util-mock/src/commands/mock/api.ts b/packages/amplify-util-mock/src/commands/mock/api.ts deleted file mode 100644 index 612524e33b..0000000000 --- a/packages/amplify-util-mock/src/commands/mock/api.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { start } from '../../api'; - -export const name = 'api'; - -export const run = async (context: $TSContext) => { - if (context.parameters.options.help) { - const header = `amplify mock ${name} \nDescription: - Mock GraphQL API locally`; - context.amplify.showHelp(header, []); - return; - } - try { - await start(context); - } catch (e) { - context.print.error(e.message); - } -}; diff --git a/packages/amplify-util-mock/src/commands/mock/function.ts b/packages/amplify-util-mock/src/commands/mock/function.ts deleted file mode 100644 index 3754895d38..0000000000 --- a/packages/amplify-util-mock/src/commands/mock/function.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { start } from '../../func'; - -export const name = 'function'; - -export const run = async (context: $TSContext) => { - if (context.parameters.options.help) { - const header = `amplify mock ${name} \nDescriptions: - Mock Functions locally`; - context.amplify.showHelp(header, []); - return; - } - try { - await start(context); - } catch (e) { - context.print.error(e.message); - } -}; diff --git a/packages/amplify-util-mock/src/commands/mock/help.ts b/packages/amplify-util-mock/src/commands/mock/help.ts deleted file mode 100644 index 30a1112d24..0000000000 --- a/packages/amplify-util-mock/src/commands/mock/help.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; - -export const name = 'help'; - -export const run = (context: $TSContext) => { - const header = `amplify ${name} [subcommand]\nDescription:\nMock resources locally`; - - const commands = [ - { - name: 'storage', - description: 'Run Storage Mock Endpoint', - }, - { - name: 'api', - description: 'Run GraphQL API Mock Endpoint', - }, - { - name: 'function ', - description: 'Invoke Function locally', - }, - ]; - context.amplify.showHelp(header, commands); - return; -}; diff --git a/packages/amplify-util-mock/src/commands/mock/mock.ts b/packages/amplify-util-mock/src/commands/mock/mock.ts deleted file mode 100644 index 43bc9f148a..0000000000 --- a/packages/amplify-util-mock/src/commands/mock/mock.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { mockAllCategories } from '../../mockAll'; -import { run as runHelp } from './help'; - -export const name = 'mock'; - -export const run = async (context: $TSContext) => { - if (context.parameters.options.help) { - return runHelp(context); - } - await mockAllCategories(context); -}; diff --git a/packages/amplify-util-mock/src/commands/mock/storage.ts b/packages/amplify-util-mock/src/commands/mock/storage.ts deleted file mode 100644 index 16e95d3f28..0000000000 --- a/packages/amplify-util-mock/src/commands/mock/storage.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { $TSContext } from '@aws-amplify/amplify-cli-core'; -import { start } from '../../storage'; - -export const name = 'storage'; - -export const run = async (context: $TSContext) => { - if (context.parameters.options.help) { - const header = `amplify mock ${name} \nDescriptions: - Mock Storage locally`; - context.amplify.showHelp(header, []); - return; - } - try { - await start(context); - } catch (e) { - context.print.error(e.message); - } -}; diff --git a/packages/amplify-util-mock/src/func/index.ts b/packages/amplify-util-mock/src/func/index.ts deleted file mode 100644 index 3643de51a4..0000000000 --- a/packages/amplify-util-mock/src/func/index.ts +++ /dev/null @@ -1,128 +0,0 @@ -import * as path from 'path'; -import { getInvoker, category, isMockable, getBuilder } from '@aws-amplify/amplify-category-function'; -import * as inquirer from 'inquirer'; -import { $TSContext, JSONUtilities, pathManager, stateManager } from '@aws-amplify/amplify-cli-core'; -import _ from 'lodash'; -import { BuildType } from 'amplify-function-plugin-interface'; -import { loadLambdaConfig } from '../utils/lambda/load-lambda-config'; - -const DEFAULT_TIMEOUT_SECONDS = 10; - -export async function start(context: $TSContext) { - const ampMeta = stateManager.getMeta(); - let resourceName = context?.input?.subCommands?.[0]; - if (!resourceName) { - const choices = _.keys(_.get(ampMeta, ['function'])).filter((resourceName) => isMockable(context, resourceName).isMockable); - if (choices.length < 1) { - throw new Error('There are no mockable functions in the project. Use `amplify add function` to create one.'); - } else if (choices.length == 1) { - resourceName = choices[0]; - } else { - const resourceNameQuestion = [ - { - type: 'list', - name: 'resourceName', - message: 'Select the function to mock', - choices, - }, - ]; - ({ resourceName } = await inquirer.prompt<{ resourceName: string }>(resourceNameQuestion)); - } - } else { - const mockable = isMockable(context, resourceName); - if (!mockable.isMockable) { - throw new Error(`Unable to mock ${resourceName}. ${mockable.reason}`); - } - } - - const event = await resolveEvent(context, resourceName); - const lambdaConfig = await loadLambdaConfig(context, resourceName); - if (!lambdaConfig?.handler) { - throw new Error(`Could not parse handler for ${resourceName} from cloudformation file`); - } - context.print.blue('Ensuring latest function changes are built...'); - await getBuilder(context, resourceName, BuildType.DEV)(); - const invoker = await getInvoker(context, { resourceName, handler: lambdaConfig.handler, envVars: lambdaConfig.environment }); - context.print.blue('Starting execution...'); - try { - const result = await timeConstrainedInvoker(invoker({ event }), context.input.options as any); - const stringResult = - typeof result === 'object' ? JSON.stringify(result, undefined, 2) : typeof result === 'undefined' ? 'undefined' : result; - context.print.success('Result:'); - context.print.info(typeof result === 'undefined' ? '' : stringResult); - } catch (err) { - context.print.error(`${resourceName} failed with the following error:`); - context.print.info(err); - } finally { - context.print.blue('Finished execution.'); - } -} - -interface InvokerOptions { - timeout?: string; -} -export const timeConstrainedInvoker = async (promise: Promise, options?: InvokerOptions): Promise => { - const { timer, cancel } = getCancellableTimer(options); - try { - return await Promise.race([promise, timer]); - } finally { - cancel(); - } -}; - -const getCancellableTimer = ({ timeout }: InvokerOptions = {}) => { - const inputTimeout = Number.parseInt(timeout, 10); - const lambdaTimeoutSeconds = !!inputTimeout && inputTimeout > 0 ? inputTimeout : DEFAULT_TIMEOUT_SECONDS; - const timeoutErrorMessage = `Lambda execution timed out after ${lambdaTimeoutSeconds} seconds. Press ctrl + C to exit the process. - To increase the lambda timeout use the --timeout parameter to set a value in seconds. - Note that the maximum Lambda execution time is 15 minutes: - https://aws.amazon.com/about-aws/whats-new/2018/10/aws-lambda-supports-functions-that-can-run-up-to-15-minutes/\n`; - let timeoutObj; - const timer = new Promise((_, reject) => { - timeoutObj = setTimeout(() => reject(new Error(timeoutErrorMessage)), lambdaTimeoutSeconds * 1000); - }); - const cancel = () => clearTimeout(timeoutObj); - return { timer, cancel }; -}; - -const resolveEvent = async (context: $TSContext, resourceName: string): Promise => { - const { amplify } = context; - const resourcePath = path.join(pathManager.getBackendDirPath(), category, resourceName); - const eventNameValidator = amplify.inputValidation({ - operator: 'regex', - value: '^[a-zA-Z0-9/._-]+?\\.json$', - onErrorMsg: 'Provide a valid unix-like path to a .json file', - required: true, - }); - let eventName: string = context.input.options ? context.input.options.event : undefined; - let promptForEvent = true; - if (eventName) { - const validatorOutput = eventNameValidator(eventName); - const isValid = typeof validatorOutput !== 'string'; - if (!isValid) { - context.print.warning(validatorOutput as string); - } else { - promptForEvent = false; - } - } - - if (promptForEvent) { - const eventNameQuestion = [ - { - type: 'input', - name: 'eventName', - message: `Provide the path to the event JSON object relative to ${resourcePath}`, - validate: eventNameValidator, - default: 'src/event.json', - }, - ]; - const resourceAnswers = await inquirer.prompt(eventNameQuestion); - eventName = resourceAnswers.eventName as string; - } - - return JSONUtilities.readJson(path.resolve(path.join(resourcePath, eventName))); -}; - -interface InvokerOptions { - timeout?: string; -} diff --git a/packages/amplify-util-mock/src/index.ts b/packages/amplify-util-mock/src/index.ts deleted file mode 100644 index a6bf1a27a8..0000000000 --- a/packages/amplify-util-mock/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './amplify-plugin-index'; diff --git a/packages/amplify-util-mock/src/mockAll.ts b/packages/amplify-util-mock/src/mockAll.ts deleted file mode 100644 index 652558203c..0000000000 --- a/packages/amplify-util-mock/src/mockAll.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { ServiceName as FunctionServiceName } from '@aws-amplify/amplify-category-function'; -import { start as startAppSyncServer } from './api'; -import { start as startS3Server } from './storage'; - -const MOCK_SUPPORTED_CATEGORY = ['AppSync', 'S3', FunctionServiceName.LambdaFunction]; - -export async function mockAllCategories(context: any) { - const resources = await context.amplify.getResourceStatus(); - const mockableResources = resources.allResources.filter( - (resource) => resource.service && MOCK_SUPPORTED_CATEGORY.includes(resource.service), - ); - const resourceToBePushed = [...resources.resourcesToBeUpdated, ...resources.resourcesToBeCreated].filter( - (resource) => resource.service && !MOCK_SUPPORTED_CATEGORY.includes(resource.service), - ); - if (mockableResources.length) { - if (resourceToBePushed.length) { - try { - // push these resources - context.print.info( - 'Some resources have changed locally and these resources are not mockable. The resources listed below need to be pushed to the cloud before starting the mock server.', - ); - const didPush = await context.amplify.pushResources(context, undefined, undefined, resourceToBePushed); - if (!didPush) { - context.print.info('\n\nMocking may not work as expected since some of the changed resources were not pushed.'); - } - } catch (e) { - context.print.info(`Pushing to the cloud failed with the following error \n${e.message}\n\n`); - const startServer = await await context.amplify.confirmPrompt('Do you still want to start the mock server?'); - if (!startServer) { - return; - } - } - } - // Run the mock servers - const serverPromises = []; - if (mockableResources.find((r) => r.service === 'AppSync')) { - serverPromises.push(startAppSyncServer(context)); - } - if (mockableResources.find((r) => r.service === 'S3')) { - serverPromises.push(startS3Server(context)); - } - await Promise.all(serverPromises); - } else { - context.print.info('No resource in project can be mocked locally.'); - } -} diff --git a/packages/amplify-util-mock/src/storage/index.ts b/packages/amplify-util-mock/src/storage/index.ts deleted file mode 100644 index 0d02eee677..0000000000 --- a/packages/amplify-util-mock/src/storage/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { StorageTest } from './storage'; - -const MOCK_SUPPORTED_CATEGORY = ['S3']; -const RESOURCE_NEEDS_PUSH = ['Cognito']; - -export async function start(context) { - const resources = await context.amplify.getResourceStatus(); - const mockableResources = resources.allResources.filter( - (resource) => resource.service && MOCK_SUPPORTED_CATEGORY.includes(resource.service), - ); - const resourceToBePushed = [...resources.resourcesToBeCreated].filter( - (resource) => resource.service && RESOURCE_NEEDS_PUSH.includes(resource.service), - ); - - if (mockableResources.length) { - if (resourceToBePushed.length) { - context.print.info( - 'Storage Mocking needs Auth resources to be pushed to the cloud. Please run `amplify auth push` before running storage mock', - ); - return Promise.resolve(false); - } - const mockStorage = new StorageTest(); - try { - await mockStorage.start(context); - // call s3 trigger - await mockStorage.trigger(context); - } catch (e) { - console.log(e); - // Sending term signal so we clean up after ourself - process.kill(process.pid, 'SIGTERM'); - } - } -} diff --git a/packages/amplify-util-mock/src/storage/storage.ts b/packages/amplify-util-mock/src/storage/storage.ts deleted file mode 100644 index bc0ee7bea0..0000000000 --- a/packages/amplify-util-mock/src/storage/storage.ts +++ /dev/null @@ -1,208 +0,0 @@ -import * as path from 'path'; -import { AmplifyStorageSimulator } from 'amplify-storage-simulator'; -import * as fs from 'fs-extra'; -import { getInvoker } from '@aws-amplify/amplify-category-function'; -import { $TSContext, JSONUtilities } from '@aws-amplify/amplify-cli-core'; -import { getAmplifyMeta, getMockDataDirectory } from '../utils'; -import { ConfigOverrideManager } from '../utils/config-override'; -import { loadLambdaConfig } from '../utils/lambda/load-lambda-config'; - -const port = 20005; // port for S3 - -/** - * @returns Name of S3 resource or undefined - */ -async function invokeS3GetResourceName(context) { - const s3ResourceName = await context.amplify.invokePluginMethod(context, 'storage', undefined, 's3GetResourceName', [context]); - return s3ResourceName; -} - -/** - * Return the cli-inputs.json - * @param context - * @param s3ResourceName - * @returns - */ -async function invokeS3GetUserInputs(context, s3ResourceName) { - const s3UserInputs = await context.amplify.invokePluginMethod(context, 'storage', undefined, 's3GetUserInput', [context, s3ResourceName]); - return s3UserInputs; -} - -export class StorageTest { - private storageName: string; - - private storageSimulator: AmplifyStorageSimulator; - - private configOverrideManager: ConfigOverrideManager; - - private storageRegion: string; - - private bucketName: string; - - async start(context) { - // loading s3 resource config form parameters.json - const meta = context.amplify.getProjectDetails().amplifyMeta; - const existingStorage = meta.storage; - this.storageRegion = meta.providers.awscloudformation.Region; - if (existingStorage === undefined || Object.keys(existingStorage).length === 0) { - return context.print.warning('Storage has not yet been added to this project.'); - } - let backendPath = context.amplify.pathManager.getBackendDirPath(); - const resourceName = Object.keys(existingStorage)[0]; - const parametersFilePath = path.join(backendPath, 'storage', resourceName, 'parameters.json'); - - const localEnvFilePath = context.amplify.pathManager.getLocalEnvFilePath(); - const localEnvInfo = context.amplify.readJsonFile(localEnvFilePath); - - const s3ResourceName = await invokeS3GetResourceName(context); - const s3UserInputs = await invokeS3GetUserInputs(context, s3ResourceName); - this.bucketName = `${s3UserInputs.bucketName}-${localEnvInfo.envName}`; - const route = path.join('/', this.bucketName); - let localDirS3 = this.createLocalStorage(context, `${s3UserInputs.bucketName}`); - - try { - context.amplify.addCleanUpTask(async (context) => { - await this.stop(); - }); - this.configOverrideManager = await ConfigOverrideManager.getInstance(context); - this.storageName = await this.getStorage(context); - const storageConfig = { port, route, localDirS3 }; - this.storageSimulator = new AmplifyStorageSimulator(storageConfig); - await this.storageSimulator.start(); - console.log('Mock Storage endpoint is running at', this.storageSimulator.url); - await this.generateTestFrontendExports(context); - } catch (e) { - console.error('Failed to start Mock Storage server', e); - } - } - - async stop() { - await this.storageSimulator.stop(); - } - - // to fire s3 triggers attached on the bucket - async trigger(context: $TSContext) { - let region = this.storageRegion; - this.storageSimulator.getServer.on('event', async (eventObj: any) => { - const meta = context.amplify.getProjectDetails().amplifyMeta; - const existingStorage = meta.storage; - let backendPath = context.amplify.pathManager.getBackendDirPath(); - const resourceName = Object.keys(existingStorage)[0]; - const CFNFilePath = path.join(backendPath, 'storage', resourceName, 'build', 'cloudformation-template.json'); - const storageParams = JSONUtilities.readJson(CFNFilePath); - const lambdaConfig = - storageParams.Resources.S3Bucket.Properties.NotificationConfiguration && - storageParams.Resources.S3Bucket.Properties.NotificationConfiguration.LambdaConfigurations; - // no trigger case - if (lambdaConfig === undefined) { - return; - } - // loop over lambda config to check for trigger based on prefix - let triggerName; - for (let obj of lambdaConfig) { - let prefix_arr = obj.Filter; - if (prefix_arr === undefined) { - let eventName = String(eventObj.Records[0].event.eventName).split(':')[0]; - if (eventName === 'ObjectRemoved' || eventName === 'ObjectCreated') { - triggerName = String(obj.Function.Ref).split('function')[1].split('Arn')[0]; - break; - } - } else { - let keyName = String(eventObj.Records[0].s3.object.key); - prefix_arr = obj.Filter.S3Key.Rules; - for (let rules of prefix_arr) { - let node; - if (typeof rules.Value === 'object') { - node = String(Object.values(rules.Value)[0][1][0] + String(region) + ':'); - } - - if (typeof rules.Value === 'string') { - node = String(rules.Value); - } - // check prefix given is the prefix of keyname in the event object - if (keyName.indexOf(node) === 0) { - triggerName = String(obj.Function.Ref).split('function')[1].split('Arn')[0]; - break; - } - } - } - if (triggerName !== undefined) { - break; - } - } - - const config = await loadLambdaConfig(context, triggerName); - const invoker = await getInvoker(context, { handler: config.handler, resourceName: triggerName, envVars: config.environment }); - try { - await invoker({ event: eventObj }); - } catch (err) { - context.print.error('Error executing lambda trigger'); - context.print.error(err); - } - }); - } - - private async generateTestFrontendExports(context) { - await this.generateFrontendExports(context, { - endpoint: this.storageSimulator.url, - name: this.storageName, - testMode: true, - }); - } - - // generate aws-exports.js - private async generateFrontendExports( - context: any, - localStorageDetails?: { - endpoint: string; - name: string; - testMode: boolean; - }, - ) { - const currentMeta = await getAmplifyMeta(context); - const override = currentMeta.storage || {}; - if (localStorageDetails) { - const storageMeta = override[localStorageDetails.name] || { output: {} }; - override[localStorageDetails.name] = { - service: 'S3', - ...storageMeta, - output: { - ...storageMeta.output, - BucketName: this.bucketName, - Region: this.storageRegion, - }, - testMode: localStorageDetails.testMode, - lastPushTimeStamp: new Date(), - }; - } - this.configOverrideManager.addOverride('storage', override); - await this.configOverrideManager.generateOverriddenFrontendExports(context); - } - - private async getStorage(context) { - const currentMeta = await getAmplifyMeta(context); - const { storage: tmp = {} } = currentMeta; - let name = null; - Object.entries(tmp).some((entry: any) => { - if (entry[1].service === 'S3') { - name = entry[0]; - return true; - } - }); - return name; - } - - // create local storage for S3 on disk which is fixes as the test folder - private createLocalStorage(context, resourceName: string) { - const directoryPath = path.join(getMockDataDirectory(context), 'S3'); // get bucket through parameters remove afterwards - fs.ensureDirSync(directoryPath); - - const localPath = path.join(directoryPath, resourceName); - fs.ensureDirSync(localPath); - return localPath; - } - - get getSimulatorObject() { - return this.storageSimulator; - } -} diff --git a/packages/amplify-util-mock/src/utils/config-override.ts b/packages/amplify-util-mock/src/utils/config-override.ts deleted file mode 100644 index fe8ad7c8ac..0000000000 --- a/packages/amplify-util-mock/src/utils/config-override.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { getAmplifyMeta } from './index'; - -export class ConfigOverrideManager { - private static instance: ConfigOverrideManager = null; - - private overrides: {}; - - private amplifyMeta: any = {}; - - constructor(context) { - this.overrides = {}; - context.amplify.addCleanUpTask(async (context) => { - await this.restoreFrontendExports(context); - }); - } - - addOverride(category: string, override: {}) { - this.overrides[category] = override; - } - - async generateOverriddenFrontendExports(context) { - const meta = await getAmplifyMeta(context); - await context.amplify.onCategoryOutputsChange(context, null, { - ...meta, - ...this.overrides, - }); - } - - async restoreFrontendExports(context) { - await context.amplify.onCategoryOutputsChange(context, null, this.amplifyMeta); - } - - static async getInstance(context: any): Promise { - if (!ConfigOverrideManager.instance) { - const configOverrideManager = new ConfigOverrideManager(context); - configOverrideManager.amplifyMeta = await getAmplifyMeta(context); - ConfigOverrideManager.instance = configOverrideManager; - } - return ConfigOverrideManager.instance; - } -} diff --git a/packages/amplify-util-mock/src/utils/dynamo-db/helpers.ts b/packages/amplify-util-mock/src/utils/dynamo-db/helpers.ts deleted file mode 100644 index 6848159add..0000000000 --- a/packages/amplify-util-mock/src/utils/dynamo-db/helpers.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { DynamoDB } from 'aws-sdk'; - -const MILLI_SECONDS = 1000; -export async function waitTillTableStateIsActive( - dynamoDBClient: DynamoDB, - tableName: string, - maximumWait: number = 15 * MILLI_SECONDS, -): Promise { - return new Promise(async (resolve, reject) => { - let intervalHandle; - let timeoutHandle; - const checkStatus = async () => { - const tableDescription = await dynamoDBClient.describeTable({ TableName: tableName }).promise(); - if (tableDescription.Table.TableStatus === 'ACTIVE') { - clearTimeout(timeoutHandle); - clearInterval(intervalHandle); - resolve(); - } - }; - intervalHandle = setInterval(checkStatus, 1000); - timeoutHandle = setTimeout(() => { - clearTimeout(timeoutHandle); - clearInterval(intervalHandle); - reject(new Error('Waiting for table status to turn ACTIVE timed out')); - }, maximumWait); - - await checkStatus(); - }); -} diff --git a/packages/amplify-util-mock/src/utils/dynamo-db/index.ts b/packages/amplify-util-mock/src/utils/dynamo-db/index.ts deleted file mode 100644 index fa0c8ee6e1..0000000000 --- a/packages/amplify-util-mock/src/utils/dynamo-db/index.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { DynamoDB } from 'aws-sdk'; -import { CreateTableInput } from 'aws-sdk/clients/dynamodb'; -import { createTables, describeTables, getUpdateTableInput, updateTables } from './utils'; - -export type MockDynamoDBConfig = { - tables: { Properties: CreateTableInput }[]; -}; - -export async function createAndUpdateTable(dynamoDbClient: DynamoDB, config: MockDynamoDBConfig): Promise { - const tables = config.tables.map((table) => table.Properties); - const existingTables = await dynamoDbClient.listTables().promise(); - const existingTablesWithDetails = await describeTables(dynamoDbClient, existingTables.TableNames); - const tablesToCreate = tables.filter((t) => { - const tableName = t.TableName; - return !existingTables.TableNames.includes(tableName); - }); - - const tablesToUpdate = tables.filter((t) => { - const tableName = t.TableName; - return existingTables.TableNames.includes(tableName); - }); - await createTables(dynamoDbClient, tablesToCreate); - const updateTableInputs = tablesToUpdate.reduce((acc, createTableInput) => { - const existingTableDetail = existingTablesWithDetails[createTableInput.TableName]; - return [...acc, ...getUpdateTableInput(createTableInput, existingTableDetail)]; - }, []); - await updateTables(dynamoDbClient, updateTableInputs); -} - -export function configureDDBDataSource(config, ddbConfig) { - return { - ...config, - dataSources: config.dataSources.map((d) => { - if (d.type !== 'AMAZON_DYNAMODB') { - return d; - } - return { - ...d, - config: { - ...d.config, - endpoint: ddbConfig.endpoint, - region: ddbConfig.region, - accessKeyId: ddbConfig.accessKeyId, - secretAccessKey: ddbConfig.secretAccessKey, - sessionToken: ddbConfig.sessionToken || process.env.AWS_SESSION_TOKEN, - }, - }; - }), - }; -} diff --git a/packages/amplify-util-mock/src/utils/dynamo-db/utils.ts b/packages/amplify-util-mock/src/utils/dynamo-db/utils.ts deleted file mode 100644 index 27f25be0c1..0000000000 --- a/packages/amplify-util-mock/src/utils/dynamo-db/utils.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { DynamoDB } from 'aws-sdk'; -import { CreateTableInput, GlobalSecondaryIndexUpdate, TableDescription, UpdateTableInput } from 'aws-sdk/clients/dynamodb'; -import { waitTillTableStateIsActive } from './helpers'; - -export async function createTables(dynamoDbClient: DynamoDB, tables: CreateTableInput[]): Promise { - for (let table of tables) { - console.log(`Creating new table ${table.TableName}`); - await dynamoDbClient.createTable(table).promise(); - } -} - -export async function updateTables(dynamoDbClient: DynamoDB, tables: UpdateTableInput[]): Promise { - for (let table of tables) { - const updateType = table.GlobalSecondaryIndexUpdates[0].Delete ? 'Deleting' : 'Creating'; - const indexName = - updateType == 'Deleting' - ? table.GlobalSecondaryIndexUpdates[0].Delete.IndexName - : table.GlobalSecondaryIndexUpdates[0].Create.IndexName; - await waitTillTableStateIsActive(dynamoDbClient, table.TableName); - console.log(`${updateType} index ${indexName} on ${table.TableName}`); - await dynamoDbClient.updateTable(table).promise(); - } -} - -export async function describeTables(dynamoDbClient: DynamoDB, tableNames: string[]): Promise> { - const tableDetails: Record = {}; - for (let tableName of tableNames) { - const tableDescription = await dynamoDbClient.describeTable({ TableName: tableName }).promise(); - if (tableDescription.Table) { - tableDetails[tableName] = tableDescription.Table; - } - } - return tableDetails; -} - -export function getUpdateTableInput(createInput: CreateTableInput, existingTableConfig: TableDescription): UpdateTableInput[] { - if (createInput.TableName !== existingTableConfig.TableName) { - throw new Error('Invalid input, table name mismatch'); - } - const inputGSINames = (createInput.GlobalSecondaryIndexes || []).map((index) => index.IndexName); - const existingGSINames = (existingTableConfig.GlobalSecondaryIndexes || []).map((index) => index.IndexName); - const indexNamesToAdd = inputGSINames.filter((indexName) => !existingGSINames.includes(indexName)); - const indexNamesToRemove = existingGSINames.filter((indexName) => !inputGSINames.includes(indexName)); - - const indicesToAdd: GlobalSecondaryIndexUpdate[] = indexNamesToAdd.map((indexName) => { - const idx = createInput.GlobalSecondaryIndexes.find((index) => index.IndexName === indexName); - return { - Create: idx, - }; - }); - const indicesToRemove: GlobalSecondaryIndexUpdate[] = indexNamesToRemove.map((indexName) => { - return { - Delete: { - IndexName: indexName, - }, - }; - }); - - return [ - ...(indicesToRemove.length - ? indicesToRemove.map((index) => { - return { - TableName: existingTableConfig.TableName, - GlobalSecondaryIndexUpdates: [index], - }; - }) - : []), - ...(indicesToAdd.length - ? indicesToAdd.map((index) => { - return { - TableName: existingTableConfig.TableName, - AttributeDefinitions: createInput.AttributeDefinitions, - GlobalSecondaryIndexUpdates: [index], - }; - }) - : []), - ]; -} diff --git a/packages/amplify-util-mock/src/utils/error-serializer.ts b/packages/amplify-util-mock/src/utils/error-serializer.ts deleted file mode 100644 index 57da29bd31..0000000000 --- a/packages/amplify-util-mock/src/utils/error-serializer.ts +++ /dev/null @@ -1,7 +0,0 @@ -const createMap = (error) => - Object.getOwnPropertyNames(error).reduce((obj, property) => { - obj[property] = error[property]; - return obj; - }, {}); - -export const serializer = (error) => JSON.stringify(createMap(error)); diff --git a/packages/amplify-util-mock/src/utils/git-ignore.ts b/packages/amplify-util-mock/src/utils/git-ignore.ts deleted file mode 100644 index 8449f2b9f8..0000000000 --- a/packages/amplify-util-mock/src/utils/git-ignore.ts +++ /dev/null @@ -1,16 +0,0 @@ -import * as path from 'path'; -import * as fs from 'fs-extra'; -import { getMockDataDirectory } from './mock-data-directory'; - -export function addMockDataToGitIgnore(context) { - const gitIgnoreFilePath = context.amplify.pathManager.getGitIgnoreFilePath(); - if (fs.existsSync(gitIgnoreFilePath)) { - const gitRoot = path.dirname(gitIgnoreFilePath); - const mockDataDirectory = path.relative(gitRoot, getMockDataDirectory(context)).replace(/\\/g, '/'); - let gitIgnoreContent = fs.readFileSync(gitIgnoreFilePath).toString(); - if (gitIgnoreContent.search(RegExp(`^\\s*${mockDataDirectory}\\w*$`, 'gm')) === -1) { - gitIgnoreContent += '\n' + mockDataDirectory; - fs.writeFileSync(gitIgnoreFilePath, gitIgnoreContent); - } - } -} diff --git a/packages/amplify-util-mock/src/utils/index.ts b/packages/amplify-util-mock/src/utils/index.ts deleted file mode 100644 index 7eba15bd5a..0000000000 --- a/packages/amplify-util-mock/src/utils/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -export { getMockDataDirectory } from './mock-data-directory'; -export { addMockDataToGitIgnore } from './git-ignore'; -export async function getAmplifyMeta(context: any) { - const amplifyMetaFilePath = context.amplify.pathManager.getAmplifyMetaFilePath(); - return context.amplify.readJsonFile(amplifyMetaFilePath); -} - -import * as which from 'which'; -import * as execa from 'execa'; -import * as semver from 'semver'; - -const minJavaVersion = '>=1.8 <= 2.0 || >=8.0'; - -export const checkJavaVersion = async (context) => { - const executablePath = which.sync('java', { - nothrow: true, - }); - - if (executablePath === null) { - context.print.error(`Unable to find Java version ${minJavaVersion} on the path. Download link: https://amzn.to/2UUljp9`); - } - - const result = execa.sync('java', ['-version']); - - if (result.exitCode !== 0) { - context.print.error(`java failed, exit code was ${result.exitCode}`); - } - - // Java prints version to stderr - if (isUnsupportedJavaVersion(result.stderr)) { - context.print.warning(`Update java to 8+`); - } -}; - -function isUnsupportedJavaVersion(stderr: string | null): boolean { - const regex = /version "(\d+)(\.(\d+\.)(\d))?/g; - const versionStrings: Array = stderr ? stderr.split(/\r?\n/) : ['']; - const mayVersion = versionStrings.map((line) => line.match(regex)).find((v) => v != null); - if (mayVersion === undefined) { - return true; - } - const version = mayVersion[0].replace('version "', ''); - const semVer = version.match(/^\d+$/g) === null ? version : `${version}.0.0`; - return !semver.satisfies(semVer, minJavaVersion); -} - -export const _isUnsupportedJavaVersion: (stderr: string | null) => boolean = isUnsupportedJavaVersion; diff --git a/packages/amplify-util-mock/src/utils/lambda/README.md b/packages/amplify-util-mock/src/utils/lambda/README.md deleted file mode 100644 index c46a343b2f..0000000000 --- a/packages/amplify-util-mock/src/utils/lambda/README.md +++ /dev/null @@ -1 +0,0 @@ -Invoking functions using the functions in this directory is deprecated. It is left here for now because the mock e2e tests depends on it and there isn't a quick way to refactor diff --git a/packages/amplify-util-mock/src/utils/lambda/load-lambda-config.ts b/packages/amplify-util-mock/src/utils/lambda/load-lambda-config.ts deleted file mode 100644 index f33e6e9266..0000000000 --- a/packages/amplify-util-mock/src/utils/lambda/load-lambda-config.ts +++ /dev/null @@ -1,50 +0,0 @@ -import * as path from 'path'; -import { JSONUtilities, pathManager, $TSContext } from '@aws-amplify/amplify-cli-core'; -import detect from 'detect-port'; -import { lambdaFunctionHandler } from '../../CFNParser/resource-processors/lambda'; -import { ProcessedLambdaFunction } from '../../CFNParser/stack/types'; -import { MOCK_API_PORT } from '../../api/api'; -import { populateCfnParams } from './populate-cfn-params'; -import { populateLambdaMockEnvVars } from './populate-lambda-mock-env-vars'; - -const CFN_DEFAULT_CONDITIONS = { - ShouldNotCreateEnvResources: true, -}; - -/** - * Loads the necessary parameters for mocking a lambda function - * - * Locates and parses the CFN template for the function and injects environment variables - * @param resourceName The labmda resource to load - * @param print The print object from context - */ -export const loadLambdaConfig = async ( - context: $TSContext, - resourceName: string, - overrideApiToLocal = false, -): Promise => { - overrideApiToLocal = overrideApiToLocal || (await isApiRunning()); - const resourcePath = path.join(pathManager.getBackendDirPath(), 'function', resourceName); - const { Resources: cfnResources } = JSONUtilities.readJson<{ Resources: Record }>( - path.join(resourcePath, `${resourceName}-cloudformation-template.json`), - ); - const lambdaDef = Object.entries(cfnResources).find(([_, resourceDef]: [string, any]) => resourceDef.Type === 'AWS::Lambda::Function'); - if (!lambdaDef) { - return; - } - const cfnParams = await populateCfnParams(context.print, resourceName, overrideApiToLocal); - const processedLambda = lambdaFunctionHandler(lambdaDef[0], lambdaDef[1], { - conditions: CFN_DEFAULT_CONDITIONS, - params: cfnParams, - exports: {}, - resources: {}, - }); - await populateLambdaMockEnvVars(context, processedLambda); - return processedLambda; -}; - -const isApiRunning = async (): Promise => { - const result = await detect(MOCK_API_PORT); - // returns the next free port so if the API is running, then the port will be different - return result !== MOCK_API_PORT; -}; diff --git a/packages/amplify-util-mock/src/utils/lambda/populate-cfn-params.ts b/packages/amplify-util-mock/src/utils/lambda/populate-cfn-params.ts deleted file mode 100644 index 3334b0c9e8..0000000000 --- a/packages/amplify-util-mock/src/utils/lambda/populate-cfn-params.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { $TSContext, AmplifyCategories, stateManager } from '@aws-amplify/amplify-cli-core'; -import { ensureEnvParamManager } from '@aws-amplify/amplify-environment-parameters'; -import _ from 'lodash'; -import { GRAPHQL_API_ENDPOINT_OUTPUT, GRAPHQL_API_KEY_OUTPUT, MOCK_API_KEY, MOCK_API_PORT } from '../../api/api'; - -/** - * Loads all parameters that should be passed into the lambda CFN template when resolving values - * - * Iterates through a list of parameter getters. If multiple getters return the same key, the latter will overwrite the former - */ -export const populateCfnParams = async ( - print: $TSContext['print'], - resourceName: string, - overrideApiToLocal: boolean = false, -): Promise> => { - const cfnParams = [getCfnPseudoParams, getAmplifyMetaParams, getParametersJsonParams] - .map((paramProvider) => paramProvider(print, resourceName, overrideApiToLocal)) - .reduce((acc, it) => ({ ...acc, ...it }), {}); - - const resourceParamManager = (await ensureEnvParamManager()).instance.getResourceParamManager(AmplifyCategories.API, resourceName); - return { ...cfnParams, ...resourceParamManager.getAllParams() }; -}; - -const getCfnPseudoParams = (): Record => { - const env = stateManager.getLocalEnvInfo().envName; - const meta = stateManager.getMeta(); - const region = _.get(meta, ['awscloudformation', 'Region'], 'us-test-1'); - const stackId = _.get(meta, ['awscloudformation', 'StackId'], 'fake-stack-id'); - const stackName = _.get(meta, ['awscloudformation', 'StackName'], 'local-testing'); - const accountIdMatcher = /arn:aws:cloudformation:.+:(?\d+):stack\/.+/; - const match = accountIdMatcher.exec(stackId); - const accountId = match ? match.groups.accountId : '12345678910'; - return { - env, - 'AWS::Region': region, - 'AWS::AccountId': accountId, - 'AWS::StackId': stackId, - 'AWS::StackName': stackName, - 'AWS::URLSuffix': 'amazonaws.com', - }; -}; - -/** - * Loads CFN parameters by matching the dependsOn field of the resource with the CFN outputs of other resources in the project - */ -const getAmplifyMetaParams = ( - print: $TSContext['print'], - resourceName: string, - overrideApiToLocal: boolean = false, -): Record => { - const projectMeta = stateManager.getMeta(); - if (!Array.isArray(projectMeta?.function?.[resourceName]?.dependsOn)) { - return {}; - } - const dependencies = projectMeta?.function?.[resourceName]?.dependsOn as { - category: string; - resourceName: string; - attributes: string[]; - }[]; - return dependencies.reduce((acc, dependency) => { - dependency.attributes.forEach((attribute) => { - let val = projectMeta?.[dependency.category]?.[dependency.resourceName]?.output?.[attribute]; - if (!val) { - print.warning( - `No output found for attribute '${attribute}' on resource '${dependency.resourceName}' in category '${dependency.category}'`, - ); - print.warning('This attribute will be undefined in the mock environment until you run `amplify push`'); - } - - if (overrideApiToLocal) { - switch (attribute) { - case GRAPHQL_API_ENDPOINT_OUTPUT: - val = `http://localhost:${MOCK_API_PORT}/graphql`; - break; - case GRAPHQL_API_KEY_OUTPUT: - val = MOCK_API_KEY; - break; - } - } - - acc[dependency.category + dependency.resourceName + attribute] = val; - }); - return acc; - }, {} as Record); -}; - -/** - * Loads CFN parameters from the parameters.json file for the resource (if present) - */ -const getParametersJsonParams = (_, resourceName: string): Record => { - return stateManager.getResourceParametersJson(undefined, 'function', resourceName, { throwIfNotExist: false }) ?? {}; -}; diff --git a/packages/amplify-util-mock/src/utils/lambda/populate-lambda-mock-env-vars.ts b/packages/amplify-util-mock/src/utils/lambda/populate-lambda-mock-env-vars.ts deleted file mode 100644 index 512f74b69f..0000000000 --- a/packages/amplify-util-mock/src/utils/lambda/populate-lambda-mock-env-vars.ts +++ /dev/null @@ -1,77 +0,0 @@ -import * as path from 'path'; -import { $TSContext, AmplifyCategories, pathManager, stateManager } from '@aws-amplify/amplify-cli-core'; -import _ from 'lodash'; -import * as dotenv from 'dotenv'; -import { loadConfigurationForEnv, resolveAppId } from '@aws-amplify/amplify-provider-awscloudformation'; -import { ProcessedLambdaFunction } from '../../CFNParser/stack/types'; - -/** - * Appends default labmda environment variables to the environment property of the processedLambda - * (see https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-runtime) - * Some values are stubbed properly and others have static default values - */ -export const populateLambdaMockEnvVars = async (context: $TSContext, processedLambda: ProcessedLambdaFunction) => { - processedLambda.environment = ( - await Promise.all( - [getAwsCredentials, getStaticDefaults, getDynamicDefaults, getDotEnvValues].map((envVarGetter) => - envVarGetter(processedLambda, context), - ), - ) - ).reduce((acc, it) => ({ ...acc, ...it }), processedLambda.environment); -}; - -const getAwsCredentials = async (_, context: $TSContext): Promise> => { - const env = stateManager.getLocalEnvInfo().envName; - let appId: string | undefined; - try { - appId = resolveAppId(context); - } catch { - // swallow no appId found as it's not necessary for mocking - } - const awsConfigInfo = await loadConfigurationForEnv(context, env, appId); - return { - AWS_ACCESS_KEY_ID: awsConfigInfo.accessKeyId, - AWS_SECRET_ACCESS_KEY: awsConfigInfo.secretAccessKey, - AWS_SESSION_TOKEN: awsConfigInfo.sessionToken, - }; -}; - -const getStaticDefaults = (): Record => ({ - _X_AMZN_TRACE_ID: 'amplify-mock-x-amzn-trace-id', - AWS_EXECUTION_ENV: 'AWS_Lambda_amplify-mock', // we could do some work to resolve the actual runtime here, but there doesn't seem to be a need at this point - AWS_LAMBDA_FUNCTION_MEMORY_SIZE: '128', // the default - AWS_LAMBDA_FUNCTION_VERSION: '1', - AWS_LAMBDA_INITIALIZATION_TYPE: 'on-demand', - AWS_LAMBDA_LOG_GROUP_NAME: 'amplify-mock-aws-lambda-log-group-name', - AWS_LAMBDA_LOG_STREAM_NAME: 'amplify-mock-aws-lambda-log-stream-name', - TZ: 'UTC', -}); - -const getDynamicDefaults = (processedLambda: ProcessedLambdaFunction): Record => { - const meta = stateManager.getMeta(); - const region = meta?.providers?.awscloudformation?.Region; - // This isn't exactly in parity with what the path will be when deployed but we don't have a good mechanism for getting a better value - const lambdaPath = pathManager.getResourceDirectoryPath(undefined, AmplifyCategories.FUNCTION, processedLambda.name); - - return { - _HANDLER: processedLambda.handler, - AWS_REGION: region, - AWS_LAMBDA_FUNCTION_NAME: processedLambda.name, - LAMBDA_TASK_ROOT: lambdaPath, - LAMBDA_RUNTIME_DIR: lambdaPath, - }; -}; - -const getDotEnvValues = (processedLambda: ProcessedLambdaFunction): Record => { - try { - const result = dotenv.config({ - path: path.join(pathManager.getResourceDirectoryPath(undefined, AmplifyCategories.FUNCTION, processedLambda.name), '.env'), - }); - if (result.error) { - throw result.error; - } - return result.parsed; - } catch { - // if there's no .env file, carry on without it - } -}; diff --git a/packages/amplify-util-mock/src/utils/mock-config-file.ts b/packages/amplify-util-mock/src/utils/mock-config-file.ts deleted file mode 100644 index 5554e66c3b..0000000000 --- a/packages/amplify-util-mock/src/utils/mock-config-file.ts +++ /dev/null @@ -1,8 +0,0 @@ -import * as path from 'path'; -import { JSONUtilities } from '@aws-amplify/amplify-cli-core'; - -export function getMockConfig(context) { - const { projectPath } = context.amplify.getEnvInfo(); - const mockConfigPath = path.join(projectPath, 'amplify', 'mock.json'); - return JSONUtilities.readJson(mockConfigPath, { throwIfNotExist: false }) ?? {}; -} diff --git a/packages/amplify-util-mock/src/utils/mock-data-directory.ts b/packages/amplify-util-mock/src/utils/mock-data-directory.ts deleted file mode 100644 index 099c5162ab..0000000000 --- a/packages/amplify-util-mock/src/utils/mock-data-directory.ts +++ /dev/null @@ -1,6 +0,0 @@ -import * as path from 'path'; - -export function getMockDataDirectory(context) { - const { projectPath } = context.amplify.getEnvInfo(); - return path.join(projectPath, 'amplify', 'mock-data'); -} diff --git a/packages/amplify-util-mock/src/velocity/index.ts b/packages/amplify-util-mock/src/velocity/index.ts deleted file mode 100644 index 432d754a3a..0000000000 --- a/packages/amplify-util-mock/src/velocity/index.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { v4 } from 'uuid'; -import { AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; -import { GraphQLResolveInfo } from 'graphql'; -import { - AmplifyAppSyncSimulator, - AmplifyAppSyncAuthenticationProviderConfig, - VelocityTemplate, - AppSyncVTLRenderContext, - AppSyncGraphQLExecutionContext, - JWTToken, - IAMToken, -} from '@aws-amplify/amplify-appsync-simulator'; - -const DEFAULT_SCHEMA = ` - type Query { - noop: String - }`; - -type iamCognitoIdentityContext = Partial< - Pick ->; - -export interface VelocityTemplateSimulatorOptions { - authConfig: AppSyncAuthConfiguration; -} -export type AppSyncVTLContext = Partial; - -export type AppSyncVTLPayload = { - context: Partial; - requestParameters: AppSyncGraphQLExecutionContext; - info?: Partial; -}; - -export class VelocityTemplateSimulator { - private gqlSimulator: AmplifyAppSyncSimulator; - - constructor(opts: VelocityTemplateSimulatorOptions) { - this.gqlSimulator = new AmplifyAppSyncSimulator(); - this.gqlSimulator.init({ - schema: { - content: DEFAULT_SCHEMA, - }, - appSync: { - name: 'appsyncAPI', - defaultAuthenticationType: opts.authConfig.defaultAuthentication as AmplifyAppSyncAuthenticationProviderConfig, - additionalAuthenticationProviders: opts.authConfig - .additionalAuthenticationProviders as AmplifyAppSyncAuthenticationProviderConfig[], - }, - }); - } - - render(template: string, payload: AppSyncVTLPayload) { - const ctxParameters: AppSyncVTLRenderContext = { source: {}, arguments: { input: {} }, stash: {}, ...payload.context }; - const vtlInfo: any = { fieldNodes: [], fragments: {}, path: { key: '' }, ...(payload.info ?? {}) }; - const vtlTemplate = new VelocityTemplate({ content: template }, this.gqlSimulator); - return vtlTemplate.render(ctxParameters, payload.requestParameters, vtlInfo); - } -} - -export const getJWTToken = ( - userPool: string, - username: string, - email: string, - groups: string[] = [], - tokenType: 'id' | 'access' = 'id', -): JWTToken => { - const token: JWTToken = { - iss: `https://cognito-idp.us-west-2.amazonaws.com/us-west-2_${userPool}`, - sub: v4(), - aud: '75pk49boud2olipfda0ke3snic', - exp: Math.floor(Date.now() / 1000) + 10000, - iat: Math.floor(Date.now() / 1000), - event_id: v4(), - token_use: tokenType, - auth_time: Math.floor(Date.now() / 1000), - 'cognito:username': username, - 'cognito:groups': groups, - email, - }; - return token; -}; - -export const getGenericToken = (username: string, email: string, groups: string[] = [], tokenType: 'id' | 'access' = 'id'): JWTToken => { - return { - iss: 'https://some-oidc-provider/auth', - sub: v4(), - aud: '75pk49boud2olipfda0ke3snic', - exp: Math.floor(Date.now() / 1000) + 10000, - iat: Math.floor(Date.now() / 1000), - event_id: v4(), - token_use: tokenType, - auth_time: Math.floor(Date.now() / 1000), - username, - email, - groups, - }; -}; - -export const getIAMToken = (username: string, identityInfo?: iamCognitoIdentityContext): IAMToken => { - let iamRoleName = username; - if (identityInfo?.cognitoIdentityAuthType) { - iamRoleName = identityInfo.cognitoIdentityAuthType === 'authenticated' ? 'authRole' : 'unauthRole'; - } - return { - username, - userArn: `arn:aws:sts::123456789012:assumed-role/${iamRoleName}/CognitoIdentityCredentials`, - accountId: '123456789012', - cognitoIdentityPoolId: identityInfo?.cognitoIdentityPoolId, - cognitoIdentityAuthProvider: identityInfo?.cognitoIdentityAuthProvider, - cognitoIdentityId: identityInfo?.cognitoIdentityId, - cognitoIdentityAuthType: identityInfo?.cognitoIdentityAuthType, - }; -}; diff --git a/packages/amplify-util-mock/tsconfig.json b/packages/amplify-util-mock/tsconfig.json deleted file mode 100644 index ad6bb389c4..0000000000 --- a/packages/amplify-util-mock/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "./lib", - "rootDir": "./src", - "strict": false, - "skipLibCheck": true - }, - "references": [ - { - "path": "../amplify-graphql-auth-transformer" - }, - { - "path": "../amplify-graphql-model-transformer" - }, - { - "path": "../amplify-graphql-name-mapping-transformer" - } - ] -} diff --git a/packages/graphql-auth-transformer/.npmignore b/packages/graphql-auth-transformer/.npmignore deleted file mode 100644 index 3ee5d55b0b..0000000000 --- a/packages/graphql-auth-transformer/.npmignore +++ /dev/null @@ -1,5 +0,0 @@ -**/__mocks__/** -**/__tests__/** -src -tsconfig.json -tsconfig.tsbuildinfo diff --git a/packages/graphql-auth-transformer/API.md b/packages/graphql-auth-transformer/API.md deleted file mode 100644 index d62a7d3885..0000000000 --- a/packages/graphql-auth-transformer/API.md +++ /dev/null @@ -1,126 +0,0 @@ -## API Report File for "graphql-auth-transformer" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { CompoundExpressionNode } from 'graphql-mapping-template'; -import { default as default_2 } from 'cloudform-types/types/appSync/apiKey'; -import { default as default_3 } from 'cloudform-types/types/appSync/resolver'; -import { default as default_4 } from 'cloudform-types/types/appSync/dataSource'; -import { DirectiveNode } from 'graphql'; -import { Expression } from 'graphql-mapping-template'; -import { FieldDefinitionNode } from 'graphql'; -import GraphQLApi from 'cloudform-types/types/appSync/graphQlApi'; -import { InterfaceTypeDefinitionNode } from 'graphql'; -import ManagedPolicy from 'cloudform-types/types/iam/managedPolicy'; -import { NumberParameter } from 'cloudform-types'; -import { ObjectTypeDefinitionNode } from 'graphql'; -import { StringParameter } from 'cloudform-types'; -import Template from 'cloudform-types/types/template'; -import { Transformer as Transformer_2 } from 'graphql-transformer-core'; -import { TransformerContext } from 'graphql-transformer-core'; - -// @public (undocumented) -export type ApiKeyConfig = { - description?: string; - apiKeyExpirationDays: number; - apiKeyExpirationDate?: Date; -}; - -// @public (undocumented) -export type AppSyncAuthConfiguration = { - defaultAuthentication: AppSyncAuthConfigurationEntry; - additionalAuthenticationProviders: Array; -}; - -// @public (undocumented) -export type AppSyncAuthConfigurationEntry = { - authenticationType: AppSyncAuthMode; - apiKeyConfig?: ApiKeyConfig; - userPoolConfig?: UserPoolConfig; - openIDConnectConfig?: OpenIDConnectConfig; - lambdaAuthorizerConfig?: LambdaAuthorizerConfig; -}; - -// @public (undocumented) -export type AppSyncAuthMode = 'API_KEY' | 'AMAZON_COGNITO_USER_POOLS' | 'AWS_IAM' | 'OPENID_CONNECT' | 'AWS_LAMBDA'; - -// @public (undocumented) -export type ConfiguredAuthProviders = { - default: AuthProvider; - onlyDefaultAuthProviderConfigured: boolean; - hasApiKey: boolean; - hasUserPools: boolean; - hasOIDC: boolean; - hasIAM: boolean; -}; - -// @public (undocumented) -export type LambdaAuthorizerConfig = { - lambdaFunction: string; - ttlSeconds?: number; -}; - -// @public (undocumented) -export class ModelAuthTransformer extends Transformer_2 { - constructor(config?: ModelAuthTransformerConfig); - // (undocumented) - after: (ctx: TransformerContext) => void; - // (undocumented) - authPolicyResources: Set; - // (undocumented) - before: (ctx: TransformerContext) => void; - // (undocumented) - config: ModelAuthTransformerConfig; - // (undocumented) - configuredAuthProviders: ConfiguredAuthProviders; - // (undocumented) - field: (parent: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, definition: FieldDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => void; - // (undocumented) - generateIAMPolicyforAuthRole: boolean; - // (undocumented) - generateIAMPolicyforUnauthRole: boolean; - // (undocumented) - hasProviderAuthRules(rules: AuthRule[]): Boolean; - // (undocumented) - object: (def: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => void; - // Warning: (ae-forgotten-export) The symbol "AuthRule" needs to be exported by the entry point index.d.ts - // - // (undocumented) - protectSyncQuery(ctx: TransformerContext, def: ObjectTypeDefinitionNode, resolverResourceID: string, rules: AuthRule[]): void; - // Warning: (ae-forgotten-export) The symbol "ResourceFactory" needs to be exported by the entry point index.d.ts - // - // (undocumented) - resources: ResourceFactory; - // (undocumented) - unauthPolicyResources: Set; -} - -// @public (undocumented) -export type ModelAuthTransformerConfig = { - authConfig?: AppSyncAuthConfiguration; - addAwsIamAuthInOutputSchema?: boolean; -}; - -// @public (undocumented) -export type OpenIDConnectConfig = { - name: string; - issuerUrl: string; - clientId?: string; - iatTTL?: number; - authTTL?: number; -}; - -// @public (undocumented) -export type UserPoolConfig = { - userPoolId: string; -}; - -// Warnings were encountered during analysis: -// -// src/ModelAuthTransformer.ts:144:3 - (ae-forgotten-export) The symbol "AuthProvider" needs to be exported by the entry point index.d.ts - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/graphql-auth-transformer/CHANGELOG.md b/packages/graphql-auth-transformer/CHANGELOG.md deleted file mode 100644 index a7032d5b78..0000000000 --- a/packages/graphql-auth-transformer/CHANGELOG.md +++ /dev/null @@ -1,1288 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [7.2.82](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.81...graphql-auth-transformer@7.2.82) (2024-07-15) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.81](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.80...graphql-auth-transformer@7.2.81) (2024-07-02) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.80](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.79...graphql-auth-transformer@7.2.80) (2024-06-25) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.79](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.78...graphql-auth-transformer@7.2.79) (2024-04-26) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.78](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.77...graphql-auth-transformer@7.2.78) (2024-04-11) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.77](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.76...graphql-auth-transformer@7.2.77) (2024-03-28) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.76](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.75...graphql-auth-transformer@7.2.76) (2024-02-28) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.75](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.74...graphql-auth-transformer@7.2.75) (2024-02-05) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.74](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.73...graphql-auth-transformer@7.2.74) (2024-01-22) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.73](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.72...graphql-auth-transformer@7.2.73) (2023-12-18) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.72](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.71...graphql-auth-transformer@7.2.72) (2023-12-14) - -### Bug Fixes - -- Fix support for [@auth](https://github.com/auth) on fields with no [@model](https://github.com/model) ([79e4d83](https://github.com/aws-amplify/amplify-category-api/commit/79e4d83528d1581767265dae1006162c1a2110f6)) - -## [7.2.71](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.70...graphql-auth-transformer@7.2.71) (2023-12-06) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.70](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.69...graphql-auth-transformer@7.2.70) (2023-11-18) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.69](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.68...graphql-auth-transformer@7.2.69) (2023-11-16) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.68](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.67...graphql-auth-transformer@7.2.68) (2023-11-15) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.67](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.66...graphql-auth-transformer@7.2.67) (2023-10-21) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.66](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.65...graphql-auth-transformer@7.2.66) (2023-08-30) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.65](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.64...graphql-auth-transformer@7.2.65) (2023-08-28) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.64](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.63...graphql-auth-transformer@7.2.64) (2023-08-09) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.63](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.62...graphql-auth-transformer@7.2.63) (2023-07-21) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.62](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.61...graphql-auth-transformer@7.2.62) (2023-07-17) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.61](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.60...graphql-auth-transformer@7.2.61) (2023-07-07) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.60](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.59...graphql-auth-transformer@7.2.60) (2023-07-07) - -### Bug Fixes - -- trigger republish of dependencies that failed in https://app.circleci.com/pipelines/github/aws-amplify/amplify-category-api/7981/workflows/e7366f04-6f0a-4ee4-9cc2-1772089e8005/jobs/163571 ([f2c7151](https://github.com/aws-amplify/amplify-category-api/commit/f2c7151005e4a9fd29d91ac1af1f3e482a06a5cc)) - -## [7.2.59](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.58...graphql-auth-transformer@7.2.59) (2023-07-07) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.58](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.57...graphql-auth-transformer@7.2.58) (2023-06-29) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.57](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.56...graphql-auth-transformer@7.2.57) (2023-06-20) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.56](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.55...graphql-auth-transformer@7.2.56) (2023-06-05) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.55](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.54...graphql-auth-transformer@7.2.55) (2023-05-23) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.54](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.53...graphql-auth-transformer@7.2.54) (2023-05-17) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.53](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.52...graphql-auth-transformer@7.2.53) (2023-04-25) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.52](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.51...graphql-auth-transformer@7.2.52) (2023-03-30) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.51](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.50...graphql-auth-transformer@7.2.51) (2023-03-15) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.50](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.49...graphql-auth-transformer@7.2.50) (2023-03-01) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.49](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.48...graphql-auth-transformer@7.2.49) (2023-02-27) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.48](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.47...graphql-auth-transformer@7.2.48) (2023-01-26) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.47](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.46...graphql-auth-transformer@7.2.47) (2023-01-12) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.46](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.45...graphql-auth-transformer@7.2.46) (2023-01-12) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.45](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.44...graphql-auth-transformer@7.2.45) (2022-12-03) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.44](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.43...graphql-auth-transformer@7.2.44) (2022-09-14) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.43](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.42...graphql-auth-transformer@7.2.43) (2022-08-04) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.42](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.40...graphql-auth-transformer@7.2.42) (2022-07-20) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.41](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.40...graphql-auth-transformer@7.2.41) (2022-07-14) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.40](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.39...graphql-auth-transformer@7.2.40) (2022-07-01) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.39](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.38...graphql-auth-transformer@7.2.39) (2022-06-23) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.38](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.37...graphql-auth-transformer@7.2.38) (2022-06-13) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.37](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.36...graphql-auth-transformer@7.2.37) (2022-06-10) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.36](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.35...graphql-auth-transformer@7.2.36) (2022-06-10) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.35](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.32...graphql-auth-transformer@7.2.35) (2022-06-07) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.34](https://github.com/aws-amplify/amplify-category-api/compare/graphql-auth-transformer@7.2.32...graphql-auth-transformer@7.2.34) (2022-05-31) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.33](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.32...graphql-auth-transformer@7.2.33) (2022-05-02) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.32](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.31...graphql-auth-transformer@7.2.32) (2022-04-29) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.31](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.30...graphql-auth-transformer@7.2.31) (2022-04-27) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.30](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.29...graphql-auth-transformer@7.2.30) (2022-04-11) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.29](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.28...graphql-auth-transformer@7.2.29) (2022-04-07) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.28](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.27...graphql-auth-transformer@7.2.28) (2022-03-23) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.27](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.26...graphql-auth-transformer@7.2.27) (2022-03-17) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.26](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.25...graphql-auth-transformer@7.2.26) (2022-03-14) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.24...graphql-auth-transformer@7.2.25) (2022-03-07) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.23...graphql-auth-transformer@7.2.24) (2022-02-25) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.22...graphql-auth-transformer@7.2.23) (2022-02-15) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.18...graphql-auth-transformer@7.2.22) (2022-02-10) - -## 7.6.19 (2022-02-08) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.17...graphql-auth-transformer@7.2.18) (2022-02-03) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.16...graphql-auth-transformer@7.2.17) (2022-01-31) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.15...graphql-auth-transformer@7.2.16) (2022-01-27) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.14...graphql-auth-transformer@7.2.15) (2022-01-23) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.13...graphql-auth-transformer@7.2.14) (2022-01-13) - -### Bug Fixes - -- clean up missing and unused GraphQL v1 dependencies ([#9496](https://github.com/aws-amplify/amplify-cli/issues/9496)) ([fe8201b](https://github.com/aws-amplify/amplify-cli/commit/fe8201be17f42db233fce0bb366ff4d0c8358ec0)) - -## [7.2.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.11...graphql-auth-transformer@7.2.13) (2022-01-10) - -## 7.6.7 (2022-01-10) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.10...graphql-auth-transformer@7.2.11) (2021-12-21) - -### Bug Fixes - -- generate list types will nullable elements ([#9310](https://github.com/aws-amplify/amplify-cli/issues/9310)) ([e972956](https://github.com/aws-amplify/amplify-cli/commit/e9729565fef2ac7df51f7fc7f345da536f385ac1)) - -## [7.2.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.9...graphql-auth-transformer@7.2.10) (2021-12-17) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.8...graphql-auth-transformer@7.2.9) (2021-12-03) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.7...graphql-auth-transformer@7.2.8) (2021-12-02) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.6...graphql-auth-transformer@7.2.7) (2021-12-01) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.5...graphql-auth-transformer@7.2.6) (2021-11-26) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.4...graphql-auth-transformer@7.2.5) (2021-11-23) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.3...graphql-auth-transformer@7.2.4) (2021-11-21) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.2...graphql-auth-transformer@7.2.3) (2021-11-20) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@7.2.1...graphql-auth-transformer@7.2.2) (2021-11-17) - -**Note:** Version bump only for package graphql-auth-transformer - -## [7.2.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.25.0...graphql-auth-transformer@7.2.1) (2021-11-15) - -**Note:** Version bump only for package graphql-auth-transformer - -# [7.0.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.26...graphql-auth-transformer@7.0.0) (2021-11-13) - -### Features - -- flag to allow destructive schema changes ([#8273](https://github.com/aws-amplify/amplify-cli/issues/8273)) ([18de856](https://github.com/aws-amplify/amplify-cli/commit/18de856fb61bf2df8f73375e4e55a58c6159a232)) -- generate list types as non-null ([#8166](https://github.com/aws-amplify/amplify-cli/issues/8166)) ([93786c1](https://github.com/aws-amplify/amplify-cli/commit/93786c13ef04c72748ca32a1ef7878c0e6b5b129)) - -# [6.25.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.26...graphql-auth-transformer@6.25.0) (2021-11-11) - -### Features - -- flag to allow destructive schema changes ([#8273](https://github.com/aws-amplify/amplify-cli/issues/8273)) ([18de856](https://github.com/aws-amplify/amplify-cli/commit/18de856fb61bf2df8f73375e4e55a58c6159a232)) -- generate list types as non-null ([#8166](https://github.com/aws-amplify/amplify-cli/issues/8166)) ([93786c1](https://github.com/aws-amplify/amplify-cli/commit/93786c13ef04c72748ca32a1ef7878c0e6b5b129)) - -## [6.24.26](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.25...graphql-auth-transformer@6.24.26) (2021-10-10) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.24...graphql-auth-transformer@6.24.25) (2021-10-06) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.23...graphql-auth-transformer@6.24.24) (2021-10-01) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.22...graphql-auth-transformer@6.24.23) (2021-09-27) - -### Bug Fixes - -- **graphql-model-transformer:** [@model](https://github.com/model) conflict resolution ([#8035](https://github.com/aws-amplify/amplify-cli/issues/8035)) ([f3bdc4a](https://github.com/aws-amplify/amplify-cli/commit/f3bdc4ac1fcf596f634d9d2e968785e76f7b138c)) - -## [6.24.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.21...graphql-auth-transformer@6.24.22) (2021-09-18) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.21](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.20...graphql-auth-transformer@6.24.21) (2021-09-14) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.20](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.19...graphql-auth-transformer@6.24.20) (2021-09-09) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.19](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.18...graphql-auth-transformer@6.24.19) (2021-09-02) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.17...graphql-auth-transformer@6.24.18) (2021-08-24) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.16...graphql-auth-transformer@6.24.17) (2021-08-06) - -### Bug Fixes - -- **graphql-auth-transformer:** extend isOptional subscription owner check ([#7765](https://github.com/aws-amplify/amplify-cli/issues/7765)) ([28d49b4](https://github.com/aws-amplify/amplify-cli/commit/28d49b4d865ff3c19ffb36a601c4facac7ea7dc4)) - -## [6.24.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.15...graphql-auth-transformer@6.24.16) (2021-07-30) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.14...graphql-auth-transformer@6.24.15) (2021-07-27) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.13...graphql-auth-transformer@6.24.14) (2021-07-16) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.12...graphql-auth-transformer@6.24.13) (2021-06-30) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.11...graphql-auth-transformer@6.24.12) (2021-06-24) - -### Bug Fixes - -- **graphql-transformer-common:** improve generated graphql pluralization ([#7258](https://github.com/aws-amplify/amplify-cli/issues/7258)) ([fc3ad0d](https://github.com/aws-amplify/amplify-cli/commit/fc3ad0dd5a12a7912c59ae12024f593b4cdf7f2d)), closes [#4224](https://github.com/aws-amplify/amplify-cli/issues/4224) -- validates optional non nullable fields to be not null ([#7170](https://github.com/aws-amplify/amplify-cli/issues/7170)) ([1ca842c](https://github.com/aws-amplify/amplify-cli/commit/1ca842c703bfc34e65bfffff85908ea8b2ccb521)) - -## [6.24.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.10...graphql-auth-transformer@6.24.11) (2021-06-15) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.9...graphql-auth-transformer@6.24.10) (2021-05-29) - -## 4.51.4 (2021-05-28) - -### Bug Fixes - -- **graphql-model-transformer:** use modelobject key for mutation resolver creation ([#7419](https://github.com/aws-amplify/amplify-cli/issues/7419)) ([37bc551](https://github.com/aws-amplify/amplify-cli/commit/37bc551030d47de993f8227ee3af0ba6cd738ab2)), closes [#i7417](https://github.com/aws-amplify/amplify-cli/issues/i7417) - -## [6.24.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.8...graphql-auth-transformer@6.24.9) (2021-05-26) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.7...graphql-auth-transformer@6.24.8) (2021-05-18) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** make primary key non null on del ([#6337](https://github.com/aws-amplify/amplify-cli/issues/6337)) ([4a5c679](https://github.com/aws-amplify/amplify-cli/commit/4a5c6795680b6b88efb19b923ee234253ca30c35)), closes [#2564](https://github.com/aws-amplify/amplify-cli/issues/2564) - -## [6.24.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.6...graphql-auth-transformer@6.24.7) (2021-05-14) - -### Bug Fixes - -- **graphql-auth-transformer:** fixes [@auth](https://github.com/auth) directives for Admin UI ([#7035](https://github.com/aws-amplify/amplify-cli/issues/7035)) ([d4f2f1e](https://github.com/aws-amplify/amplify-cli/commit/d4f2f1e9f5bfd1803711dcb1ba50ca845005a7e5)) - -## [6.24.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.4...graphql-auth-transformer@6.24.6) (2021-05-03) - -## 4.50.1 (2021-05-03) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.4...graphql-auth-transformer@6.24.5) (2021-05-03) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.3...graphql-auth-transformer@6.24.4) (2021-04-27) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.2...graphql-auth-transformer@6.24.3) (2021-04-19) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.24.1...graphql-auth-transformer@6.24.2) (2021-04-14) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.24.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.23.11...graphql-auth-transformer@6.24.1) (2021-04-09) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.23.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.23.10...graphql-auth-transformer@6.23.11) (2021-03-23) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.23.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.23.9...graphql-auth-transformer@6.23.10) (2021-03-11) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.23.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.23.8...graphql-auth-transformer@6.23.9) (2021-03-05) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.23.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.23.7...graphql-auth-transformer@6.23.8) (2021-02-26) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.23.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.23.6...graphql-auth-transformer@6.23.7) (2021-02-24) - -### Bug Fixes - -- **graphql-auth-transformer:** fix auth on non model types ([#6579](https://github.com/aws-amplify/amplify-cli/issues/6579)) ([deb53bd](https://github.com/aws-amplify/amplify-cli/commit/deb53bd36a0994d951f6e120c0b8f0b1ee0dfdc8)), closes [#6557](https://github.com/aws-amplify/amplify-cli/issues/6557) - -## [6.23.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.23.5...graphql-auth-transformer@6.23.6) (2021-02-17) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.23.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.23.4...graphql-auth-transformer@6.23.5) (2021-02-11) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.23.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.23.3...graphql-auth-transformer@6.23.4) (2021-02-10) - -### Bug Fixes - -- **graphql-auth-transformer:** protection for connection types ([#5655](https://github.com/aws-amplify/amplify-cli/issues/5655)) ([52d33f8](https://github.com/aws-amplify/amplify-cli/commit/52d33f8a114266720b7429de4ab3360fea0f63b7)), closes [#4874](https://github.com/aws-amplify/amplify-cli/issues/4874) [#5510](https://github.com/aws-amplify/amplify-cli/issues/5510) - -## [6.23.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.23.2...graphql-auth-transformer@6.23.3) (2021-01-08) - -### Bug Fixes - -- **graphql-auth-transformer:** fix field auth with connection ([#6320](https://github.com/aws-amplify/amplify-cli/issues/6320)) ([8cc85d0](https://github.com/aws-amplify/amplify-cli/commit/8cc85d0da8b1877e19285f9b8347dd54f48d87a1)), closes [#4760](https://github.com/aws-amplify/amplify-cli/issues/4760) - -## [6.23.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.23.1...graphql-auth-transformer@6.23.2) (2020-12-16) - -### Bug Fixes - -- [#6108](https://github.com/aws-amplify/amplify-cli/issues/6108) - add proper AWSJSON mapping in generated filter input types ([#6112](https://github.com/aws-amplify/amplify-cli/issues/6112)) ([743e84a](https://github.com/aws-amplify/amplify-cli/commit/743e84a9d968aab4648a12d3a19aa5ea14c4d755)) - -### Reverts - -- Revert "Revert "Revert "fix: #6108 - add proper AWSJSON mapping in generated filter input types (#6112)" (#6158)" (#6160)" (#6183) ([a0ca94e](https://github.com/aws-amplify/amplify-cli/commit/a0ca94e5a1a848404ef3977743f19d26300a636a)), closes [#6108](https://github.com/aws-amplify/amplify-cli/issues/6108) [#6112](https://github.com/aws-amplify/amplify-cli/issues/6112) [#6158](https://github.com/aws-amplify/amplify-cli/issues/6158) [#6160](https://github.com/aws-amplify/amplify-cli/issues/6160) [#6183](https://github.com/aws-amplify/amplify-cli/issues/6183) -- Revert "Revert "fix: #6108 - add proper AWSJSON mapping in generated filter input types (#6112)" (#6158)" (#6160) ([f425924](https://github.com/aws-amplify/amplify-cli/commit/f42592420dcb49640c680c5001b3026ae0129090)), closes [#6108](https://github.com/aws-amplify/amplify-cli/issues/6108) [#6112](https://github.com/aws-amplify/amplify-cli/issues/6112) [#6158](https://github.com/aws-amplify/amplify-cli/issues/6158) [#6160](https://github.com/aws-amplify/amplify-cli/issues/6160) -- Revert "fix: #6108 - add proper AWSJSON mapping in generated filter input types (#6112)" (#6158) ([9e57e4d](https://github.com/aws-amplify/amplify-cli/commit/9e57e4d8c887be8ee4119c87383c7379cec40c37)), closes [#6108](https://github.com/aws-amplify/amplify-cli/issues/6108) [#6112](https://github.com/aws-amplify/amplify-cli/issues/6112) [#6158](https://github.com/aws-amplify/amplify-cli/issues/6158) - -## [6.23.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.23.0...graphql-auth-transformer@6.23.1) (2020-12-07) - -**Note:** Version bump only for package graphql-auth-transformer - -# [6.23.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.22.1...graphql-auth-transformer@6.23.0) (2020-11-30) - -### Features - -- pre-deploy pull, new login mechanism and pkg cli updates ([#5941](https://github.com/aws-amplify/amplify-cli/issues/5941)) ([7274251](https://github.com/aws-amplify/amplify-cli/commit/7274251faadc1035acce5f44699b172e10e2e67d)) - -## [6.22.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.21.1...graphql-auth-transformer@6.22.1) (2020-11-22) - -**Note:** Version bump only for package graphql-auth-transformer - -# [6.22.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.7.5...graphql-auth-transformer@6.22.0) (2020-11-22) - -### Bug Fixes - -- **graphql-auth-transformer:** add a time delay when creating apiKey ([#4493](https://github.com/aws-amplify/amplify-cli/issues/4493)) ([3f544e7](https://github.com/aws-amplify/amplify-cli/commit/3f544e7f421f66f3d4e920cdd89ddb926c412241)) -- **graphql-auth-transformer:** add authmode check ([#5014](https://github.com/aws-amplify/amplify-cli/issues/5014)) ([23080c4](https://github.com/aws-amplify/amplify-cli/commit/23080c4406dde488b68c38d01efbb625537894ab)), closes [#3700](https://github.com/aws-amplify/amplify-cli/issues/3700) -- **graphql-auth-transformer:** add list support for ownerField in subs ([#3166](https://github.com/aws-amplify/amplify-cli/issues/3166)) ([8d68277](https://github.com/aws-amplify/amplify-cli/commit/8d6827752ebd076424d3c76122b136eca65b02a8)) -- **graphql-auth-transformer:** add support for ownerfield ([eaa3451](https://github.com/aws-amplify/amplify-cli/commit/eaa345158e83c0c169bd2c290601f0f3481dba04)), closes [#2361](https://github.com/aws-amplify/amplify-cli/issues/2361) -- **graphql-auth-transformer:** added helper function for static auth var ([24c8f6d](https://github.com/aws-amplify/amplify-cli/commit/24c8f6d37508fd98a55cd2f892e5d17414c5e9fe)) -- **graphql-auth-transformer:** added staticgroupVar function ([#2433](https://github.com/aws-amplify/amplify-cli/issues/2433)) ([e168d1c](https://github.com/aws-amplify/amplify-cli/commit/e168d1cd1899bb9990ffca88d0a01b83b8e3f19f)) -- **graphql-auth-transformer:** allow auth progation to recursive types ([#4788](https://github.com/aws-amplify/amplify-cli/issues/4788)) ([6402304](https://github.com/aws-amplify/amplify-cli/commit/6402304b6bae2ac17156c4da94d013362239e5ca)), closes [#4631](https://github.com/aws-amplify/amplify-cli/issues/4631) -- **graphql-auth-transformer:** allow optional owner arg on multi auth ([#4719](https://github.com/aws-amplify/amplify-cli/issues/4719)) ([fd0a4bc](https://github.com/aws-amplify/amplify-cli/commit/fd0a4bcfbf8532cb3e13438923a1e03f7260ef26)), closes [#4638](https://github.com/aws-amplify/amplify-cli/issues/4638) -- **graphql-auth-transformer:** early return if no obj ([#5050](https://github.com/aws-amplify/amplify-cli/issues/5050)) ([ed1f2b3](https://github.com/aws-amplify/amplify-cli/commit/ed1f2b364b50ab3f2b16ddac849c937b239bb499)) -- **graphql-auth-transformer:** fix null owner auth assignment ([#5045](https://github.com/aws-amplify/amplify-cli/issues/5045)) ([72bdb19](https://github.com/aws-amplify/amplify-cli/commit/72bdb19f83396237d59f33ed968e47e62df5d500)), closes [#5018](https://github.com/aws-amplify/amplify-cli/issues/5018) -- [#3910](https://github.com/aws-amplify/amplify-cli/issues/3910) - propagate non-model auth to nested types ([#4477](https://github.com/aws-amplify/amplify-cli/issues/4477)) ([8d0892f](https://github.com/aws-amplify/amplify-cli/commit/8d0892fa4d71d5e9e60c4409ca704f9ce548d379)) -- **graphql-auth-transformer:** fix dynamic group auth permission check ([#4084](https://github.com/aws-amplify/amplify-cli/issues/4084)) ([688e831](https://github.com/aws-amplify/amplify-cli/commit/688e83148f554eb5f0803d0a603ae569609757ab)) -- **graphql-auth-transformer:** fixed per field delete logic ([#2333](https://github.com/aws-amplify/amplify-cli/issues/2333)) ([00db7c8](https://github.com/aws-amplify/amplify-cli/commit/00db7c89114263ca9b88d0b978a12a05e43ab9a1)) -- **graphql-auth-transformer:** include ApiKeyConfig in additional providers ([#2744](https://github.com/aws-amplify/amplify-cli/issues/2744)) ([d1dc7ac](https://github.com/aws-amplify/amplify-cli/commit/d1dc7acbbf27a567df6c250ae4428943ca2f66d0)), closes [#2741](https://github.com/aws-amplify/amplify-cli/issues/2741) -- **graphql-auth-transformer:** remove enforce model check for field ([#2607](https://github.com/aws-amplify/amplify-cli/issues/2607)) ([b1d6d4b](https://github.com/aws-amplify/amplify-cli/commit/b1d6d4b1c933e552874b3bb016f611567df186d0)), closes [#2591](https://github.com/aws-amplify/amplify-cli/issues/2591) [#2591](https://github.com/aws-amplify/amplify-cli/issues/2591) -- **graphql-auth-transformer:** removed subs auth check for field ([9584254](https://github.com/aws-amplify/amplify-cli/commit/95842542d2c2cf6178f660faf3f20009fd848c60)) -- **graphql-auth-transformer:** use read to allow subscriptions ([#4340](https://github.com/aws-amplify/amplify-cli/issues/4340)) ([b8fc10d](https://github.com/aws-amplify/amplify-cli/commit/b8fc10d4e55c871826f1309fe340e32d0259ac0e)), closes [#3777](https://github.com/aws-amplify/amplify-cli/issues/3777) [#4182](https://github.com/aws-amplify/amplify-cli/issues/4182) [#4137](https://github.com/aws-amplify/amplify-cli/issues/4137) -- **graphql-elasticsearch-transformer:** support del in sync enabled API ([#4281](https://github.com/aws-amplify/amplify-cli/issues/4281)) ([bae946d](https://github.com/aws-amplify/amplify-cli/commit/bae946dabe4a2e37cfdb87c6fbd88af824f21b69)), closes [#4228](https://github.com/aws-amplify/amplify-cli/issues/4228) [#4228](https://github.com/aws-amplify/amplify-cli/issues/4228) -- [#2013](https://github.com/aws-amplify/amplify-cli/issues/2013) - Dynamic group auth when groups field is null ([#2097](https://github.com/aws-amplify/amplify-cli/issues/2097)) ([4ad3d5c](https://github.com/aws-amplify/amplify-cli/commit/4ad3d5cf34f689867ce3929f8fa84e751985fbfe)) -- [#2272](https://github.com/aws-amplify/amplify-cli/issues/2272), [#2273](https://github.com/aws-amplify/amplify-cli/issues/2273) - create correct policies when IAM is the default auth ([#2276](https://github.com/aws-amplify/amplify-cli/issues/2276)) ([5ae0686](https://github.com/aws-amplify/amplify-cli/commit/5ae06868eb48f9cd8e5474af900bb5528d9740c4)) -- [#2703](https://github.com/aws-amplify/amplify-cli/issues/2703) - policy size calculation ([#3016](https://github.com/aws-amplify/amplify-cli/issues/3016)) ([dcee2aa](https://github.com/aws-amplify/amplify-cli/commit/dcee2aab12b40562d1c6f0d260b830ca4ab0bedd)) -- [#2711](https://github.com/aws-amplify/amplify-cli/issues/2711) - usage of [@auth](https://github.com/auth) without [@model](https://github.com/model) on fields ([#3590](https://github.com/aws-amplify/amplify-cli/issues/3590)) ([553186e](https://github.com/aws-amplify/amplify-cli/commit/553186e53050cafdf27120443d176023ef4acebc)) -- [#2727](https://github.com/aws-amplify/amplify-cli/issues/2727) ([#2754](https://github.com/aws-amplify/amplify-cli/issues/2754)) ([44a7b54](https://github.com/aws-amplify/amplify-cli/commit/44a7b549f84ff8d752fd0dc87d6d689a609a579d)) -- build break, chore: typescript, lerna update ([#2640](https://github.com/aws-amplify/amplify-cli/issues/2640)) ([29fae36](https://github.com/aws-amplify/amplify-cli/commit/29fae366f4cab054feefa58c7dc733002d19570c)) -- change default length for api key back to 7 days ([#2507](https://github.com/aws-amplify/amplify-cli/issues/2507)) ([6a7e61f](https://github.com/aws-amplify/amplify-cli/commit/6a7e61fc7315f5e732ad7b36b5c0ae88ea36b628)) -- directive generation for groups auth ([#2305](https://github.com/aws-amplify/amplify-cli/issues/2305)) ([1ce074e](https://github.com/aws-amplify/amplify-cli/commit/1ce074e2ee3097ebb8e66c3603d3617cbf36f0d4)) -- export Typescript definitions and fix resulting type errors ([#2452](https://github.com/aws-amplify/amplify-cli/issues/2452)) ([7de3845](https://github.com/aws-amplify/amplify-cli/commit/7de384594d3b9cbf22cdaa85107fc8df26c141ec)), closes [#2451](https://github.com/aws-amplify/amplify-cli/issues/2451) -- fix typo in comment ([#3490](https://github.com/aws-amplify/amplify-cli/issues/3490)) ([ad3a137](https://github.com/aws-amplify/amplify-cli/commit/ad3a1375ff1e81a6ef5567c2518434114c852df0)) -- fixed bug with per field auth on create ([#2327](https://github.com/aws-amplify/amplify-cli/issues/2327)) ([3206e45](https://github.com/aws-amplify/amplify-cli/commit/3206e45f401c7407acee0a248341930ede6a3dfb)), closes [#2316](https://github.com/aws-amplify/amplify-cli/issues/2316) -- generate iam policies for auth role for public rules as well ([#2258](https://github.com/aws-amplify/amplify-cli/issues/2258)) ([6bbfce3](https://github.com/aws-amplify/amplify-cli/commit/6bbfce3addeb0228088a8094f680d4e82823a305)) -- handle [@auth](https://github.com/auth) propagation for non-model nested types ([#3223](https://github.com/aws-amplify/amplify-cli/issues/3223)) ([9a517aa](https://github.com/aws-amplify/amplify-cli/commit/9a517aaf7d23b5bf12b7513d5b0f79c086518f49)) -- non-model [@auth](https://github.com/auth) propagation fails enums ([#3252](https://github.com/aws-amplify/amplify-cli/issues/3252)) ([f48fefa](https://github.com/aws-amplify/amplify-cli/commit/f48fefa31cb36846af2b029ecf3c0c7049937811)) -- sanitize input in transformer resolver([#3316](https://github.com/aws-amplify/amplify-cli/issues/3316)) ([a3bc0a5](https://github.com/aws-amplify/amplify-cli/commit/a3bc0a5e5d3faa7946d16d0f6595ce8c2f3c11dc)) -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) -- use managedpolicies and slice them ([#2883](https://github.com/aws-amplify/amplify-cli/issues/2883)) ([fa0f2ed](https://github.com/aws-amplify/amplify-cli/commit/fa0f2ed2fc725d964cbaf11a892b3850aaf42d84)), closes [#2084](https://github.com/aws-amplify/amplify-cli/issues/2084) -- **graphql-auth-transformer:** verify multiple static group auth rules ([289d575](https://github.com/aws-amplify/amplify-cli/commit/289d5758439e89c52a45c529c1e58b1f361ca83b)), closes [#2241](https://github.com/aws-amplify/amplify-cli/issues/2241) - -### Features - -- **graphql-elasticsearch-transformer:** add 'from' query parameter ([#5098](https://github.com/aws-amplify/amplify-cli/issues/5098)) ([d52a804](https://github.com/aws-amplify/amplify-cli/commit/d52a804c25df63cd1cee1a72bb99286ecfe54ed5)) -- headless mode for API category ([#4834](https://github.com/aws-amplify/amplify-cli/issues/4834)) ([c2e09d7](https://github.com/aws-amplify/amplify-cli/commit/c2e09d73fd1bb461eeace8f4a7addd70a63047ad)) -- **amplify-category-auth:** allow more than one groupClaim ([f4397e0](https://github.com/aws-amplify/amplify-cli/commit/f4397e089513e16db5f363458c3c61b351acb5b9)) -- **graphql-auth-transformer:** enable groups authentication for oidc ([#2719](https://github.com/aws-amplify/amplify-cli/issues/2719)) ([741eedb](https://github.com/aws-amplify/amplify-cli/commit/741eedb0fd5ebeefa32c0640d1585a828e244eae)) -- **graphql-dynamodb-transformer:** expose createdAt and updatedAt on model ([#4149](https://github.com/aws-amplify/amplify-cli/issues/4149)) ([8e0662e](https://github.com/aws-amplify/amplify-cli/commit/8e0662eac8c88da9393f32c33457a597acf591ed)), closes [#401](https://github.com/aws-amplify/amplify-cli/issues/401) -- **graphql-elasticsearch-transformer:** add total in es response ([#2602](https://github.com/aws-amplify/amplify-cli/issues/2602)) ([dbdb000](https://github.com/aws-amplify/amplify-cli/commit/dbdb0002b8e7cd33e37880d3166bc99c5faf1234)), closes [#2600](https://github.com/aws-amplify/amplify-cli/issues/2600) -- **graphql-key-transformer:** add query automatically for named keys ([#4458](https://github.com/aws-amplify/amplify-cli/issues/4458)) ([375282d](https://github.com/aws-amplify/amplify-cli/commit/375282d648cf9d096d13c7b958a0dfb7bd6d60b0)) -- **graphql-key-transformer:** auto population of id and timestamp ([#4382](https://github.com/aws-amplify/amplify-cli/issues/4382)) ([6586611](https://github.com/aws-amplify/amplify-cli/commit/6586611293a07db9959247ff82f95542a239ff1f)) -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c1927da10f8c54f38a523021187361131c)) -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- implement multi-auth functionality ([#1916](https://github.com/aws-amplify/amplify-cli/issues/1916)) ([b99f58e](https://github.com/aws-amplify/amplify-cli/commit/b99f58e4a2b85cbe9f430838554ae3c277440132)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -### Reverts - -- add query automatically for named keys ([#4513](https://github.com/aws-amplify/amplify-cli/issues/4513)) ([50c1120](https://github.com/aws-amplify/amplify-cli/commit/50c112050645b8fd5011a1e6863d30f58e0c55cb)) -- Revert "fix(graphql-auth-transformer): add list support for ownerField in subs (#3166)" (#3572) ([d693e6b](https://github.com/aws-amplify/amplify-cli/commit/d693e6b2819a5d20188fa9f68d94ef955e474bd3)), closes [#3166](https://github.com/aws-amplify/amplify-cli/issues/3166) [#3572](https://github.com/aws-amplify/amplify-cli/issues/3572) - -* Adding Auth on Subscriptions (#2068) ([81c630d](https://github.com/aws-amplify/amplify-cli/commit/81c630d782a6be720e513677a34b7a7dacbdc629)), closes [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) - -### BREAKING CHANGES - -- If an owner is used in the auth directive it will either be a requirement if it's - the only rule or an optional input if used with other rules -- If an owner is included in the auth directive it will either be a requirement if - it's the only rule or an optional input if used with other rules -- the subscription operations will require an argument if owner is the only auth rule -- Subscriptions will require an argument if an owner is only rule set - If owner & - group rules are owner will be an optional arg - -## [6.21.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.21.1...graphql-auth-transformer@6.21.4) (2020-11-20) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.21.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.21.1...graphql-auth-transformer@6.21.3) (2020-11-20) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.21.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.21.1...graphql-auth-transformer@6.21.2) (2020-11-19) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.21.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.21.0...graphql-auth-transformer@6.21.1) (2020-11-08) - -**Note:** Version bump only for package graphql-auth-transformer - -# [6.21.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.20.10...graphql-auth-transformer@6.21.0) (2020-10-30) - -### Features - -- **graphql-elasticsearch-transformer:** add 'from' query parameter ([#5098](https://github.com/aws-amplify/amplify-cli/issues/5098)) ([d52a804](https://github.com/aws-amplify/amplify-cli/commit/d52a804c25df63cd1cee1a72bb99286ecfe54ed5)) - -## [6.20.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.20.9...graphql-auth-transformer@6.20.10) (2020-10-27) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.20.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.20.8...graphql-auth-transformer@6.20.9) (2020-10-22) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.20.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.20.7...graphql-auth-transformer@6.20.8) (2020-10-17) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.20.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.20.6...graphql-auth-transformer@6.20.7) (2020-10-01) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.20.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.20.5...graphql-auth-transformer@6.20.6) (2020-09-16) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.20.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.20.4...graphql-auth-transformer@6.20.5) (2020-09-02) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.20.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.20.3...graphql-auth-transformer@6.20.4) (2020-08-31) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.20.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.20.2...graphql-auth-transformer@6.20.3) (2020-08-20) - -### Bug Fixes - -- **graphql-auth-transformer:** allow optional owner arg on multi auth ([#4719](https://github.com/aws-amplify/amplify-cli/issues/4719)) ([fd0a4bc](https://github.com/aws-amplify/amplify-cli/commit/fd0a4bcfbf8532cb3e13438923a1e03f7260ef26)), closes [#4638](https://github.com/aws-amplify/amplify-cli/issues/4638) - -## [6.20.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.20.1...graphql-auth-transformer@6.20.2) (2020-08-14) - -### Bug Fixes - -- **graphql-auth-transformer:** add authmode check ([#5014](https://github.com/aws-amplify/amplify-cli/issues/5014)) ([23080c4](https://github.com/aws-amplify/amplify-cli/commit/23080c4406dde488b68c38d01efbb625537894ab)), closes [#3700](https://github.com/aws-amplify/amplify-cli/issues/3700) -- **graphql-auth-transformer:** early return if no obj ([#5050](https://github.com/aws-amplify/amplify-cli/issues/5050)) ([ed1f2b3](https://github.com/aws-amplify/amplify-cli/commit/ed1f2b364b50ab3f2b16ddac849c937b239bb499)) - -## [6.20.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.20.0...graphql-auth-transformer@6.20.1) (2020-08-11) - -### Bug Fixes - -- **graphql-auth-transformer:** fix null owner auth assignment ([#5045](https://github.com/aws-amplify/amplify-cli/issues/5045)) ([72bdb19](https://github.com/aws-amplify/amplify-cli/commit/72bdb19f83396237d59f33ed968e47e62df5d500)), closes [#5018](https://github.com/aws-amplify/amplify-cli/issues/5018) - -# [6.20.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.18.6...graphql-auth-transformer@6.20.0) (2020-07-29) - -### Features - -- headless mode for API category ([#4834](https://github.com/aws-amplify/amplify-cli/issues/4834)) ([c2e09d7](https://github.com/aws-amplify/amplify-cli/commit/c2e09d73fd1bb461eeace8f4a7addd70a63047ad)) - -# [6.19.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.18.6...graphql-auth-transformer@6.19.0) (2020-07-23) - -### Features - -- headless mode for API category ([#4834](https://github.com/aws-amplify/amplify-cli/issues/4834)) ([b729266](https://github.com/aws-amplify/amplify-cli/commit/b729266b9bb519738ef88125784d72ac428f47e1)) - -## [6.18.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.18.5...graphql-auth-transformer@6.18.6) (2020-07-18) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.18.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.18.4...graphql-auth-transformer@6.18.5) (2020-07-15) - -### Bug Fixes - -- **graphql-auth-transformer:** add a time delay when creating apiKey ([#4493](https://github.com/aws-amplify/amplify-cli/issues/4493)) ([1d56b40](https://github.com/aws-amplify/amplify-cli/commit/1d56b40d673b257e07905d9bc1830e8f9c8495a1)) - -## [6.18.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.18.3...graphql-auth-transformer@6.18.4) (2020-07-14) - -### Bug Fixes - -- **graphql-auth-transformer:** allow auth progation to recursive types ([#4788](https://github.com/aws-amplify/amplify-cli/issues/4788)) ([827c7b8](https://github.com/aws-amplify/amplify-cli/commit/827c7b8df81fdae38826c94f7ac7698a8887001a)), closes [#4631](https://github.com/aws-amplify/amplify-cli/issues/4631) - -## [6.18.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.18.2...graphql-auth-transformer@6.18.3) (2020-06-25) - -### Reverts - -- Revert "fix: change scope of hashed files for AppSync (#4602)" ([73aaab1](https://github.com/aws-amplify/amplify-cli/commit/73aaab1a7b1f8b2de5fa22fa1ef9aeea7de35cb4)), closes [#4602](https://github.com/aws-amplify/amplify-cli/issues/4602) - -## [6.18.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.18.1...graphql-auth-transformer@6.18.2) (2020-06-18) - -### Bug Fixes - -- change scope of hashed files for AppSync ([#4602](https://github.com/aws-amplify/amplify-cli/issues/4602)) ([10fa9da](https://github.com/aws-amplify/amplify-cli/commit/10fa9da646f4de755e2dc92cd4bb2a6319425d72)), closes [#4458](https://github.com/aws-amplify/amplify-cli/issues/4458) - -## [6.18.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.18.0...graphql-auth-transformer@6.18.1) (2020-06-11) - -### Reverts - -- add query automatically for named keys ([#4513](https://github.com/aws-amplify/amplify-cli/issues/4513)) ([6d3123b](https://github.com/aws-amplify/amplify-cli/commit/6d3123bfe3ba412d3b1af076e550e6733c988c8f)) - -# [6.18.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.17.0...graphql-auth-transformer@6.18.0) (2020-06-10) - -### Bug Fixes - -- [#3910](https://github.com/aws-amplify/amplify-cli/issues/3910) - propagate non-model auth to nested types ([#4477](https://github.com/aws-amplify/amplify-cli/issues/4477)) ([493e631](https://github.com/aws-amplify/amplify-cli/commit/493e631b51643ab22e7497591464e882a1bba7df)) - -### Features - -- **graphql-key-transformer:** add query automatically for named keys ([#4458](https://github.com/aws-amplify/amplify-cli/issues/4458)) ([3d194f8](https://github.com/aws-amplify/amplify-cli/commit/3d194f805dcbd6325ddf78155c4327dbca3e7f4a)) - -# [6.17.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.16.1...graphql-auth-transformer@6.17.0) (2020-06-02) - -### Bug Fixes - -- **graphql-auth-transformer:** use read to allow subscriptions ([#4340](https://github.com/aws-amplify/amplify-cli/issues/4340)) ([15eac84](https://github.com/aws-amplify/amplify-cli/commit/15eac8454e0455cd402776308a2716ac406bacbb)), closes [#3777](https://github.com/aws-amplify/amplify-cli/issues/3777) [#4182](https://github.com/aws-amplify/amplify-cli/issues/4182) [#4137](https://github.com/aws-amplify/amplify-cli/issues/4137) - -### Features - -- **graphql-key-transformer:** auto population of id and timestamp ([#4382](https://github.com/aws-amplify/amplify-cli/issues/4382)) ([c0a4f88](https://github.com/aws-amplify/amplify-cli/commit/c0a4f8889fc363bb9c9d08ff822c591874777f7b)) - -## [6.16.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.16.0...graphql-auth-transformer@6.16.1) (2020-05-26) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** support del in sync enabled API ([#4281](https://github.com/aws-amplify/amplify-cli/issues/4281)) ([f57f824](https://github.com/aws-amplify/amplify-cli/commit/f57f8242f18c79d48b751e29952e3cdd21409f98)), closes [#4228](https://github.com/aws-amplify/amplify-cli/issues/4228) [#4228](https://github.com/aws-amplify/amplify-cli/issues/4228) - -# [6.16.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.15.4...graphql-auth-transformer@6.16.0) (2020-05-15) - -### Features - -- **graphql-dynamodb-transformer:** expose createdAt and updatedAt on model ([#4149](https://github.com/aws-amplify/amplify-cli/issues/4149)) ([8e0662e](https://github.com/aws-amplify/amplify-cli/commit/8e0662eac8c88da9393f32c33457a597acf591ed)), closes [#401](https://github.com/aws-amplify/amplify-cli/issues/401) - -## [6.15.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.15.3...graphql-auth-transformer@6.15.4) (2020-05-08) - -### Bug Fixes - -- **graphql-auth-transformer:** fix dynamic group auth permission check ([#4084](https://github.com/aws-amplify/amplify-cli/issues/4084)) ([688e831](https://github.com/aws-amplify/amplify-cli/commit/688e83148f554eb5f0803d0a603ae569609757ab)) - -## [6.15.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.15.2...graphql-auth-transformer@6.15.3) (2020-04-23) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.15.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.15.1...graphql-auth-transformer@6.15.2) (2020-03-22) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.15.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.13.4...graphql-auth-transformer@6.15.1) (2020-03-07) - -### Bug Fixes - -- **graphql-auth-transformer:** add list support for ownerField in subs ([#3166](https://github.com/aws-amplify/amplify-cli/issues/3166)) ([8d68277](https://github.com/aws-amplify/amplify-cli/commit/8d6827752ebd076424d3c76122b136eca65b02a8)) -- [#2711](https://github.com/aws-amplify/amplify-cli/issues/2711) - usage of [@auth](https://github.com/auth) without [@model](https://github.com/model) on fields ([#3590](https://github.com/aws-amplify/amplify-cli/issues/3590)) ([553186e](https://github.com/aws-amplify/amplify-cli/commit/553186e53050cafdf27120443d176023ef4acebc)) -- fix typo in comment ([#3490](https://github.com/aws-amplify/amplify-cli/issues/3490)) ([ad3a137](https://github.com/aws-amplify/amplify-cli/commit/ad3a1375ff1e81a6ef5567c2518434114c852df0)) - -### Reverts - -- Revert "fix(graphql-auth-transformer): add list support for ownerField in subs (#3166)" (#3572) ([d693e6b](https://github.com/aws-amplify/amplify-cli/commit/d693e6b2819a5d20188fa9f68d94ef955e474bd3)), closes [#3166](https://github.com/aws-amplify/amplify-cli/issues/3166) [#3572](https://github.com/aws-amplify/amplify-cli/issues/3572) - -## [6.14.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.13.6-beta.0...graphql-auth-transformer@6.14.1) (2020-03-05) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.13.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.13.3...graphql-auth-transformer@6.13.4) (2020-02-18) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.13.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.13.2...graphql-auth-transformer@6.13.3) (2020-02-13) - -**Note:** Version bump only for package graphql-auth-transformer - -## [6.13.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.13.1...graphql-auth-transformer@6.13.2) (2020-02-07) - -### Bug Fixes - -- sanitize input in transformer resolver([#3316](https://github.com/aws-amplify/amplify-cli/issues/3316)) ([a3bc0a5](https://github.com/aws-amplify/amplify-cli/commit/a3bc0a5e5d3faa7946d16d0f6595ce8c2f3c11dc)) - -## [6.13.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@6.13.0...graphql-auth-transformer@6.13.1) (2020-01-24) - -### Bug Fixes - -- non-model [@auth](https://github.com/auth) propagation fails enums ([#3252](https://github.com/aws-amplify/amplify-cli/issues/3252)) ([f48fefa](https://github.com/aws-amplify/amplify-cli/commit/f48fefa31cb36846af2b029ecf3c0c7049937811)) - -# [6.13.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@5.18.0...graphql-auth-transformer@6.13.0) (2020-01-23) - -### Bug Fixes - -- **graphql-auth-transformer:** include ApiKeyConfig in additional providers ([#2744](https://github.com/aws-amplify/amplify-cli/issues/2744)) ([d1dc7ac](https://github.com/aws-amplify/amplify-cli/commit/d1dc7acbbf27a567df6c250ae4428943ca2f66d0)), closes [#2741](https://github.com/aws-amplify/amplify-cli/issues/2741) -- [#2703](https://github.com/aws-amplify/amplify-cli/issues/2703) - policy size calculation ([#3016](https://github.com/aws-amplify/amplify-cli/issues/3016)) ([dcee2aa](https://github.com/aws-amplify/amplify-cli/commit/dcee2aab12b40562d1c6f0d260b830ca4ab0bedd)) -- [#2727](https://github.com/aws-amplify/amplify-cli/issues/2727) ([#2754](https://github.com/aws-amplify/amplify-cli/issues/2754)) ([44a7b54](https://github.com/aws-amplify/amplify-cli/commit/44a7b549f84ff8d752fd0dc87d6d689a609a579d)) -- handle [@auth](https://github.com/auth) propagation for non-model nested types ([#3223](https://github.com/aws-amplify/amplify-cli/issues/3223)) ([9a517aa](https://github.com/aws-amplify/amplify-cli/commit/9a517aaf7d23b5bf12b7513d5b0f79c086518f49)) -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) -- use managedpolicies and slice them ([#2883](https://github.com/aws-amplify/amplify-cli/issues/2883)) ([fa0f2ed](https://github.com/aws-amplify/amplify-cli/commit/fa0f2ed2fc725d964cbaf11a892b3850aaf42d84)), closes [#2084](https://github.com/aws-amplify/amplify-cli/issues/2084) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) -- **graphql-auth-transformer:** enable groups authentication for oidc ([#2719](https://github.com/aws-amplify/amplify-cli/issues/2719)) ([741eedb](https://github.com/aws-amplify/amplify-cli/commit/741eedb0fd5ebeefa32c0640d1585a828e244eae)) - -# [6.12.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@5.18.0...graphql-auth-transformer@6.12.0) (2020-01-09) - -### Bug Fixes - -- **graphql-auth-transformer:** include ApiKeyConfig in additional providers ([#2744](https://github.com/aws-amplify/amplify-cli/issues/2744)) ([d1dc7ac](https://github.com/aws-amplify/amplify-cli/commit/d1dc7acbbf27a567df6c250ae4428943ca2f66d0)), closes [#2741](https://github.com/aws-amplify/amplify-cli/issues/2741) -- [#2703](https://github.com/aws-amplify/amplify-cli/issues/2703) - policy size calculation ([#3016](https://github.com/aws-amplify/amplify-cli/issues/3016)) ([dcee2aa](https://github.com/aws-amplify/amplify-cli/commit/dcee2aab12b40562d1c6f0d260b830ca4ab0bedd)) -- [#2727](https://github.com/aws-amplify/amplify-cli/issues/2727) ([#2754](https://github.com/aws-amplify/amplify-cli/issues/2754)) ([44a7b54](https://github.com/aws-amplify/amplify-cli/commit/44a7b549f84ff8d752fd0dc87d6d689a609a579d)) -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) -- use managedpolicies and slice them ([#2883](https://github.com/aws-amplify/amplify-cli/issues/2883)) ([fa0f2ed](https://github.com/aws-amplify/amplify-cli/commit/fa0f2ed2fc725d964cbaf11a892b3850aaf42d84)), closes [#2084](https://github.com/aws-amplify/amplify-cli/issues/2084) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.11.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@5.18.0...graphql-auth-transformer@6.11.0) (2019-12-31) - -### Bug Fixes - -- **graphql-auth-transformer:** include ApiKeyConfig in additional providers ([#2744](https://github.com/aws-amplify/amplify-cli/issues/2744)) ([d1dc7ac](https://github.com/aws-amplify/amplify-cli/commit/d1dc7acbbf27a567df6c250ae4428943ca2f66d0)), closes [#2741](https://github.com/aws-amplify/amplify-cli/issues/2741) -- [#2703](https://github.com/aws-amplify/amplify-cli/issues/2703) - policy size calculation ([#3016](https://github.com/aws-amplify/amplify-cli/issues/3016)) ([dcee2aa](https://github.com/aws-amplify/amplify-cli/commit/dcee2aab12b40562d1c6f0d260b830ca4ab0bedd)) -- [#2727](https://github.com/aws-amplify/amplify-cli/issues/2727) ([#2754](https://github.com/aws-amplify/amplify-cli/issues/2754)) ([44a7b54](https://github.com/aws-amplify/amplify-cli/commit/44a7b549f84ff8d752fd0dc87d6d689a609a579d)) -- use managedpolicies and slice them ([#2883](https://github.com/aws-amplify/amplify-cli/issues/2883)) ([fa0f2ed](https://github.com/aws-amplify/amplify-cli/commit/fa0f2ed2fc725d964cbaf11a892b3850aaf42d84)), closes [#2084](https://github.com/aws-amplify/amplify-cli/issues/2084) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.10.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@5.18.0...graphql-auth-transformer@6.10.0) (2019-12-28) - -### Bug Fixes - -- **graphql-auth-transformer:** include ApiKeyConfig in additional providers ([#2744](https://github.com/aws-amplify/amplify-cli/issues/2744)) ([d1dc7ac](https://github.com/aws-amplify/amplify-cli/commit/d1dc7acbbf27a567df6c250ae4428943ca2f66d0)), closes [#2741](https://github.com/aws-amplify/amplify-cli/issues/2741) -- [#2703](https://github.com/aws-amplify/amplify-cli/issues/2703) - policy size calculation ([#3016](https://github.com/aws-amplify/amplify-cli/issues/3016)) ([dcee2aa](https://github.com/aws-amplify/amplify-cli/commit/dcee2aab12b40562d1c6f0d260b830ca4ab0bedd)) -- [#2727](https://github.com/aws-amplify/amplify-cli/issues/2727) ([#2754](https://github.com/aws-amplify/amplify-cli/issues/2754)) ([44a7b54](https://github.com/aws-amplify/amplify-cli/commit/44a7b549f84ff8d752fd0dc87d6d689a609a579d)) -- use managedpolicies and slice them ([#2883](https://github.com/aws-amplify/amplify-cli/issues/2883)) ([fa0f2ed](https://github.com/aws-amplify/amplify-cli/commit/fa0f2ed2fc725d964cbaf11a892b3850aaf42d84)), closes [#2084](https://github.com/aws-amplify/amplify-cli/issues/2084) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.9.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@5.18.0...graphql-auth-transformer@6.9.0) (2019-12-26) - -### Bug Fixes - -- **graphql-auth-transformer:** include ApiKeyConfig in additional providers ([#2744](https://github.com/aws-amplify/amplify-cli/issues/2744)) ([d1dc7ac](https://github.com/aws-amplify/amplify-cli/commit/d1dc7acbbf27a567df6c250ae4428943ca2f66d0)), closes [#2741](https://github.com/aws-amplify/amplify-cli/issues/2741) -- [#2703](https://github.com/aws-amplify/amplify-cli/issues/2703) - policy size calculation ([#3016](https://github.com/aws-amplify/amplify-cli/issues/3016)) ([dcee2aa](https://github.com/aws-amplify/amplify-cli/commit/dcee2aab12b40562d1c6f0d260b830ca4ab0bedd)) -- [#2727](https://github.com/aws-amplify/amplify-cli/issues/2727) ([#2754](https://github.com/aws-amplify/amplify-cli/issues/2754)) ([44a7b54](https://github.com/aws-amplify/amplify-cli/commit/44a7b549f84ff8d752fd0dc87d6d689a609a579d)) -- use managedpolicies and slice them ([#2883](https://github.com/aws-amplify/amplify-cli/issues/2883)) ([fa0f2ed](https://github.com/aws-amplify/amplify-cli/commit/fa0f2ed2fc725d964cbaf11a892b3850aaf42d84)), closes [#2084](https://github.com/aws-amplify/amplify-cli/issues/2084) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.8.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@5.18.0...graphql-auth-transformer@6.8.0) (2019-12-25) - -### Bug Fixes - -- **graphql-auth-transformer:** include ApiKeyConfig in additional providers ([#2744](https://github.com/aws-amplify/amplify-cli/issues/2744)) ([d1dc7ac](https://github.com/aws-amplify/amplify-cli/commit/d1dc7acbbf27a567df6c250ae4428943ca2f66d0)), closes [#2741](https://github.com/aws-amplify/amplify-cli/issues/2741) -- [#2703](https://github.com/aws-amplify/amplify-cli/issues/2703) - policy size calculation ([#3016](https://github.com/aws-amplify/amplify-cli/issues/3016)) ([dcee2aa](https://github.com/aws-amplify/amplify-cli/commit/dcee2aab12b40562d1c6f0d260b830ca4ab0bedd)) -- [#2727](https://github.com/aws-amplify/amplify-cli/issues/2727) ([#2754](https://github.com/aws-amplify/amplify-cli/issues/2754)) ([44a7b54](https://github.com/aws-amplify/amplify-cli/commit/44a7b549f84ff8d752fd0dc87d6d689a609a579d)) -- use managedpolicies and slice them ([#2883](https://github.com/aws-amplify/amplify-cli/issues/2883)) ([fa0f2ed](https://github.com/aws-amplify/amplify-cli/commit/fa0f2ed2fc725d964cbaf11a892b3850aaf42d84)), closes [#2084](https://github.com/aws-amplify/amplify-cli/issues/2084) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.7.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@5.18.0...graphql-auth-transformer@6.7.0) (2019-12-20) - -### Bug Fixes - -- **graphql-auth-transformer:** include ApiKeyConfig in additional providers ([#2744](https://github.com/aws-amplify/amplify-cli/issues/2744)) ([d1dc7ac](https://github.com/aws-amplify/amplify-cli/commit/d1dc7acbbf27a567df6c250ae4428943ca2f66d0)), closes [#2741](https://github.com/aws-amplify/amplify-cli/issues/2741) -- [#2703](https://github.com/aws-amplify/amplify-cli/issues/2703) - policy size calculation ([#3016](https://github.com/aws-amplify/amplify-cli/issues/3016)) ([dcee2aa](https://github.com/aws-amplify/amplify-cli/commit/dcee2aab12b40562d1c6f0d260b830ca4ab0bedd)) -- [#2727](https://github.com/aws-amplify/amplify-cli/issues/2727) ([#2754](https://github.com/aws-amplify/amplify-cli/issues/2754)) ([44a7b54](https://github.com/aws-amplify/amplify-cli/commit/44a7b549f84ff8d752fd0dc87d6d689a609a579d)) -- use managedpolicies and slice them ([#2883](https://github.com/aws-amplify/amplify-cli/issues/2883)) ([fa0f2ed](https://github.com/aws-amplify/amplify-cli/commit/fa0f2ed2fc725d964cbaf11a892b3850aaf42d84)), closes [#2084](https://github.com/aws-amplify/amplify-cli/issues/2084) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.6.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@5.18.0...graphql-auth-transformer@6.6.0) (2019-12-10) - -### Bug Fixes - -- **graphql-auth-transformer:** include ApiKeyConfig in additional providers ([#2744](https://github.com/aws-amplify/amplify-cli/issues/2744)) ([d1dc7ac](https://github.com/aws-amplify/amplify-cli/commit/d1dc7acbbf27a567df6c250ae4428943ca2f66d0)), closes [#2741](https://github.com/aws-amplify/amplify-cli/issues/2741) -- [#2727](https://github.com/aws-amplify/amplify-cli/issues/2727) ([#2754](https://github.com/aws-amplify/amplify-cli/issues/2754)) ([44a7b54](https://github.com/aws-amplify/amplify-cli/commit/44a7b549f84ff8d752fd0dc87d6d689a609a579d)) -- use managedpolicies and slice them ([#2883](https://github.com/aws-amplify/amplify-cli/issues/2883)) ([fa0f2ed](https://github.com/aws-amplify/amplify-cli/commit/fa0f2ed2fc725d964cbaf11a892b3850aaf42d84)), closes [#2084](https://github.com/aws-amplify/amplify-cli/issues/2084) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.4.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@5.18.0...graphql-auth-transformer@6.4.0) (2019-12-03) - -### Bug Fixes - -- **graphql-auth-transformer:** include ApiKeyConfig in additional providers ([#2744](https://github.com/aws-amplify/amplify-cli/issues/2744)) ([d1dc7ac](https://github.com/aws-amplify/amplify-cli/commit/d1dc7acbbf27a567df6c250ae4428943ca2f66d0)), closes [#2741](https://github.com/aws-amplify/amplify-cli/issues/2741) -- [#2727](https://github.com/aws-amplify/amplify-cli/issues/2727) ([#2754](https://github.com/aws-amplify/amplify-cli/issues/2754)) ([44a7b54](https://github.com/aws-amplify/amplify-cli/commit/44a7b549f84ff8d752fd0dc87d6d689a609a579d)) -- use managedpolicies and slice them ([#2883](https://github.com/aws-amplify/amplify-cli/issues/2883)) ([fa0f2ed](https://github.com/aws-amplify/amplify-cli/commit/fa0f2ed2fc725d964cbaf11a892b3850aaf42d84)), closes [#2084](https://github.com/aws-amplify/amplify-cli/issues/2084) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.3.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@5.18.0...graphql-auth-transformer@6.3.0) (2019-12-01) - -### Bug Fixes - -- **graphql-auth-transformer:** include ApiKeyConfig in additional providers ([#2744](https://github.com/aws-amplify/amplify-cli/issues/2744)) ([d1dc7ac](https://github.com/aws-amplify/amplify-cli/commit/d1dc7acbbf27a567df6c250ae4428943ca2f66d0)), closes [#2741](https://github.com/aws-amplify/amplify-cli/issues/2741) -- [#2727](https://github.com/aws-amplify/amplify-cli/issues/2727) ([#2754](https://github.com/aws-amplify/amplify-cli/issues/2754)) ([44a7b54](https://github.com/aws-amplify/amplify-cli/commit/44a7b549f84ff8d752fd0dc87d6d689a609a579d)) -- use managedpolicies and slice them ([#2883](https://github.com/aws-amplify/amplify-cli/issues/2883)) ([fa0f2ed](https://github.com/aws-amplify/amplify-cli/commit/fa0f2ed2fc725d964cbaf11a892b3850aaf42d84)), closes [#2084](https://github.com/aws-amplify/amplify-cli/issues/2084) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.2.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@5.18.0...graphql-auth-transformer@6.2.0) (2019-11-27) - -### Bug Fixes - -- **graphql-auth-transformer:** include ApiKeyConfig in additional providers ([#2744](https://github.com/aws-amplify/amplify-cli/issues/2744)) ([d1dc7ac](https://github.com/aws-amplify/amplify-cli/commit/d1dc7acbbf27a567df6c250ae4428943ca2f66d0)), closes [#2741](https://github.com/aws-amplify/amplify-cli/issues/2741) -- [#2727](https://github.com/aws-amplify/amplify-cli/issues/2727) ([#2754](https://github.com/aws-amplify/amplify-cli/issues/2754)) ([44a7b54](https://github.com/aws-amplify/amplify-cli/commit/44a7b549f84ff8d752fd0dc87d6d689a609a579d)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.1.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@5.18.0...graphql-auth-transformer@6.1.0) (2019-11-27) - -### Bug Fixes - -- **graphql-auth-transformer:** include ApiKeyConfig in additional providers ([#2744](https://github.com/aws-amplify/amplify-cli/issues/2744)) ([d1dc7ac](https://github.com/aws-amplify/amplify-cli/commit/d1dc7acbbf27a567df6c250ae4428943ca2f66d0)), closes [#2741](https://github.com/aws-amplify/amplify-cli/issues/2741) -- [#2727](https://github.com/aws-amplify/amplify-cli/issues/2727) ([#2754](https://github.com/aws-amplify/amplify-cli/issues/2754)) ([44a7b54](https://github.com/aws-amplify/amplify-cli/commit/44a7b549f84ff8d752fd0dc87d6d689a609a579d)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [5.0.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.7.5...graphql-auth-transformer@5.0.0) (2019-08-30) - -### Bug Fixes - -- [#2013](https://github.com/aws-amplify/amplify-cli/issues/2013) - Dynamic group auth when groups field is null ([#2097](https://github.com/aws-amplify/amplify-cli/issues/2097)) ([4ad3d5c](https://github.com/aws-amplify/amplify-cli/commit/4ad3d5c)) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -* Adding Auth on Subscriptions (#2068) ([81c630d](https://github.com/aws-amplify/amplify-cli/commit/81c630d)), closes [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) - -### BREAKING CHANGES - -- If an owner is used in the auth directive it will either be a requirement if it's - the only rule or an optional input if used with other rules -- If an owner is included in the auth directive it will either be a requirement if - it's the only rule or an optional input if used with other rules -- the subscription operations will require an argument if owner is the only auth rule -- Subscriptions will require an argument if an owner is only rule set - If owner & - group rules are owner will be an optional arg - -# [4.0.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.7.5...graphql-auth-transformer@4.0.0) (2019-08-28) - -### Bug Fixes - -- [#2013](https://github.com/aws-amplify/amplify-cli/issues/2013) - Dynamic group auth when groups field is null ([#2097](https://github.com/aws-amplify/amplify-cli/issues/2097)) ([4ad3d5c](https://github.com/aws-amplify/amplify-cli/commit/4ad3d5c)) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -* Adding Auth on Subscriptions (#2068) ([81c630d](https://github.com/aws-amplify/amplify-cli/commit/81c630d)), closes [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) - -### BREAKING CHANGES - -- If an owner is used in the auth directive it will either be a requirement if it's - the only rule or an optional input if used with other rules -- If an owner is included in the auth directive it will either be a requirement if - it's the only rule or an optional input if used with other rules -- the subscription operations will require an argument if owner is the only auth rule -- Subscriptions will require an argument if an owner is only rule set - If owner & - group rules are owner will be an optional arg - -# [3.11.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.7.5...graphql-auth-transformer@3.11.0) (2019-08-13) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.10.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.7.5...graphql-auth-transformer@3.10.0) (2019-08-07) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.9.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.7.5...graphql-auth-transformer@3.9.0) (2019-08-02) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.8.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.7.5...graphql-auth-transformer@3.8.0) (2019-07-31) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -## [3.7.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.7.4...graphql-auth-transformer@3.7.5) (2019-07-24) - -**Note:** Version bump only for package graphql-auth-transformer - -## [3.7.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.7.2...graphql-auth-transformer@3.7.4) (2019-06-30) - -**Note:** Version bump only for package graphql-auth-transformer - -## [3.7.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.7.1...graphql-auth-transformer@3.7.2) (2019-06-26) - -**Note:** Version bump only for package graphql-auth-transformer - -## [3.7.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.7.0...graphql-auth-transformer@3.7.1) (2019-06-12) - -**Note:** Version bump only for package graphql-auth-transformer - -# [3.7.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.6.4...graphql-auth-transformer@3.7.0) (2019-05-29) - -### Features - -- feature/[@key](https://github.com/key) ([#1463](https://github.com/aws-amplify/amplify-cli/issues/1463)) ([00ed819](https://github.com/aws-amplify/amplify-cli/commit/00ed819)) - -## [3.6.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.6.3...graphql-auth-transformer@3.6.4) (2019-05-21) - -**Note:** Version bump only for package graphql-auth-transformer - -## [3.6.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.6.2...graphql-auth-transformer@3.6.3) (2019-05-17) - -**Note:** Version bump only for package graphql-auth-transformer - -## [3.6.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.6.0...graphql-auth-transformer@3.6.2) (2019-05-07) - -**Note:** Version bump only for package graphql-auth-transformer - -## [3.6.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.6.0...graphql-auth-transformer@3.6.1) (2019-05-06) - -**Note:** Version bump only for package graphql-auth-transformer - -# [3.6.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.5.1...graphql-auth-transformer@3.6.0) (2019-04-16) - -### Features - -- **field-level-auth:** Add field level auth support via the [@auth](https://github.com/auth) directive ([#1262](https://github.com/aws-amplify/amplify-cli/issues/1262)) ([3b1c600](https://github.com/aws-amplify/amplify-cli/commit/3b1c600)), closes [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) - -## [3.5.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.4.0...graphql-auth-transformer@3.5.1) (2019-04-09) - -**Note:** Version bump only for package graphql-auth-transformer - -# [3.4.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.0.9...graphql-auth-transformer@3.4.0) (2019-04-03) - -### Bug Fixes - -- **graphql-auth-transformer:** conditional group expression ([#1186](https://github.com/aws-amplify/amplify-cli/issues/1186)) ([83ef244](https://github.com/aws-amplify/amplify-cli/commit/83ef244)), closes [#360](https://github.com/aws-amplify/amplify-cli/issues/360) - -### Features - -- support for provisioning Cognito Hosted UI and support CRUD operations in Storage and API categories ([729b0de](https://github.com/aws-amplify/amplify-cli/commit/729b0de)) - -## [3.0.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.0.8...graphql-auth-transformer@3.0.9) (2019-03-22) - -**Note:** Version bump only for package graphql-auth-transformer - -## [3.0.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.0.7...graphql-auth-transformer@3.0.8) (2019-03-05) - -**Note:** Version bump only for package graphql-auth-transformer - -## [3.0.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.0.6...graphql-auth-transformer@3.0.7) (2019-02-20) - -**Note:** Version bump only for package graphql-auth-transformer - -## [3.0.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.0.5...graphql-auth-transformer@3.0.6) (2019-02-12) - -**Note:** Version bump only for package graphql-auth-transformer - -## [3.0.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.0.3-beta.0...graphql-auth-transformer@3.0.5) (2019-02-11) - -**Note:** Version bump only for package graphql-auth-transformer - -## [3.0.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.0.3-beta.0...graphql-auth-transformer@3.0.3) (2019-02-11) - -**Note:** Version bump only for package graphql-auth-transformer - -## [3.0.3-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@3.0.2...graphql-auth-transformer@3.0.3-beta.0) (2019-02-11) - -**Note:** Version bump only for package graphql-auth-transformer - - - -# [2.0.0-multienv.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.34-multienv.1...graphql-auth-transformer@2.0.0-multienv.2) (2018-12-31) - -### Bug Fixes - -- update grahql transformer package versions for multienv ([8b4b2bd](https://github.com/aws-amplify/amplify-cli/commit/8b4b2bd)) - - - -## [1.0.34-multienv.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.34-multienv.0...graphql-auth-transformer@1.0.34-multienv.1) (2018-12-19) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## [1.0.34-multienv.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.33...graphql-auth-transformer@1.0.34-multienv.0) (2018-11-16) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## [1.0.33](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.33-beta.0...graphql-auth-transformer@1.0.33) (2018-11-09) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## [1.0.33-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.12...graphql-auth-transformer@1.0.33-beta.0) (2018-11-09) - -### Bug Fixes - -- **graphql-auth-transformer:** Modifies the name of the user pool resource ([d613481](https://github.com/aws-amplify/amplify-cli/commit/d613481)) - - - -## [1.0.32](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.32-beta.0...graphql-auth-transformer@1.0.32) (2018-11-05) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## [1.0.32-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.12...graphql-auth-transformer@1.0.32-beta.0) (2018-11-05) - -### Bug Fixes - -- **graphql-auth-transformer:** Modifies the name of the user pool resource ([d613481](https://github.com/aws-amplify/amplify-cli/commit/d613481)) - - - -## [1.0.31](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.12...graphql-auth-transformer@1.0.31) (2018-11-02) - -### Bug Fixes - -- **graphql-auth-transformer:** Modifies the name of the user pool resource ([d613481](https://github.com/aws-amplify/amplify-cli/commit/d613481)) - - - -## [1.0.30](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.30-beta.0...graphql-auth-transformer@1.0.30) (2018-11-02) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## [1.0.30-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.12...graphql-auth-transformer@1.0.30-beta.0) (2018-11-02) - -### Bug Fixes - -- **graphql-auth-transformer:** Modifies the name of the user pool resource ([d613481](https://github.com/aws-amplify/amplify-cli/commit/d613481)) - - - -## [1.0.29](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.29-beta.0...graphql-auth-transformer@1.0.29) (2018-10-23) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## [1.0.29-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.12...graphql-auth-transformer@1.0.29-beta.0) (2018-10-23) - -### Bug Fixes - -- **graphql-auth-transformer:** Modifies the name of the user pool resource ([d613481](https://github.com/aws-amplify/amplify-cli/commit/d613481)) - - - -## [1.0.28](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.28-beta.0...graphql-auth-transformer@1.0.28) (2018-10-18) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## [1.0.28-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.12...graphql-auth-transformer@1.0.28-beta.0) (2018-10-12) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## [1.0.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.11...graphql-auth-transformer@1.0.12) (2018-08-23) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## [1.0.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.10...graphql-auth-transformer@1.0.11) (2018-08-23) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## [1.0.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.9...graphql-auth-transformer@1.0.10) (2018-08-23) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## [1.0.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.8...graphql-auth-transformer@1.0.9) (2018-08-23) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## [1.0.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.7...graphql-auth-transformer@1.0.8) (2018-08-23) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## [1.0.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.6...graphql-auth-transformer@1.0.7) (2018-08-23) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## [1.0.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.5...graphql-auth-transformer@1.0.6) (2018-08-23) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## [1.0.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-auth-transformer@1.0.4...graphql-auth-transformer@1.0.5) (2018-08-23) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## 1.0.4 (2018-08-23) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## 1.0.3 (2018-08-23) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## 1.0.2 (2018-08-23) - -**Note:** Version bump only for package graphql-auth-transformer - - - -## 1.0.1 (2018-08-23) - -**Note:** Version bump only for package graphql-auth-transformer diff --git a/packages/graphql-auth-transformer/package.json b/packages/graphql-auth-transformer/package.json deleted file mode 100644 index 033ef4924d..0000000000 --- a/packages/graphql-auth-transformer/package.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "name": "graphql-auth-transformer", - "version": "7.2.82", - "description": "Implements the @auth directive for the appsync model transform.", - "repository": { - "type": "git", - "url": "https://github.com/aws-amplify/amplify-category-api.git", - "directory": "packages/graphql-auth-transformer" - }, - "author": "Amazon Web Services", - "license": "Apache-2.0", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "keywords": [ - "graphql", - "appsync", - "aws" - ], - "scripts": { - "test": "jest", - "build": "tsc", - "clean": "rimraf ./lib", - "watch": "tsc -w", - "extract-api": "ts-node ../../scripts/extract-api.ts" - }, - "dependencies": { - "graphql": "^15.5.0", - "graphql-connection-transformer": "5.2.80", - "graphql-mapping-template": "4.20.16", - "graphql-transformer-common": "4.31.1", - "graphql-transformer-core": "8.2.13" - }, - "devDependencies": { - "cloudform-types": "^4.2.0", - "graphql-dynamodb-transformer": "7.2.80", - "graphql-elasticsearch-transformer": "5.2.81", - "graphql-function-transformer": "3.3.71", - "lodash": "^4.17.21", - "rimraf": "^3.0.0" - }, - "jest": { - "testURL": "http://localhost", - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, - "testRegex": "(src/__tests__/.*.test.ts)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], - "collectCoverage": true, - "coverageProvider": "v8", - "coverageThreshold": { - "global": { - "branches": 89, - "functions": 90, - "lines": 90 - } - }, - "coverageReporters": [ - "clover", - "text" - ], - "collectCoverageFrom": [ - "src/**/*.ts" - ], - "coveragePathIgnorePatterns": [ - "/__tests__/" - ] - } -} diff --git a/packages/graphql-auth-transformer/src/AuthRule.ts b/packages/graphql-auth-transformer/src/AuthRule.ts deleted file mode 100644 index 17563baa64..0000000000 --- a/packages/graphql-auth-transformer/src/AuthRule.ts +++ /dev/null @@ -1,20 +0,0 @@ -export type AuthStrategy = 'owner' | 'groups' | 'public' | 'private' | 'custom'; -export type AuthProvider = 'apiKey' | 'iam' | 'oidc' | 'userPools' | 'function'; -export type ModelQuery = 'get' | 'list'; -export type ModelMutation = 'create' | 'update' | 'delete'; -export type ModelOperation = 'create' | 'update' | 'delete' | 'read'; -export interface AuthRule { - allow: AuthStrategy; - provider?: AuthProvider; - ownerField?: string; - identityField?: string; - identityClaim?: string; - groupsField?: string; - groupClaim?: string; - groups?: string[]; - operations?: ModelOperation[]; - queries?: ModelQuery[]; - mutations?: ModelMutation[]; - // Used only for IAM provider to decide if an IAM policy needs to be generated. IAM auth with AdminUI does not need IAM policies - generateIAMPolicy?: boolean; -} diff --git a/packages/graphql-auth-transformer/src/ModelAuthTransformer.ts b/packages/graphql-auth-transformer/src/ModelAuthTransformer.ts deleted file mode 100644 index 2dd9b9087e..0000000000 --- a/packages/graphql-auth-transformer/src/ModelAuthTransformer.ts +++ /dev/null @@ -1,2438 +0,0 @@ -import { Transformer, TransformerContext, InvalidDirectiveError, getDirectiveArguments, getFieldArguments } from 'graphql-transformer-core'; -import { AuthDirectiveV1 } from '@aws-amplify/graphql-directives'; -import GraphQLAPI from 'cloudform-types/types/appSync/graphQlApi'; -import Resolver from 'cloudform-types/types/appSync/resolver'; -import { StringParameter } from 'cloudform-types'; -import { - ObjectTypeDefinitionNode, - DirectiveNode, - ArgumentNode, - Kind, - FieldDefinitionNode, - InterfaceTypeDefinitionNode, - valueFromASTUntyped, - NamedTypeNode, - InputObjectTypeDefinitionNode, - TypeDefinitionNode, - parse, -} from 'graphql'; -import { - ResourceConstants, - ResolverResourceIDs, - isListType, - getBaseType, - makeDirective, - makeNamedType, - makeInputValueDefinition, - blankObjectExtension, - extensionWithDirectives, - extendFieldWithDirectives, - makeNonNullType, - makeField, - ModelResourceIDs, -} from 'graphql-transformer-common'; -import { Expression, print, raw, iff, forEach, set, ref, list, compoundExpression, newline, comment, not } from 'graphql-mapping-template'; -import { AuthRule, ModelQuery, ModelMutation, ModelOperation, AuthProvider } from './AuthRule'; -import { ResourceFactory } from './resources'; -import { ModelDirectiveConfiguration, ModelDirectiveOperationType, ModelSubscriptionLevel } from './ModelDirectiveConfiguration'; - -import { OWNER_AUTH_STRATEGY, GROUPS_AUTH_STRATEGY, DEFAULT_OWNER_FIELD, AUTH_NON_MODEL_TYPES } from './constants'; - -/** - * Implements the ModelAuthTransformer - * - * Owner Auth Usage: - * - * type Post @auth(allow: owner) { - * id: ID! - * title: String - * createdAt: String - * updatedAt: String - * } - * - * Impact: - * - * getPost - In the response mapping template we check the "owner" field === $ctx.identity.username. - * listPost - In the response mapping template we return only items where "owner" === $ctx.identity.username - * createPost - We automatically insert an "owner" field to attribute values where "owner" === $ctx.identity.username. - * updatePost - Expose "owner" field in input/output and would set conditional update expression to look for owner. - * deletePost - Conditional expression checking that the owner === $ctx.identity.username - * - * Note: The name of the "owner" field may be configured via "ownerField" parameter within the @auth directive. - * - * type Post @auth(allow: groups, groups: ["Admin", "Dev"]) { - * id: ID! - * title: String - * createdAt: String - * updatedAt: String - * } - * - * Impact: - * - * getPost - Update req template to look for the groups in the identity. - * listPost - Update req template to look for the groups in the identity. - * createPost - Update req template to look for the groups in the identity. - * updatePost - Update req template to look for the groups in the identity. - * deletePost - Update req template to look for the groups in the identity. - * - * TODO: Document support for dynamic group authorization against - * attributes of the records using conditional expressions. This will likely - * be via a new argument such as "groupsField". - */ -export type AppSyncAuthMode = 'API_KEY' | 'AMAZON_COGNITO_USER_POOLS' | 'AWS_IAM' | 'OPENID_CONNECT' | 'AWS_LAMBDA'; -export type AppSyncAuthConfiguration = { - defaultAuthentication: AppSyncAuthConfigurationEntry; - additionalAuthenticationProviders: Array; -}; -export type AppSyncAuthConfigurationEntry = { - authenticationType: AppSyncAuthMode; - apiKeyConfig?: ApiKeyConfig; - userPoolConfig?: UserPoolConfig; - openIDConnectConfig?: OpenIDConnectConfig; - lambdaAuthorizerConfig?: LambdaAuthorizerConfig; -}; -export type ApiKeyConfig = { - description?: string; - apiKeyExpirationDays: number; - apiKeyExpirationDate?: Date; -}; -export type UserPoolConfig = { - userPoolId: string; -}; -export type OpenIDConnectConfig = { - name: string; - issuerUrl: string; - clientId?: string; - iatTTL?: number; - authTTL?: number; -}; -export type LambdaAuthorizerConfig = { - lambdaFunction: string; - ttlSeconds?: number; -}; - -const validateAuthModes = (authConfig: AppSyncAuthConfiguration) => { - let additionalAuthModes = []; - - if (authConfig.additionalAuthenticationProviders) { - additionalAuthModes = authConfig.additionalAuthenticationProviders.map((p) => p.authenticationType).filter((t) => !!t); - } - - const authModes: AppSyncAuthMode[] = [...additionalAuthModes, authConfig.defaultAuthentication.authenticationType]; - - for (let i = 0; i < authModes.length; i++) { - const mode = authModes[i]; - - if ( - mode !== 'API_KEY' && - mode !== 'AMAZON_COGNITO_USER_POOLS' && - mode !== 'AWS_IAM' && - mode !== 'OPENID_CONNECT' && - mode !== 'AWS_LAMBDA' - ) { - throw new Error(`Invalid auth mode ${mode}`); - } - } -}; - -export type ModelAuthTransformerConfig = { - authConfig?: AppSyncAuthConfiguration; - addAwsIamAuthInOutputSchema?: boolean; -}; - -export type ConfiguredAuthProviders = { - default: AuthProvider; - onlyDefaultAuthProviderConfigured: boolean; - hasApiKey: boolean; - hasUserPools: boolean; - hasOIDC: boolean; - hasIAM: boolean; -}; - -export class ModelAuthTransformer extends Transformer { - resources: ResourceFactory; - - config: ModelAuthTransformerConfig; - - configuredAuthProviders: ConfiguredAuthProviders; - - generateIAMPolicyforUnauthRole: boolean; - - generateIAMPolicyforAuthRole: boolean; - - authPolicyResources: Set; - - unauthPolicyResources: Set; - - constructor(config?: ModelAuthTransformerConfig) { - super('ModelAuthTransformer', parse(AuthDirectiveV1.definition)); - - if (config && config.authConfig) { - this.config = config; - if (!this.config.authConfig.additionalAuthenticationProviders) { - this.config.authConfig.additionalAuthenticationProviders = []; - } - } else { - this.config = { authConfig: { defaultAuthentication: { authenticationType: 'API_KEY' }, additionalAuthenticationProviders: [] } }; - } - validateAuthModes(this.config.authConfig); - this.resources = new ResourceFactory(); - this.configuredAuthProviders = this.getConfiguredAuthProviders(); - this.generateIAMPolicyforUnauthRole = false; - this.generateIAMPolicyforAuthRole = false; - this.authPolicyResources = new Set(); - this.unauthPolicyResources = new Set(); - } - - /** - * Updates the GraphQL API record with configured authentication providers - */ - private updateAPIAuthentication = (ctx: TransformerContext): void => { - const apiRecord = ctx.getResource(ResourceConstants.RESOURCES.GraphQLAPILogicalID) as GraphQLAPI; - const updated = this.resources.updateGraphQLAPIWithAuth(apiRecord, this.config.authConfig); - ctx.setResource(ResourceConstants.RESOURCES.GraphQLAPILogicalID, updated); - - // Check if we need to create an API key resource or not. - }; - - public before = (ctx: TransformerContext): void => { - const template = this.resources.initTemplate(this.getApiKeyConfig()); - ctx.mergeResources(template.Resources); - ctx.mergeParameters(template.Parameters); - ctx.mergeOutputs(template.Outputs); - ctx.mergeConditions(template.Conditions); - this.updateAPIAuthentication(ctx); - if (!ctx.metadata.has(AUTH_NON_MODEL_TYPES)) { - ctx.metadata.set(AUTH_NON_MODEL_TYPES, new Map>()); - } - }; - - public after = (ctx: TransformerContext): void => { - if (this.generateIAMPolicyforAuthRole === true) { - // Sanity check to make sure we're not generating invalid policies, where no resources are defined. - if (this.authPolicyResources.size === 0) { - // When AdminUI is enabled, IAM auth is added but it does not need any policies to be generated - if (!this.isAdminUIEnabled()) { - throw new Error('AuthRole policies should be generated, but no resources were added'); - } - } else { - ctx.mergeParameters({ - [ResourceConstants.PARAMETERS.AuthRoleName]: new StringParameter({ - Description: 'Reference to the name of the Auth Role created for the project.', - }), - }); - - const authPolicies = this.resources.makeIAMPolicyForRole(true, this.authPolicyResources); - - for (let i = 0; i < authPolicies.length; i++) { - const paddedIndex = `${i + 1}`.padStart(2, '0'); - const resourceName = `${ResourceConstants.RESOURCES.AuthRolePolicy}${paddedIndex}`; - ctx.mergeResources({ - [resourceName]: authPolicies[i], - }); - } - } - } - - if (this.generateIAMPolicyforUnauthRole === true) { - // Sanity check to make sure we're not generating invalid policies, where no resources are defined. - if (this.unauthPolicyResources.size === 0) { - throw new Error('UnauthRole policies should be generated, but no resources were added'); - } - - ctx.mergeParameters({ - [ResourceConstants.PARAMETERS.UnauthRoleName]: new StringParameter({ - Description: 'Reference to the name of the Unauth Role created for the project.', - }), - }); - - const unauthPolicies = this.resources.makeIAMPolicyForRole(false, this.unauthPolicyResources); - - for (let i = 0; i < unauthPolicies.length; i++) { - const paddedIndex = `${i + 1}`.padStart(2, '0'); - const resourceName = `${ResourceConstants.RESOURCES.UnauthRolePolicy}${paddedIndex}`; - ctx.mergeResources({ - [resourceName]: unauthPolicies[i], - }); - } - } - }; - - private getApiKeyConfig(): ApiKeyConfig { - let authProviders = []; - - if (this.config.authConfig.additionalAuthenticationProviders) { - authProviders = authProviders.concat(this.config.authConfig.additionalAuthenticationProviders.filter((p) => !!p.authenticationType)); - } - - authProviders.push(this.config.authConfig.defaultAuthentication); - - const apiKeyAuthProvider = authProviders.find((p) => p.authenticationType === 'API_KEY'); - - // Return the found instance or a default instance with 7 days of API key expiration - return apiKeyAuthProvider ? apiKeyAuthProvider.apiKeyConfig : { apiKeyExpirationDays: 7 }; - } - - /** - * Implement the transform for an object type. Depending on which operations are to be protected - */ - public object = (def: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext): void => { - const modelDirective = def.directives.find((dir) => dir.name.value === 'model'); - if (!modelDirective) { - throw new InvalidDirectiveError('Types annotated with @auth must also be annotated with @model.'); - } - - // check if searchable is enabled on the type - const searchableDirective = def.directives.find((dir) => dir.name.value === 'searchable'); - - // Get and validate the auth rules. - const rules = this.extendAuthRulesForAdminUI(this.getAuthRulesFromDirective(directive)); - - // Assign default providers to rules where no provider was explicitly defined - this.ensureDefaultAuthProviderAssigned(rules); - this.validateRules(rules); - - // add owner fields to type that may not been only present in auth rules. - this.addOwnerFieldsToObject(ctx, def.name.value, rules); - // Check the rules if we've to generate IAM policies for Unauth role or not - this.setAuthPolicyFlag(rules); - this.setUnauthPolicyFlag(rules); - - // Check if the object type has fields of type without the @model directive. - // We've to make sure that appropriate @aws_* directive will be added and a policy entry for the - // type will be emitted as well in case of IAM. - this.propagateAuthDirectivesToNestedTypes(def, rules, ctx); - - // Retrieve the configuration options for the related @model directive - const modelConfiguration = new ModelDirectiveConfiguration(modelDirective, def, ctx.featureFlags.getBoolean('improvePluralization')); - - // Get the directives we need to add to the GraphQL nodes - const directives = this.getDirectivesForRules(rules, rules.length === 0 ? this.shouldAddDefaultAuthDirective() : false); - - // Add the directives to the Type node itself - if (directives.length > 0) { - this.extendTypeWithDirectives(ctx, def.name.value, directives); - } - - this.addTypeToResourceReferences(def.name.value, rules); - - const { operationRules, queryRules } = this.splitRules(rules); - - // For each operation evaluate the rules and apply the changes to the relevant resolver. - this.protectCreateMutation( - ctx, - ResolverResourceIDs.DynamoDBCreateResolverResourceID(def.name.value), - operationRules.create, - def, - modelConfiguration, - ); - this.protectUpdateMutation( - ctx, - ResolverResourceIDs.DynamoDBUpdateResolverResourceID(def.name.value), - operationRules.update, - def, - modelConfiguration, - ); - this.protectDeleteMutation( - ctx, - ResolverResourceIDs.DynamoDBDeleteResolverResourceID(def.name.value), - operationRules.delete, - def, - modelConfiguration, - ); - this.protectGetQuery( - ctx, - ResolverResourceIDs.DynamoDBGetResolverResourceID(def.name.value), - queryRules.get, - def, - modelConfiguration, - true, - ); - this.protectListQuery( - ctx, - ResolverResourceIDs.DynamoDBListResolverResourceID(def.name.value), - queryRules.list, - def, - modelConfiguration, - undefined, - true, - ); - this.protectConnections(ctx, def, operationRules.read, modelConfiguration); - this.protectQueries(ctx, def, operationRules.read, modelConfiguration); - - // protect search query if @searchable is enabled - if (searchableDirective) { - this.protectSearchQuery(ctx, def, ResolverResourceIDs.ElasticsearchSearchResolverResourceID(def.name.value), operationRules.read); - } - - // protect sync query if model is sync enabled - if (this.isSyncEnabled(ctx, def.name.value)) { - this.protectSyncQuery(ctx, def, ResolverResourceIDs.SyncResolverResourceID(def.name.value), operationRules.read); - } - - // Check if subscriptions is enabled - if (modelConfiguration.getName('level') !== 'off') { - this.protectOnCreateSubscription(ctx, operationRules.read, def, modelConfiguration); - this.protectOnUpdateSubscription(ctx, operationRules.read, def, modelConfiguration); - this.protectOnDeleteSubscription(ctx, operationRules.read, def, modelConfiguration); - } - - // Update ModelXConditionInput type - this.updateMutationConditionInput(ctx, def, rules); - }; - - public field = ( - parent: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, - definition: FieldDefinitionNode, - directive: DirectiveNode, - ctx: TransformerContext, - ) => { - if (parent.kind === Kind.INTERFACE_TYPE_DEFINITION) { - throw new InvalidDirectiveError( - `The @auth directive cannot be placed on an interface's field. See ${parent.name.value}${definition.name.value}`, - ); - } - const modelDirective = parent.directives.find((dir) => dir.name.value === 'model'); - const isParentTypeBuiltinType = - parent.name.value === ctx.getQueryTypeName() || - parent.name.value === ctx.getMutationTypeName() || - parent.name.value === ctx.getSubscriptionTypeName(); - - if (isParentTypeBuiltinType) { - console.warn( - `Be careful when using @auth directives on a field in a root type. @auth directives on field definitions use the source \ -object to perform authorization logic and the source will be an empty object for fields on root types. \ -Static group authorization should perform as expected.`, - ); - } - - // Get and validate the auth rules. - const rules = this.getAuthRulesFromDirective(directive); - if (!isParentTypeBuiltinType) { - // add owner fields to the type - this.addOwnerFieldsToObject(ctx, parent.name.value, rules); - } - // Assign default providers to rules where no provider was explicitly defined - this.ensureDefaultAuthProviderAssigned(rules); - this.validateFieldRules(rules, isParentTypeBuiltinType, modelDirective !== undefined); - // Check the rules if we've to generate IAM policies for Unauth role or not - this.setAuthPolicyFlag(rules); - this.setUnauthPolicyFlag(rules); - - this.addFieldToResourceReferences(parent.name.value, definition.name.value, rules); - - // Add the directives to the parent type as well, we've to add the default provider if - // - The type has no @auth directives, so there are NO restrictions on the type - // or - // - The type has @auth rules for the default provider - const includeDefault = this.isTypeNeedsDefaultProviderAccess(parent); - // Should not propagate auth directives onto Query/Mutation/Subscription types - const typeDirectives = isParentTypeBuiltinType ? [] : this.getDirectivesForRules(rules, includeDefault); - - if (typeDirectives.length > 0) { - this.extendTypeWithDirectives(ctx, parent.name.value, typeDirectives); - } - - const isOpRule = (op: ModelOperation) => (rule: AuthRule) => { - if (rule.operations) { - const matchesOp = rule.operations.find((o) => o === op); - return Boolean(matchesOp); - } - if (rule.operations === null) { - return false; - } - return true; - }; - - // add rules if per field @auth is used with @model - if (modelDirective) { - const isReadRule = isOpRule('read'); - const isCreateRule = isOpRule('create'); - const isUpdateRule = isOpRule('update'); - const isDeleteRule = isOpRule('delete'); - - // Retrieve the configuration options for the related @model directive - const modelConfiguration = new ModelDirectiveConfiguration( - modelDirective, - parent, - ctx.featureFlags.getBoolean('improvePluralization'), - ); - // The field handler adds the read rule on the object - const readRules = rules.filter((rule: AuthRule) => isReadRule(rule)); - this.protectReadForField(ctx, parent, definition, readRules, modelConfiguration); - - // Protect mutations when objects including this field are trying to be created. - const createRules = rules.filter((rule: AuthRule) => isCreateRule(rule)); - this.protectCreateForField(ctx, parent, definition, createRules, modelConfiguration); - - // Protect update mutations when objects inluding this field are trying to be updated. - const updateRules = rules.filter((rule: AuthRule) => isUpdateRule(rule)); - this.protectUpdateForField(ctx, parent, definition, updateRules, modelConfiguration); - - // Delete operations are only protected by @auth directives on objects. - const deleteRules = rules.filter((rule: AuthRule) => isDeleteRule(rule)); - this.protectDeleteForField(ctx, parent, definition, deleteRules, modelConfiguration); - } else { - const directives = this.getDirectivesForRules(rules, false); - - if (directives.length > 0) { - this.addDirectivesToField(ctx, parent.name.value, definition.name.value, directives); - } - - // if @auth is used without @model only generate static group rules - const staticGroupRules = rules.filter((rule: AuthRule) => rule.groups); - this.protectField(ctx, parent, definition, staticGroupRules); - } - }; - - private propagateAuthDirectivesToNestedTypes(type: ObjectTypeDefinitionNode, rules: AuthRule[], ctx: TransformerContext) { - const seenNonModelTypes: Map> = ctx.metadata.get(AUTH_NON_MODEL_TYPES); - - const getDirectivesToAdd = (nonModelName: string): { current: DirectiveNode[]; old?: Set } => { - const directives = this.getDirectivesForRules(rules, true); - if (seenNonModelTypes.has(nonModelName)) { - const nonModelDirectives: Set = seenNonModelTypes.get(nonModelName); - return { current: directives.filter((directive) => !nonModelDirectives.has(directive.name.value)), old: nonModelDirectives }; - } - return { current: directives }; - }; - - const nonModelTypePredicate = (fieldType: TypeDefinitionNode): TypeDefinitionNode | undefined => { - if (fieldType) { - if (fieldType.kind !== 'ObjectTypeDefinition') { - return undefined; - } - const typeModel = fieldType.directives.find((dir) => dir.name.value === 'model'); - return typeModel !== undefined ? undefined : fieldType; - } - return fieldType; - }; - const nonModelFieldTypes = type.fields.map((f) => ctx.getType(getBaseType(f.type)) as TypeDefinitionNode).filter(nonModelTypePredicate); - for (const nonModelFieldType of nonModelFieldTypes) { - const directives = getDirectivesToAdd(nonModelFieldType.name.value); - if (directives.current.length > 0) { - // merge back the newly added auth directives with what already exists in the set - const totalDirectives = new Set([ - ...directives.current.map((dir) => dir.name.value), - ...(directives.old ? directives.old : []), - ]); - seenNonModelTypes.set(nonModelFieldType.name.value, totalDirectives); - this.extendTypeWithDirectives(ctx, nonModelFieldType.name.value, directives.current); - const hasIAM = - directives.current.filter((directive) => directive.name.value === 'aws_iam') || this.configuredAuthProviders.default === 'iam'; - if (hasIAM) { - this.unauthPolicyResources.add(`${nonModelFieldType.name.value}/null`); - this.authPolicyResources.add(`${nonModelFieldType.name.value}/null`); - } - this.propagateAuthDirectivesToNestedTypes(nonModelFieldType, rules, ctx); - } - } - } - - private protectField( - ctx: TransformerContext, - parent: ObjectTypeDefinitionNode, - field: FieldDefinitionNode, - staticGroupRules: AuthRule[], - ) { - const typeName = parent.name.value; - const fieldName = field.name.value; - const resolverResourceId = ResolverResourceIDs.ResolverResourceID(typeName, fieldName); - let fieldResolverResource = ctx.getResource(resolverResourceId); - - const templateParts = []; - - if (staticGroupRules && staticGroupRules.length) { - // add logic here to only use static group rules - const staticGroupAuthorizationRules = this.getStaticGroupRules(staticGroupRules); - const staticGroupAuthorizationExpression = this.resources.staticGroupAuthorizationExpression(staticGroupAuthorizationRules, field); - const throwIfUnauthorizedExpression = this.resources.throwIfStaticGroupUnauthorized(field); - - // If other authModes (aside from userPools) are included then add the authMode check block - // to the start of the resolver - const authModesToCheck = new Set(); - const expressions: Array = new Array(); - if (staticGroupAuthorizationRules.find((r) => r.provider === 'userPools')) { - authModesToCheck.add('userPools'); - } - if (staticGroupAuthorizationRules.find((r) => r.provider === 'oidc')) { - authModesToCheck.add('oidc'); - } - if (authModesToCheck.size > 0) { - const isUserPoolTheDefault = this.configuredAuthProviders.default === 'userPools'; - expressions.push(this.resources.getAuthModeDeterminationExpression(authModesToCheck, isUserPoolTheDefault)); - } - const authCheckExpressions = [staticGroupAuthorizationExpression, newline(), throwIfUnauthorizedExpression]; - // Create the authMode if block and add it to the resolver - expressions.push(this.resources.getAuthModeCheckWrappedExpression(authModesToCheck, compoundExpression(authCheckExpressions))); - - templateParts.push(print(compoundExpression(expressions))); - } - - // if the field resolver does not exist create it - if (!fieldResolverResource) { - fieldResolverResource = this.resources.blankResolver(typeName, fieldName); - ctx.setResource(resolverResourceId, fieldResolverResource); - // add none ds if that does not exist - const noneDS = ctx.getResource(ResourceConstants.RESOURCES.NoneDataSource); - if (!noneDS) { - ctx.setResource(ResourceConstants.RESOURCES.NoneDataSource, this.resources.noneDataSource()); - } - } - templateParts.push(fieldResolverResource.Properties.RequestMappingTemplate); - fieldResolverResource.Properties.RequestMappingTemplate = templateParts.join('\n\n'); - ctx.setResource(resolverResourceId, fieldResolverResource); - } - - private protectReadForField( - ctx: TransformerContext, - parent: ObjectTypeDefinitionNode, - field: FieldDefinitionNode, - rules: AuthRule[], - modelConfiguration: ModelDirectiveConfiguration, - ) { - if (rules && rules.length) { - // Get the directives we need to add to the GraphQL nodes - const directives = this.getDirectivesForRules(rules, false); - - if (directives.length > 0) { - this.addDirectivesToField(ctx, parent.name.value, field.name.value, directives); - - const addDirectivesForOperation = (operationType: ModelDirectiveOperationType) => { - if (modelConfiguration.shouldHave(operationType)) { - const operationName = modelConfiguration.getName(operationType); - // If the parent type has any rules for this operation AND - // the default provider we've to get directives including the default - // as well. - const includeDefault = this.doesTypeHaveRulesForOperation(parent, operationType); - const operationDirectives = this.getDirectivesForRules(rules, includeDefault); - - this.addDirectivesToOperation(ctx, ctx.getQueryTypeName(), operationName, operationDirectives); - } - }; - - addDirectivesForOperation('get'); - addDirectivesForOperation('list'); - } - - const addResourceReference = (operationType: ModelDirectiveOperationType) => { - if (modelConfiguration.shouldHave(operationType)) { - const operationName = modelConfiguration.getName(operationType); - this.addFieldToResourceReferences(ctx.getQueryTypeName(), operationName, rules); - } - }; - - addResourceReference('get'); - addResourceReference('list'); - - const resolverResourceId = ResolverResourceIDs.ResolverResourceID(parent.name.value, field.name.value); - // If the resolver exists (e.g. @connection use it else make a blank one against None) - let resolver = ctx.getResource(resolverResourceId); - if (!resolver) { - // If we need a none data source for the blank resolver, add it. - const noneDS = ctx.getResource(ResourceConstants.RESOURCES.NoneDataSource); - if (!noneDS) { - ctx.setResource(ResourceConstants.RESOURCES.NoneDataSource, this.resources.noneDataSource()); - } - // We also need to add a stack mapping so that this resolver is added to the model stack. - ctx.mapResourceToStack(parent.name.value, resolverResourceId); - resolver = this.resources.blankResolver(parent.name.value, field.name.value); - } - const authExpression = this.authorizationExpressionOnSingleObject(rules, 'ctx.source'); - // if subscriptions auth is enabled protect this field by checking for the operation - // if the operation is a mutation then we deny the a read operation on the field - if (modelConfiguration.getName('level') === 'on') { - if (field.type.kind === Kind.NON_NULL_TYPE) { - throw new InvalidDirectiveError(`\nPer-field auth on the required field ${field.name.value} is not supported with subscriptions. -Either make the field optional, set auth on the object and not the field, or disable subscriptions for the object (setting level to off or public)\n`); - } - // operation check in the protected field - resolver.Properties.ResponseMappingTemplate = print(this.resources.operationCheckExpression(ctx.getMutationTypeName(), field)); - } - // If a resolver exists, a @connection for example. Prepend it to the req. - const templateParts = [print(authExpression), resolver.Properties.RequestMappingTemplate]; - resolver.Properties.RequestMappingTemplate = templateParts.join('\n\n'); - ctx.setResource(resolverResourceId, resolver); - } - } - - private protectUpdateForField( - ctx: TransformerContext, - parent: ObjectTypeDefinitionNode, - field: FieldDefinitionNode, - rules: AuthRule[], - modelConfiguration: ModelDirectiveConfiguration, - ) { - const resolverResourceId = ResolverResourceIDs.DynamoDBUpdateResolverResourceID(parent.name.value); - const subscriptionOperation: ModelDirectiveOperationType = 'onUpdate'; - this.protectUpdateMutation(ctx, resolverResourceId, rules, parent, modelConfiguration, field, subscriptionOperation); - } - - private protectDeleteForField( - ctx: TransformerContext, - parent: ObjectTypeDefinitionNode, - field: FieldDefinitionNode, - rules: AuthRule[], - modelConfiguration: ModelDirectiveConfiguration, - ) { - const resolverResourceId = ResolverResourceIDs.DynamoDBUpdateResolverResourceID(parent.name.value); - const subscriptionOperation: ModelDirectiveOperationType = 'onDelete'; - this.protectDeleteMutation(ctx, resolverResourceId, rules, parent, modelConfiguration, field, subscriptionOperation); - } - - /** - * Protects a create mutation based on an @auth rule specified on a @model field. - * @param ctx The context. - * @param typeName The parent type name. - * @param fieldName The name of the field with the @auth directive. - * @param rules The set of rules that should be applied to create operations. - */ - private protectCreateForField( - ctx: TransformerContext, - parent: ObjectTypeDefinitionNode, - field: FieldDefinitionNode, - rules: AuthRule[], - modelConfiguration: ModelDirectiveConfiguration, - ) { - const typeName = parent.name.value; - const resolverResourceId = ResolverResourceIDs.DynamoDBCreateResolverResourceID(typeName); - const createResolverResource = ctx.getResource(resolverResourceId); - const mutationTypeName = ctx.getMutationTypeName(); - if (rules && rules.length && createResolverResource) { - // Get the directives we need to add to the GraphQL nodes - const directives = this.getDirectivesForRules(rules, false); - let operationName: string = undefined; - - if (directives.length > 0) { - this.addDirectivesToField(ctx, typeName, field.name.value, directives); - - if (modelConfiguration.shouldHave('create')) { - // If the parent type has any rules for this operation AND - // the default provider we've to get directives including the default - // as well. - const includeDefault = this.doesTypeHaveRulesForOperation(parent, 'create'); - const operationDirectives = this.getDirectivesForRules(rules, includeDefault); - - operationName = modelConfiguration.getName('create'); - - this.addDirectivesToOperation(ctx, mutationTypeName, operationName, operationDirectives); - } - } - - if (operationName) { - this.addFieldToResourceReferences(mutationTypeName, operationName, rules); - } - - // Break the rules out by strategy. - const staticGroupAuthorizationRules = this.getStaticGroupRules(rules); - const dynamicGroupAuthorizationRules = this.getDynamicGroupRules(rules); - const ownerAuthorizationRules = this.getOwnerRules(rules); - const providerAuthorization = this.hasProviderAuthRules(rules); - - if ( - (staticGroupAuthorizationRules.length > 0 || dynamicGroupAuthorizationRules.length > 0 || ownerAuthorizationRules.length > 0) && - providerAuthorization === false - ) { - // Generate the expressions to validate each strategy. - const staticGroupAuthorizationExpression = this.resources.staticGroupAuthorizationExpression(staticGroupAuthorizationRules, field); - - // In create mutations, the dynamic group and ownership authorization checks - // are done before calling PutItem. - const dynamicGroupAuthorizationExpression = this.resources.dynamicGroupAuthorizationExpressionForCreateOperationsByField( - dynamicGroupAuthorizationRules, - field.name.value, - ); - const fieldIsList = (fieldName: string) => { - const field = parent.fields.find((field) => field.name.value === fieldName); - if (field) { - return isListType(field.type); - } - return false; - }; - const ownerAuthorizationExpression = this.resources.ownerAuthorizationExpressionForCreateOperationsByField( - ownerAuthorizationRules, - field.name.value, - fieldIsList, - ); - - const throwIfUnauthorizedExpression = this.resources.throwIfUnauthorized(field); - - // Populate a list of configured authentication providers based on the rules - const authModesToCheck = new Set(); - const expressions: Array = new Array(); - - if ( - ownerAuthorizationRules.find((r) => r.provider === 'userPools') || - staticGroupAuthorizationRules.find((r) => r.provider === 'userPools') || - dynamicGroupAuthorizationRules.find((r) => r.provider === 'userPools') - ) { - authModesToCheck.add('userPools'); - } - if ( - ownerAuthorizationRules.find((r) => r.provider === 'oidc') || - staticGroupAuthorizationRules.find((r) => r.provider === 'oidc') || - dynamicGroupAuthorizationRules.find((r) => r.provider === 'oidc') - ) { - authModesToCheck.add('oidc'); - } - - // If we've any modes to check, then add the authMode check code block - // to the start of the resolver. - if (authModesToCheck.size > 0) { - const isUserPoolTheDefault = this.configuredAuthProviders.default === 'userPools'; - expressions.push(this.resources.getAuthModeDeterminationExpression(authModesToCheck, isUserPoolTheDefault)); - } - - // These statements will be wrapped into an authMode check if statement - const authCheckExpressions = [ - staticGroupAuthorizationExpression, - newline(), - dynamicGroupAuthorizationExpression, - newline(), - ownerAuthorizationExpression, - newline(), - throwIfUnauthorizedExpression, - ]; - - // Create the authMode if block and add it to the resolver - expressions.push(this.resources.getAuthModeCheckWrappedExpression(authModesToCheck, compoundExpression(authCheckExpressions))); - - const templateParts = [ - print(iff(raw(`$ctx.args.input.containsKey("${field.name.value}")`), compoundExpression(expressions))), - createResolverResource.Properties.RequestMappingTemplate, - ]; - createResolverResource.Properties.RequestMappingTemplate = templateParts.join('\n\n'); - ctx.setResource(resolverResourceId, createResolverResource); - } - - // if subscriptions is enabled the operation is specified in the mutation response resolver - if (modelConfiguration.shouldHave('onCreate') && (modelConfiguration.getName('level') as ModelSubscriptionLevel) === 'on') { - const getTemplateParts = [createResolverResource.Properties.ResponseMappingTemplate]; - - if (!this.isOperationExpressionSet(mutationTypeName, createResolverResource.Properties.ResponseMappingTemplate)) { - getTemplateParts.unshift(this.resources.setOperationExpression(mutationTypeName)); - } - createResolverResource.Properties.ResponseMappingTemplate = getTemplateParts.join('\n\n'); - ctx.setResource(resolverResourceId, createResolverResource); - } - } - } - - /** - * Takes a flat list of rules, each containing their own list of operations (or queries/mutations if an old API). - * This method splits those rules into buckets keyed by operation and implements some logic for backwards compatibility. - * @param rules The list of auth rules - */ - private splitRules(rules: AuthRule[]) { - // Create a reverse index on rules from operation -> rules list. - const queryRules: { [k in ModelQuery]: AuthRule[] } = { - get: [], - list: [], - }; - const operationRules: { [k in ModelOperation]: AuthRule[] } = { - create: [], - update: [], - delete: [], - read: [], - }; - const matchQuery = (op: ModelQuery) => (rule: AuthRule) => { - if (rule.queries) { - const matchesOp = rule.queries.find((o) => o === op); - return Boolean(matchesOp); - } else if (rule.queries === null) { - return false; - } - return true; - }; - const matchMutation = (op: ModelMutation) => (rule: AuthRule) => { - if (rule.mutations) { - const matchesOp = rule.mutations.find((o) => o === op); - return Boolean(matchesOp); - } else if (rule.mutations === null) { - return false; - } - return true; - }; - const matchOperation = (op: ModelOperation) => (rule: AuthRule) => { - if (rule.operations) { - const matchesOp = rule.operations.find((o) => o === op); - return Boolean(matchesOp); - } else if (rule.operations === null) { - return false; - } - return true; - }; - for (const rule of rules) { - // If operations is provided, then it takes precendence. - if (isTruthyOrNull(rule.operations)) { - // If operations is given use it. - if (matchOperation('read')(rule)) { - queryRules.get.push(rule); - queryRules.list.push(rule); - operationRules.read.push(rule); - } - if (matchOperation('create')(rule)) { - operationRules.create.push(rule); - } - if (matchOperation('update')(rule)) { - operationRules.update.push(rule); - } - if (matchOperation('delete')(rule)) { - operationRules.delete.push(rule); - } - } else { - // If operations is not provided, either use the default behavior or deprecated - // behavior from the queries/mutations arguments for backwards compatibility. - - // Handle default or deprecated query use case - if (isUndefined(rule.queries)) { - // If both operations and queries are undefined, default to read operation protection. - // This is the default behavior. E.G. @auth(rules: [{ allow: owner }]) - queryRules.get.push(rule); - queryRules.list.push(rule); - operationRules.read.push(rule); - } else { - // If operations is undefined & queries is defined, use queries. - // This is the old behavior for backwards compatibility. - if (matchQuery('get')(rule)) { - queryRules.get.push(rule); - } - if (matchQuery('list')(rule)) { - queryRules.list.push(rule); - } - } - - // Handle default or deprecated mutation use case - if (isUndefined(rule.mutations)) { - // If both operations and mutations are undefined, default to create, update, delete - // operation protection. This is the default behavior. E.G. @auth(rules: [{ allow: owner }]) - operationRules.create.push(rule); - operationRules.update.push(rule); - operationRules.delete.push(rule); - } else { - // If operations is undefined & mutations is defined, use mutations. - // This is the old behavior for backwards compatibility. - if (matchMutation('create')(rule)) { - operationRules.create.push(rule); - } - if (matchMutation('update')(rule)) { - operationRules.update.push(rule); - } - if (matchMutation('delete')(rule)) { - operationRules.delete.push(rule); - } - } - } - } - return { - operationRules, - queryRules, - }; - } - - private validateRules(rules: AuthRule[]) { - for (const rule of rules) { - this.validateRuleAuthStrategy(rule); - - const { queries, mutations, operations } = rule; - if (mutations && operations) { - console.warn(`It is not recommended to use 'mutations' and 'operations'. The 'operations' argument will be used.`); - } - if (queries && operations) { - console.warn(`It is not recommended to use 'queries' and 'operations'. The 'operations' argument will be used.`); - } - this.commonRuleValidation(rule); - } - } - - private validateFieldRules(rules: AuthRule[], isParentTypeBuiltinType: boolean, parentHasModelDirective: boolean) { - for (const rule of rules) { - this.validateRuleAuthStrategy(rule); - - const { queries, mutations } = rule; - if (queries || mutations) { - throw new InvalidDirectiveError( - `@auth directives used on field definitions may not specify the 'queries' or 'mutations' arguments. \ -All @auth directives used on field definitions are performed when the field is resolved and can be thought of as 'read' operations.`, - ); - } - - if (isParentTypeBuiltinType && rule.operations && rule.operations.length > 0) { - throw new InvalidDirectiveError( - `@auth rules on fields within Query, Mutation, Subscription cannot specify 'operations' argument as these rules \ -are already on an operation already.`, - ); - } - - if (!parentHasModelDirective && rule.operations && rule.operations.length > 0) { - throw new InvalidDirectiveError( - `@auth rules on fields within types that does not have @model directive cannot specify 'operations' argument as there are \ -operations will be generated by the CLI.`, - ); - } - - this.commonRuleValidation(rule); - } - } - - // commmon rule validation between obj and field - private commonRuleValidation(rule: AuthRule) { - const { identityField, identityClaim, allow, groups, groupsField, groupClaim } = rule; - if (allow === 'groups' && (identityClaim || identityField)) { - throw new InvalidDirectiveError(` - @auth identityField/Claim can only be used for 'allow: owner'`); - } - if (allow === 'owner' && groupClaim) { - throw new InvalidDirectiveError(` - @auth groupClaim can only be used 'allow: groups'`); - } - if (groupsField && groups) { - throw new InvalidDirectiveError('This rule has groupsField and groups, please use one or the other'); - } - if (identityField && identityClaim) { - throw new InvalidDirectiveError('Please use consider IdentifyClaim over IdentityField as it is deprecated.'); - } - } - - /** - * Protect get queries. - * If static group: - * If statically authorized then allow the operation. Stop. - * If owner and/or dynamic group: - * If the result item satisfies the owner/group authorization condition - * then allow it. - * @param ctx The transformer context. - * @param resolverResourceId The logical id of the get resolver. - * @param rules The auth rules to apply. - * @param parent ObjectDefinition of the type - * @param modelConfiguration auth configuration for the model - * @param updateSchema flag to indicate if protection needs to update the schema or just the resolver. When a connection is being protected - * the schema should not be updated - */ - private protectGetQuery( - ctx: TransformerContext, - resolverResourceId: string, - rules: AuthRule[], - parent: ObjectTypeDefinitionNode | null, - modelConfiguration: ModelDirectiveConfiguration, - updateSchema: boolean, - ) { - const resolver = ctx.getResource(resolverResourceId); - if (!rules || rules.length === 0 || !resolver) { - return; - } else { - let operationName: string = undefined; - - if (modelConfiguration.shouldHave('get') && updateSchema) { - operationName = modelConfiguration.getName('get'); - // If the parent type has any rules for this operation AND - // the default provider we've to get directives including the default - // as well. - const includeDefault = parent !== null ? this.doesTypeHaveRulesForOperation(parent, 'get') : this.shouldAddDefaultAuthDirective(); - const operationDirectives = this.getDirectivesForRules(rules, includeDefault); - - if (operationDirectives.length > 0) { - this.addDirectivesToOperation(ctx, ctx.getQueryTypeName(), operationName, operationDirectives); - } - } - - if (operationName) { - this.addFieldToResourceReferences(ctx.getQueryTypeName(), operationName, rules); - } - - const authExpression = this.authorizationExpressionOnSingleObject(rules); - - if (authExpression) { - const templateParts = [print(authExpression), resolver.Properties.ResponseMappingTemplate]; - resolver.Properties.ResponseMappingTemplate = templateParts.join('\n\n'); - ctx.setResource(resolverResourceId, resolver); - } - } - } - - private authorizationExpressionOnSingleObject(rules: AuthRule[], objectPath: string = 'ctx.result') { - // Break the rules out by strategy. - const staticGroupAuthorizationRules = this.getStaticGroupRules(rules); - const dynamicGroupAuthorizationRules = this.getDynamicGroupRules(rules); - const ownerAuthorizationRules = this.getOwnerRules(rules); - const providerAuthorization = this.hasProviderAuthRules(rules); - - if ( - (staticGroupAuthorizationRules.length > 0 || dynamicGroupAuthorizationRules.length > 0 || ownerAuthorizationRules.length > 0) && - providerAuthorization === false - ) { - // Generate the expressions to validate each strategy. - const staticGroupAuthorizationExpression = this.resources.staticGroupAuthorizationExpression(staticGroupAuthorizationRules); - const dynamicGroupAuthorizationExpression = this.resources.dynamicGroupAuthorizationExpressionForReadOperations( - dynamicGroupAuthorizationRules, - objectPath, - ); - const ownerAuthorizationExpression = this.resources.ownerAuthorizationExpressionForReadOperations( - ownerAuthorizationRules, - objectPath, - ); - const throwIfUnauthorizedExpression = this.resources.throwIfUnauthorized(); - - // If we've any modes to check, then add the authMode check code block - // to the start of the resolver. - const authModesToCheck = new Set(); - const expressions: Array = new Array(); - expressions.push(this.resources.returnIfEmpty(objectPath)); - if ( - ownerAuthorizationRules.find((r) => r.provider === 'userPools') || - staticGroupAuthorizationRules.find((r) => r.provider === 'userPools') || - dynamicGroupAuthorizationRules.find((r) => r.provider === 'userPools') - ) { - authModesToCheck.add('userPools'); - } - if ( - ownerAuthorizationRules.find((r) => r.provider === 'oidc') || - staticGroupAuthorizationRules.find((r) => r.provider === 'oidc') || - dynamicGroupAuthorizationRules.find((r) => r.provider === 'oidc') - ) { - authModesToCheck.add('oidc'); - } - - if (authModesToCheck.size > 0) { - const isUserPoolTheDefault = this.configuredAuthProviders.default === 'userPools'; - expressions.push(this.resources.getAuthModeDeterminationExpression(authModesToCheck, isUserPoolTheDefault)); - } - - // Update the existing resolver with the authorization checks. - // These statements will be wrapped into an authMode check if statement - const templateExpressions = [ - staticGroupAuthorizationExpression, - newline(), - dynamicGroupAuthorizationExpression, - newline(), - ownerAuthorizationExpression, - newline(), - throwIfUnauthorizedExpression, - ]; - - // These statements will be wrapped into an authMode check if statement - expressions.push(this.resources.getAuthModeCheckWrappedExpression(authModesToCheck, compoundExpression(templateExpressions))); - - return compoundExpression(expressions); - } - } - - /** - * Protect list queries. - * If static group: - * If the user is statically authorized then return items and stop. - * If dynamic group and/or owner: - * Loop through all items and find items that satisfy any of the group or - * owner conditions. - * @param ctx The transformer context. - * @param resolverResourceId The logical id of the resolver to be updated in the CF template. - * @param rules The set of rules that apply to the operation. - * @argument parent The parent Object of the query - * @argument modelConfiguration model directive configuration of the parent - * @argument explicitOperationName name of the listQuery to be generated - * @argument updateSchema flag indicating if the schema needs to be updated with appsync auth directives - */ - private protectListQuery( - ctx: TransformerContext, - resolverResourceId: string, - rules: AuthRule[], - parent: ObjectTypeDefinitionNode | null, - modelConfiguration: ModelDirectiveConfiguration, - explicitOperationName: string = undefined, - updateSchema: boolean = true, - ) { - const resolver = ctx.getResource(resolverResourceId); - if (!rules || rules.length === 0 || !resolver) { - return; - } - - if (modelConfiguration.shouldHave('list')) { - const operationName = explicitOperationName ? explicitOperationName : modelConfiguration.getName('list'); - // If the parent type has any rules for this operation AND - // the default provider we've to get directives including the default - // as well. - const includeDefault = parent !== null ? this.doesTypeHaveRulesForOperation(parent, 'list') : this.shouldAddDefaultAuthDirective(); - const operationDirectives = this.getDirectivesForRules(rules, includeDefault); - - if (operationDirectives.length > 0 && updateSchema) { - this.addDirectivesToOperation(ctx, ctx.getQueryTypeName(), operationName, operationDirectives); - } - - this.addFieldToResourceReferences(ctx.getQueryTypeName(), operationName, rules); - } - - const authExpression = this.authorizationExpressionForListResult(rules); - - if (authExpression) { - const templateParts = [print(authExpression), resolver.Properties.ResponseMappingTemplate]; - resolver.Properties.ResponseMappingTemplate = templateParts.join('\n\n'); - ctx.setResource(resolverResourceId, resolver); - } - } - - /** - * Returns a VTL expression that will authorize a list of results based on a set of auth rules. - * @param rules The auth rules. - * - * If an itemList is specifed in @param itemList it will use this ref to filter out items in this list that are not authorized - */ - private authorizationExpressionForListResult(rules: AuthRule[], itemList: string = 'ctx.result.items') { - // Break the rules out by strategy. - const staticGroupAuthorizationRules = this.getStaticGroupRules(rules); - const dynamicGroupAuthorizationRules = this.getDynamicGroupRules(rules); - const ownerAuthorizationRules = this.getOwnerRules(rules); - const providerAuthorization = this.hasProviderAuthRules(rules); - - // if there is a rule combination of owner or group and private, public for userpools then we don't need to emit any of the access check - // logic since it is not needed. For example we don't emit any of this logic for rules like this: - // { allow: groups, groups: ["Admin"]}, - // { allow: private } - - if ( - (staticGroupAuthorizationRules.length > 0 || dynamicGroupAuthorizationRules.length > 0 || ownerAuthorizationRules.length > 0) && - providerAuthorization === false - ) { - // Generate the expressions to validate each strategy. - const staticGroupAuthorizationExpression = this.resources.staticGroupAuthorizationExpression(staticGroupAuthorizationRules); - - // In list queries, the dynamic group and ownership authorization checks - // occur on a per item basis. The helpers take the variable names - // as parameters to allow for this use case. - const dynamicGroupAuthorizationExpression = this.resources.dynamicGroupAuthorizationExpressionForReadOperations( - dynamicGroupAuthorizationRules, - 'item', - ResourceConstants.SNIPPETS.IsLocalDynamicGroupAuthorizedVariable, - raw(`false`), - ); - const ownerAuthorizationExpression = this.resources.ownerAuthorizationExpressionForReadOperations( - ownerAuthorizationRules, - 'item', - ResourceConstants.SNIPPETS.IsLocalOwnerAuthorizedVariable, - raw(`false`), - ); - const appendIfLocallyAuthorized = this.resources.appendItemIfLocallyAuthorized(); - - const ifNotStaticallyAuthedFilterObjects = iff( - not(ref(ResourceConstants.SNIPPETS.IsStaticGroupAuthorizedVariable)), - compoundExpression([ - set(ref('items'), list([])), - forEach(ref('item'), ref(itemList), [ - dynamicGroupAuthorizationExpression, - newline(), - ownerAuthorizationExpression, - newline(), - appendIfLocallyAuthorized, - ]), - set(ref(itemList), ref('items')), - ]), - ); - - // If we've any modes to check, then add the authMode check code block - // to the start of the resolver. - const authModesToCheck = new Set(); - const expressions: Array = new Array(); - - if ( - ownerAuthorizationRules.find((r) => r.provider === 'userPools') || - staticGroupAuthorizationRules.find((r) => r.provider === 'userPools') || - dynamicGroupAuthorizationRules.find((r) => r.provider === 'userPools') - ) { - authModesToCheck.add('userPools'); - } - if ( - ownerAuthorizationRules.find((r) => r.provider === 'oidc') || - staticGroupAuthorizationRules.find((r) => r.provider === 'oidc') || - dynamicGroupAuthorizationRules.find((r) => r.provider === 'oidc') - ) { - authModesToCheck.add('oidc'); - } - - if (authModesToCheck.size > 0) { - const isUserPoolTheDefault = this.configuredAuthProviders.default === 'userPools'; - expressions.push(this.resources.getAuthModeDeterminationExpression(authModesToCheck, isUserPoolTheDefault)); - } - - // These statements will be wrapped into an authMode check if statement - const templateExpressions = [ - staticGroupAuthorizationExpression, - newline(), - comment('[Start] If not static group authorized, filter items'), - ifNotStaticallyAuthedFilterObjects, - comment('[End] If not static group authorized, filter items'), - ]; - - // Create the authMode if block and add it to the resolver - expressions.push(this.resources.getAuthModeCheckWrappedExpression(authModesToCheck, compoundExpression(templateExpressions))); - - return compoundExpression(expressions); - } - } - - /** - * Inject auth rules for create mutations. - * If owner auth: - * If the owner field exists in the input, validate that it against the identity. - * If the owner field dne in the input, insert the identity. - * If group: - * If the user is static group authorized allow operation no matter what. - * If dynamic group and the input defines a group(s) validate it against the identity. - * @param ctx - * @param resolverResourceId - * @param rules - */ - private protectCreateMutation( - ctx: TransformerContext, - resolverResourceId: string, - rules: AuthRule[], - parent: ObjectTypeDefinitionNode, - modelConfiguration: ModelDirectiveConfiguration, - ) { - const resolver = ctx.getResource(resolverResourceId); - if (!rules || rules.length === 0 || !resolver) { - return; - } else { - const mutationTypeName = ctx.getMutationTypeName(); - - if (modelConfiguration.shouldHave('create')) { - const operationName = modelConfiguration.getName('create'); - // If the parent type has any rules for this operation AND - // the default provider we've to get directives including the default - // as well. - const includeDefault = this.doesTypeHaveRulesForOperation(parent, 'create'); - const operationDirectives = this.getDirectivesForRules(rules, includeDefault); - - if (operationDirectives.length > 0) { - this.addDirectivesToOperation(ctx, mutationTypeName, operationName, operationDirectives); - } - - this.addFieldToResourceReferences(mutationTypeName, operationName, rules); - } - - // Break the rules out by strategy. - const staticGroupAuthorizationRules = this.getStaticGroupRules(rules); - const dynamicGroupAuthorizationRules = this.getDynamicGroupRules(rules); - const ownerAuthorizationRules = this.getOwnerRules(rules); - const providerAuthorization = this.hasProviderAuthRules(rules); - - if ( - (staticGroupAuthorizationRules.length > 0 || dynamicGroupAuthorizationRules.length > 0 || ownerAuthorizationRules.length > 0) && - providerAuthorization === false - ) { - // Generate the expressions to validate each strategy. - const staticGroupAuthorizationExpression = this.resources.staticGroupAuthorizationExpression(staticGroupAuthorizationRules); - - // In create mutations, the dynamic group and ownership authorization checks - // are done before calling PutItem. - const dynamicGroupAuthorizationExpression = - this.resources.dynamicGroupAuthorizationExpressionForCreateOperations(dynamicGroupAuthorizationRules); - const fieldIsList = (fieldName: string) => { - const field = parent.fields.find((field) => field.name.value === fieldName); - if (field) { - return isListType(field.type); - } - return false; - }; - const ownerAuthorizationExpression = this.resources.ownerAuthorizationExpressionForCreateOperations( - ownerAuthorizationRules, - fieldIsList, - ); - - const throwIfUnauthorizedExpression = this.resources.throwIfUnauthorized(); - - // If we've any modes to check, then add the authMode check code block - // to the start of the resolver. - const authModesToCheck = new Set(); - const expressions: Array = new Array(); - - if ( - ownerAuthorizationRules.find((r) => r.provider === 'userPools') || - staticGroupAuthorizationRules.find((r) => r.provider === 'userPools') || - dynamicGroupAuthorizationRules.find((r) => r.provider === 'userPools') - ) { - authModesToCheck.add('userPools'); - } - if ( - ownerAuthorizationRules.find((r) => r.provider === 'oidc') || - staticGroupAuthorizationRules.find((r) => r.provider === 'oidc') || - dynamicGroupAuthorizationRules.find((r) => r.provider === 'oidc') - ) { - authModesToCheck.add('oidc'); - } - - if (authModesToCheck.size > 0) { - const isUserPoolTheDefault = this.configuredAuthProviders.default === 'userPools'; - expressions.push(this.resources.getAuthModeDeterminationExpression(authModesToCheck, isUserPoolTheDefault)); - } - - // These statements will be wrapped into an authMode check if statement - const authCheckExpressions = [ - staticGroupAuthorizationExpression, - newline(), - dynamicGroupAuthorizationExpression, - newline(), - ownerAuthorizationExpression, - newline(), - throwIfUnauthorizedExpression, - ]; - - // Create the authMode if block and add it to the resolver - expressions.push(this.resources.getAuthModeCheckWrappedExpression(authModesToCheck, compoundExpression(authCheckExpressions))); - - const templateParts = [print(compoundExpression(expressions)), resolver.Properties.RequestMappingTemplate]; - resolver.Properties.RequestMappingTemplate = templateParts.join('\n\n'); - ctx.setResource(resolverResourceId, resolver); - } - } - } - - /** - * Protect update and delete mutations. - * If Owner: - * Update the conditional expression such that the update only works if - * the user is the owner. - * If dynamic group: - * Update the conditional expression such that it succeeds if the user is - * dynamic group authorized. If the operation is also owner authorized this - * should be joined with an OR expression. - * If static group: - * If the user is statically authorized then allow no matter what. This can - * be done by removing the conditional expression as long as static group - * auth is always checked last. - * @param ctx The transformer context. - * @param resolverResourceId The logical id of the resolver in the template. - * @param rules The list of rules to apply. - */ - private protectUpdateOrDeleteMutation( - ctx: TransformerContext, - resolverResourceId: string, - rules: AuthRule[], - parent: ObjectTypeDefinitionNode, - modelConfiguration: ModelDirectiveConfiguration, - isUpdate: boolean, - field?: FieldDefinitionNode, - ifCondition?: Expression, - subscriptionOperation?: ModelDirectiveOperationType, - ) { - const resolver = ctx.getResource(resolverResourceId); - if (!rules || rules.length === 0 || !resolver) { - return; - } else { - const mutationTypeName = ctx.getMutationTypeName(); - - if (modelConfiguration.shouldHave(isUpdate ? 'update' : 'delete')) { - const operationName = modelConfiguration.getName(isUpdate ? 'update' : 'delete'); - // If the parent type has any rules for this operation AND - // the default provider we've to get directives including the default - // as well. - const includeDefault = Boolean(!field && this.doesTypeHaveRulesForOperation(parent, isUpdate ? 'update' : 'delete')); - const operationDirectives = this.getDirectivesForRules(rules, includeDefault); - - if (operationDirectives.length > 0) { - this.addDirectivesToOperation(ctx, mutationTypeName, operationName, operationDirectives); - } - - this.addFieldToResourceReferences(mutationTypeName, operationName, rules); - } - - // Break the rules out by strategy. - const staticGroupAuthorizationRules = this.getStaticGroupRules(rules); - const dynamicGroupAuthorizationRules = this.getDynamicGroupRules(rules); - const ownerAuthorizationRules = this.getOwnerRules(rules); - const providerAuthorization = this.hasProviderAuthRules(rules); - - if ( - (staticGroupAuthorizationRules.length > 0 || dynamicGroupAuthorizationRules.length > 0 || ownerAuthorizationRules.length > 0) && - providerAuthorization === false - ) { - // Generate the expressions to validate each strategy. - const staticGroupAuthorizationExpression = this.resources.staticGroupAuthorizationExpression(staticGroupAuthorizationRules, field); - - const fieldIsList = (fieldName: string) => { - const field = parent.fields.find((field) => field.name.value === fieldName); - if (field) { - return isListType(field.type); - } - return false; - }; - - // In create mutations, the dynamic group and ownership authorization checks - // are done before calling PutItem. - const dynamicGroupAuthorizationExpression = this.resources.dynamicGroupAuthorizationExpressionForUpdateOrDeleteOperations( - dynamicGroupAuthorizationRules, - fieldIsList, - field ? field.name.value : undefined, - ); - - const ownerAuthorizationExpression = this.resources.ownerAuthorizationExpressionForUpdateOrDeleteOperations( - ownerAuthorizationRules, - fieldIsList, - field ? field.name.value : undefined, - ); - - const collectAuthCondition = this.resources.collectAuthCondition(); - const staticGroupAuthorizedVariable = this.resources.getStaticAuthorizationVariable(field); - const ifNotStaticallyAuthedCreateAuthCondition = iff( - raw(`! $${staticGroupAuthorizedVariable}`), - compoundExpression([ - dynamicGroupAuthorizationExpression, - newline(), - ownerAuthorizationExpression, - newline(), - collectAuthCondition, - ]), - ); - - const throwIfNotStaticGroupAuthorizedOrAuthConditionIsEmpty = - this.resources.throwIfNotStaticGroupAuthorizedOrAuthConditionIsEmpty(field); - - // If we've any modes to check, then add the authMode check code block - // to the start of the resolver. - const authModesToCheck = new Set(); - const expressions: Array = new Array(); - - if ( - ownerAuthorizationRules.find((r) => r.provider === 'userPools') || - staticGroupAuthorizationRules.find((r) => r.provider === 'userPools') || - dynamicGroupAuthorizationRules.find((r) => r.provider === 'userPools') - ) { - authModesToCheck.add('userPools'); - } - if ( - ownerAuthorizationRules.find((r) => r.provider === 'oidc') || - staticGroupAuthorizationRules.find((r) => r.provider === 'oidc') || - dynamicGroupAuthorizationRules.find((r) => r.provider === 'oidc') - ) { - authModesToCheck.add('oidc'); - } - - if (authModesToCheck.size > 0) { - const isUserPoolTheDefault = this.configuredAuthProviders.default === 'userPools'; - expressions.push(this.resources.getAuthModeDeterminationExpression(authModesToCheck, isUserPoolTheDefault)); - } - - // These statements will be wrapped into an authMode check if statement - const authorizationLogic = compoundExpression([ - staticGroupAuthorizationExpression, - newline(), - ifNotStaticallyAuthedCreateAuthCondition, - newline(), - throwIfNotStaticGroupAuthorizedOrAuthConditionIsEmpty, - ]); - - // Create the authMode if block and add it to the resolver - expressions.push(this.resources.getAuthModeCheckWrappedExpression(authModesToCheck, authorizationLogic)); - - const templateParts = [ - print(field && ifCondition ? iff(ifCondition, compoundExpression(expressions)) : compoundExpression(expressions)), - resolver.Properties.RequestMappingTemplate, - ]; - resolver.Properties.RequestMappingTemplate = templateParts.join('\n\n'); - ctx.setResource(resolverResourceId, resolver); - } - - // if protect is for field and there is a subscription for update / delete then protect the field in that operation - if ( - field && - subscriptionOperation && - modelConfiguration.shouldHave(subscriptionOperation) && - (modelConfiguration.getName('level') as ModelSubscriptionLevel) === 'on' - ) { - let mutationResolver = resolver; - let mutationResolverResourceID = resolverResourceId; - // if we are protecting delete then we need to get the delete resolver - if (subscriptionOperation === 'onDelete') { - mutationResolverResourceID = ResolverResourceIDs.DynamoDBDeleteResolverResourceID(parent.name.value); - mutationResolver = ctx.getResource(mutationResolverResourceID); - } - const getTemplateParts = [mutationResolver.Properties.ResponseMappingTemplate]; - if (!this.isOperationExpressionSet(mutationTypeName, mutationResolver.Properties.ResponseMappingTemplate)) { - getTemplateParts.unshift(this.resources.setOperationExpression(mutationTypeName)); - } - mutationResolver.Properties.ResponseMappingTemplate = getTemplateParts.join('\n\n'); - ctx.setResource(mutationResolverResourceID, mutationResolver); - } - } - } - - /** - * If we are protecting the mutation for a field level @auth directive, include - * the necessary if condition. - * @param ctx The transformer context - * @param resolverResourceId The resolver resource id - * @param rules The delete rules - * @param parent The parent object - * @param field The optional field - */ - private protectUpdateMutation( - ctx: TransformerContext, - resolverResourceId: string, - rules: AuthRule[], - parent: ObjectTypeDefinitionNode, - modelConfiguration: ModelDirectiveConfiguration, - field?: FieldDefinitionNode, - subscriptionOperation?: ModelDirectiveOperationType, - ) { - return this.protectUpdateOrDeleteMutation( - ctx, - resolverResourceId, - rules, - parent, - modelConfiguration, - true, - field, - field ? raw(`$ctx.args.input.containsKey("${field.name.value}")`) : undefined, - subscriptionOperation, - ); - } - - /** - * If we are protecting the mutation for a field level @auth directive, include - * the necessary if condition. - * @param ctx The transformer context - * @param resolverResourceId The resolver resource id - * @param rules The delete rules - * @param parent The parent object - * @param field The optional field - */ - private protectDeleteMutation( - ctx: TransformerContext, - resolverResourceId: string, - rules: AuthRule[], - parent: ObjectTypeDefinitionNode, - modelConfiguration: ModelDirectiveConfiguration, - field?: FieldDefinitionNode, - subscriptionOperation?: ModelDirectiveOperationType, - ) { - return this.protectUpdateOrDeleteMutation( - ctx, - resolverResourceId, - rules, - parent, - modelConfiguration, - false, - field, - field - ? raw(`$ctx.args.input.containsKey("${field.name.value}") && $util.isNull($ctx.args.input.get("${field.name.value}"))`) - : undefined, - subscriptionOperation, - ); - } - - /** - * When read operations are protected via @auth, all @connection resolvers will be protected. - * Find the directives & update their resolvers with auth logic - */ - private protectConnections( - ctx: TransformerContext, - def: ObjectTypeDefinitionNode, - rules: AuthRule[], - modelConfiguration: ModelDirectiveConfiguration, - ) { - const thisModelName = def.name.value; - for (const inputDef of ctx.inputDocument.definitions) { - if (inputDef.kind === Kind.OBJECT_TYPE_DEFINITION) { - for (const field of inputDef.fields) { - const returnTypeName = getBaseType(field.type); - if (fieldHasDirective(field, 'connection') && returnTypeName === thisModelName) { - const resolverResourceId = ResolverResourceIDs.ResolverResourceID(inputDef.name.value, field.name.value); - - // Add the auth directives to the connection to make sure the - // member is accessible. - const directives = this.getDirectivesForRules(rules, false); - if (directives.length > 0) { - this.addDirectivesToOperation(ctx, inputDef.name.value, field.name.value, directives); - } - - if (isListType(field.type)) { - this.protectListQuery(ctx, resolverResourceId, rules, null, modelConfiguration, undefined, false); - } else { - this.protectGetQuery(ctx, resolverResourceId, rules, null, modelConfiguration, false); - } - } - } - } - } - } - - /** - * When read operations are protected via @auth, all secondary @key query resolvers will be protected. - * Find the directives & update their resolvers with auth logic - */ - private protectQueries( - ctx: TransformerContext, - def: ObjectTypeDefinitionNode, - rules: AuthRule[], - modelConfiguration: ModelDirectiveConfiguration, - ) { - const secondaryKeyDirectivesWithQueries = (def.directives || []).filter((d) => { - const isKey = d.name.value === 'key'; - const args = getDirectiveArguments(d); - // @key with a name is a secondary key. - const isSecondaryKey = Boolean(args.name); - const hasQueryField = Boolean(args.queryField); - return isKey && isSecondaryKey && hasQueryField; - }); - for (const keyWithQuery of secondaryKeyDirectivesWithQueries) { - const args = getDirectiveArguments(keyWithQuery); - const resolverResourceId = ResolverResourceIDs.ResolverResourceID(ctx.getQueryTypeName(), args.queryField); - this.protectListQuery(ctx, resolverResourceId, rules, null, modelConfiguration, args.queryField, true); - } - } - - private protectSearchQuery(ctx: TransformerContext, def: ObjectTypeDefinitionNode, resolverResourceId: string, rules: AuthRule[]) { - const resolver = ctx.getResource(resolverResourceId); - if (!rules || rules.length === 0 || !resolver) { - return; - } else { - const operationName = resolver.Properties.FieldName; - const includeDefault = def !== null ? this.doesTypeHaveRulesForOperation(def, 'list') : this.shouldAddDefaultAuthDirective(); - const operationDirectives = this.getDirectivesForRules(rules, includeDefault); - if (operationDirectives.length > 0) { - this.addDirectivesToOperation(ctx, ctx.getQueryTypeName(), operationName, operationDirectives); - } - this.addFieldToResourceReferences(ctx.getQueryTypeName(), operationName, rules); - // create auth expression - const authExpression = this.authorizationExpressionForListResult(rules, 'es_items'); - if (authExpression) { - const templateParts = [ - print(this.resources.makeESItemsExpression(ctx.isProjectUsingDataStore())), - print(authExpression), - print(this.resources.makeESToGQLExpression()), - ]; - resolver.Properties.ResponseMappingTemplate = templateParts.join('\n\n'); - ctx.setResource(resolverResourceId, resolver); - } - } - } - - protectSyncQuery(ctx: TransformerContext, def: ObjectTypeDefinitionNode, resolverResourceID: string, rules: AuthRule[]) { - const resolver = ctx.getResource(resolverResourceID); - if (!rules || rules.length === 0 || !resolver) { - return; - } - const operationName = resolver.Properties.FieldName; - const includeDefault = def !== null ? this.doesTypeHaveRulesForOperation(def, 'list') : this.shouldAddDefaultAuthDirective(); - const operationDirectives = this.getDirectivesForRules(rules, includeDefault); - if (operationDirectives.length > 0) { - this.addDirectivesToOperation(ctx, ctx.getQueryTypeName(), operationName, operationDirectives); - } - this.addFieldToResourceReferences(ctx.getQueryTypeName(), operationName, rules); - // create auth expression - const authExpression = this.authorizationExpressionForListResult(rules); - if (authExpression) { - const templateParts = [print(authExpression), resolver.Properties.ResponseMappingTemplate]; - resolver.Properties.ResponseMappingTemplate = templateParts.join('\n\n'); - ctx.setResource(resolverResourceID, resolver); - } - } - - // OnCreate Subscription - private protectOnCreateSubscription( - ctx: TransformerContext, - rules: AuthRule[], - parent: ObjectTypeDefinitionNode, - modelConfiguration: ModelDirectiveConfiguration, - ) { - const names = modelConfiguration.getNames('onCreate'); - const level = modelConfiguration.getName('level') as ModelSubscriptionLevel; - if (names) { - names.forEach((name) => { - this.addSubscriptionResolvers(ctx, rules, parent, level, name); - }); - } - } - - // OnUpdate Subscription - private protectOnUpdateSubscription( - ctx: TransformerContext, - rules: AuthRule[], - parent: ObjectTypeDefinitionNode, - modelConfiguration: ModelDirectiveConfiguration, - ) { - const names = modelConfiguration.getNames('onUpdate'); - const level = modelConfiguration.getName('level') as ModelSubscriptionLevel; - if (names) { - names.forEach((name) => { - this.addSubscriptionResolvers(ctx, rules, parent, level, name); - }); - } - } - - // OnDelete Subscription - private protectOnDeleteSubscription( - ctx: TransformerContext, - rules: AuthRule[], - parent: ObjectTypeDefinitionNode, - modelConfiguration: ModelDirectiveConfiguration, - ) { - const names = modelConfiguration.getNames('onDelete'); - const level = modelConfiguration.getName('level') as ModelSubscriptionLevel; - if (names) { - names.forEach((name) => { - this.addSubscriptionResolvers(ctx, rules, parent, level, name); - }); - } - } - - // adds subscription resolvers (request / response) based on the operation provided - private addSubscriptionResolvers( - ctx: TransformerContext, - rules: AuthRule[], - parent: ObjectTypeDefinitionNode, - level: ModelSubscriptionLevel, - fieldName: string, - ) { - const resolverResourceId = ResolverResourceIDs.ResolverResourceID('Subscription', fieldName); - const resolver = this.resources.generateSubscriptionResolver(fieldName); - // If the data source does not exist it is created and added as a resource for public && on levels - const noneDS = ctx.getResource(ResourceConstants.RESOURCES.NoneDataSource); - - // add the rules in the subscription resolver - if (!rules || rules.length === 0) { - return; - } else if (level === 'public') { - // set the resource with no auth logic - ctx.setResource(resolverResourceId, resolver); - } else { - // Get the directives we need to add to the GraphQL nodes - const includeDefault = parent !== null ? this.doesTypeHaveRulesForOperation(parent, 'get') : this.shouldAddDefaultAuthDirective(); - const directives = this.getDirectivesForRules(rules, includeDefault); - - if (directives.length > 0) { - this.addDirectivesToField(ctx, ctx.getSubscriptionTypeName(), fieldName, directives); - } - - this.addFieldToResourceReferences(ctx.getSubscriptionTypeName(), fieldName, rules); - - // Break the rules out by strategy. - const staticGroupAuthorizationRules = this.getStaticGroupRules(rules); - const ownerAuthorizationRules = this.getOwnerRules(rules); - const providerAuthorization = this.hasProviderAuthRules(rules); - - if ((staticGroupAuthorizationRules.length > 0 || ownerAuthorizationRules.length > 0) && providerAuthorization === false) { - const staticGroupAuthorizationExpression = this.resources.staticGroupAuthorizationExpression(staticGroupAuthorizationRules); - const ownerAuthorizationExpression = this.resources.ownerAuthorizationExpressionForSubscriptions(ownerAuthorizationRules); - - const throwIfUnauthorizedExpression = this.resources.throwIfSubscriptionUnauthorized(); - - // Populate a list of configured authentication providers based on the rules - const authModesToCheck = new Set(); - const expressions: Array = new Array(); - - if ( - ownerAuthorizationRules.find((r) => r.provider === 'userPools') || - staticGroupAuthorizationRules.find((r) => r.provider === 'userPools') - ) { - authModesToCheck.add('userPools'); - } - if ( - ownerAuthorizationRules.find((r) => r.provider === 'oidc') || - staticGroupAuthorizationRules.find((r) => r.provider === 'oidc') - ) { - authModesToCheck.add('oidc'); - } - - // If we've any modes to check, then add the authMode check code block - // to the start of the resolver. - if (authModesToCheck.size > 0) { - const isUserPoolTheDefault = this.configuredAuthProviders.default === 'userPools'; - expressions.push(this.resources.getAuthModeDeterminationExpression(authModesToCheck, isUserPoolTheDefault)); - } - - const authCheckExpressions = [ - staticGroupAuthorizationExpression, - newline(), - ownerAuthorizationExpression, - newline(), - throwIfUnauthorizedExpression, - ]; - - // Create the authMode if block and add it to the resolver - expressions.push(this.resources.getAuthModeCheckWrappedExpression(authModesToCheck, compoundExpression(authCheckExpressions))); - - const templateParts = [print(compoundExpression(expressions)), resolver.Properties.ResponseMappingTemplate]; - - resolver.Properties.ResponseMappingTemplate = templateParts.join('\n\n'); - ctx.setResource(resolverResourceId, resolver); - - // check if owner is enabled in auth - const ownerRules = rules.filter((rule) => rule.allow === OWNER_AUTH_STRATEGY); - const needsDefaultOwnerField = ownerRules.find((rule) => !rule.ownerField); - - if (ownerRules) { - // if there is an owner rule without ownerField add the owner field in the type - if (needsDefaultOwnerField) { - this.addOwner(ctx, parent.name.value); - } - - const makeNonNull = !this.isSubscriptionOwnerArgumentOptional(rules); - this.addSubscriptionOwnerArgument(ctx, resolver, ownerRules, makeNonNull); - } - } - } - // If the subscription level is set to public it adds the subscription resolver with no auth logic - if (!noneDS) { - ctx.setResource(ResourceConstants.RESOURCES.NoneDataSource, this.resources.noneDataSource()); - } - // finally map the resource to the stack - ctx.mapResourceToStack(parent.name.value, resolverResourceId); - } - - private isSubscriptionOwnerArgumentOptional(rules: AuthRule[]): Boolean { - const ownerRules = rules.filter((rule) => rule.allow === OWNER_AUTH_STRATEGY); - - // if there are multiple owner rules then the owner argument is optional - if (ownerRules.length > 1) { - return true; - } - - // if there are any public, private, and/or static group rules then the owner argument is optional - return !!rules.find( - (rule) => (rule.allow === GROUPS_AUTH_STRATEGY && !rule.groupsField) || rule.allow === 'private' || rule.allow === 'public', - ); - } - - private addSubscriptionOwnerArgument(ctx: TransformerContext, resolver: Resolver, ownerRules: AuthRule[], makeNonNull: boolean = false) { - let subscription = ctx.getSubscription(); - let createField: FieldDefinitionNode = subscription.fields.find( - (field) => field.name.value === resolver.Properties.FieldName, - ) as FieldDefinitionNode; - const nameNode: any = makeNonNull ? makeNonNullType(makeNamedType('String')) : makeNamedType('String'); - // const createArguments = [makeInputValueDefinition(DEFAULT_OWNER_FIELD, nameNode)]; - const ownerArgumentList = ownerRules.map((rule) => { - return makeInputValueDefinition(rule.ownerField || DEFAULT_OWNER_FIELD, nameNode); - }); - createField = { - ...createField, - arguments: ownerArgumentList, - }; - subscription = { - ...subscription, - fields: subscription.fields.map((field) => (field.name.value === resolver.Properties.FieldName ? createField : field)), - }; - ctx.putType(subscription); - } - - /** - * Add owner fields to the type to make the owners accessible in selection set - * @param ctx TransformerContext - * @param object ObjectDefinitionNode - * @param rules Authorization rules - */ - private addOwnerFieldsToObject(ctx: TransformerContext, typeName: string, rules: AuthRule[]): void { - if (ctx.featureFlags.getBoolean('addMissingOwnerFields', true)) { - const object = ctx.getObject(typeName); - const ownerRules = rules.filter((rule) => rule.allow === 'owner'); - const existingFields = Object.keys(getFieldArguments(object)); - const ownerFields = Array.from(new Set(ownerRules.map((rule) => rule.ownerField || DEFAULT_OWNER_FIELD)).values()); - const fieldsToAdd = ownerFields.filter((field) => !existingFields.includes(field)); - const modelType: any = ctx.getType(object.name.value); - if (fieldsToAdd.length) { - for (let ownerField of fieldsToAdd) { - modelType.fields.push(makeField(ownerField, [], makeNamedType('String'))); - } - ctx.putType(modelType); - } - } - } - - private addOwner(ctx: TransformerContext, parent: string) { - if (ctx.featureFlags.getBoolean('addMissingOwnerFields', true)) { - // owner field is already added, return - return; - } - const modelType: any = ctx.getType(parent); - const fields = getFieldArguments(modelType); - if (!('owner' in fields)) { - modelType.fields.push(makeField(DEFAULT_OWNER_FIELD, [], makeNamedType('String'))); - } - ctx.putType(modelType); - } - - private getOwnerRules(rules: AuthRule[]): AuthRule[] { - return rules.filter((rule) => rule.allow === 'owner'); - } - - private getStaticGroupRules(rules: AuthRule[]): AuthRule[] { - return rules.filter((rule) => rule.allow === 'groups' && Boolean(rule.groups)); - } - - private getDynamicGroupRules(rules: AuthRule[]): AuthRule[] { - return rules.filter((rule) => rule.allow === 'groups' && !Boolean(rule.groups)); - } - - public hasProviderAuthRules(rules: AuthRule[]): Boolean { - return rules.filter((rule) => rule.provider === 'userPools' && (rule.allow === 'public' || rule.allow === 'private')).length > 0; - } - - private extendTypeWithDirectives(ctx: TransformerContext, typeName: string, directives: DirectiveNode[]) { - let objectTypeExtension = blankObjectExtension(typeName); - - objectTypeExtension = extensionWithDirectives(objectTypeExtension, directives); - - ctx.addObjectExtension(objectTypeExtension); - } - - private addDirectivesToOperation(ctx: TransformerContext, typeName: string, operationName: string, directives: DirectiveNode[]) { - // Add the directives to the given operation - this.addDirectivesToField(ctx, typeName, operationName, directives); - - // Add the directives to the result type of the operation; - const type = ctx.getType(typeName) as ObjectTypeDefinitionNode; - - if (type) { - const field = type.fields.find((f) => f.name.value === operationName); - - if (field) { - const returnFieldType = field.type as NamedTypeNode; - - if (returnFieldType.name) { - const returnTypeName = returnFieldType.name.value; - - this.extendTypeWithDirectives(ctx, returnTypeName, directives); - } - } - } - } - - private addDirectivesToField(ctx: TransformerContext, typeName: string, fieldName: string, directives: DirectiveNode[]) { - const type = ctx.getType(typeName) as ObjectTypeDefinitionNode; - - if (type) { - const field = type.fields.find((f) => f.name.value === fieldName); - - if (field) { - const newFields = [...type.fields.filter((f) => f.name.value !== field.name.value), extendFieldWithDirectives(field, directives)]; - - const newMutation = { - ...type, - fields: newFields, - }; - - ctx.putType(newMutation); - } - } - } - - private extendAuthRulesForAdminUI(rules: Readonly): AuthRule[] { - // Check for Amplify Admin - if (this.isAdminUIEnabled()) { - return [...rules, { allow: 'private', provider: 'iam', generateIAMPolicy: false }]; - } - return [...rules]; - } - - private getDirectivesForRules(rules: Readonly, addDefaultIfNeeded: boolean = true): DirectiveNode[] { - if (!rules || rules.length === 0) { - return []; - } - - const directives: DirectiveNode[] = new Array(); - - // - // We only add a directive if it is not the default auth or - // if it is the default one, but there are other rules for a - // different provider. - // For fields we don't add the default, since it would open up - // the access rights. - // - - const addDirectiveIfNeeded = (provider: AuthProvider, directiveName: string) => { - if ( - (this.configuredAuthProviders.default !== provider && Boolean(rules.find((r) => r.provider === provider))) || - (this.configuredAuthProviders.default === provider && - Boolean(rules.find((r) => r.provider !== provider && addDefaultIfNeeded === true))) - ) { - directives.push(makeDirective(directiveName, [])); - } - }; - - const authProviderDirectiveMap = new Map([ - ['apiKey', 'aws_api_key'], - ['iam', 'aws_iam'], - ['oidc', 'aws_oidc'], - ['userPools', 'aws_cognito_user_pools'], - ]); - - for (const entry of authProviderDirectiveMap.entries()) { - addDirectiveIfNeeded(entry[0], entry[1]); - } - - // - // If we've any rules for other than the default provider AND - // we've rules for the default provider as well add the default provider's - // directive, regardless of the addDefaultIfNeeded flag. - // - // For example if we've this rule and the default is API_KEY: - // - // @auth(rules: [{allow: owner},{allow: public, operations: [read]}]) - // - // Then we need to add @aws_api_key on the create mutation together with the - // @aws_cognito_user_pools, but we cannot add @aws_api_key to other operations - // since that is not allowed by the rule. - // - - if ( - Boolean(rules.find((r) => r.provider === this.configuredAuthProviders.default)) && - Boolean( - rules.find((r) => r.provider !== this.configuredAuthProviders.default) && - !Boolean(directives.find((d) => d.name.value === authProviderDirectiveMap.get(this.configuredAuthProviders.default))), - ) - ) { - directives.push(makeDirective(authProviderDirectiveMap.get(this.configuredAuthProviders.default), [])); - } - - return directives; - } - - private ensureDefaultAuthProviderAssigned(rules: AuthRule[]) { - // We assign the default provider if an override is not present make further handling easier. - for (const rule of rules) { - if (!rule.provider) { - switch (rule.allow) { - case 'owner': - case 'groups': - rule.provider = 'userPools'; - break; - case 'private': - rule.provider = 'userPools'; - break; - case 'public': - rule.provider = 'apiKey'; - break; - default: - rule.provider = null; - break; - } - } - } - } - - private validateRuleAuthStrategy(rule: AuthRule) { - // - // Groups - // - - if (rule.allow === 'groups' && rule.provider !== 'userPools' && rule.provider !== 'oidc') { - throw new InvalidDirectiveError( - `@auth directive with 'groups' strategy only supports 'userPools' and 'oidc' providers, but found '${rule.provider}' assigned.`, - ); - } - - // - // Owner - // - - if (rule.allow === 'owner') { - if (rule.provider !== null && rule.provider !== 'userPools' && rule.provider !== 'oidc') { - throw new InvalidDirectiveError( - `@auth directive with 'owner' strategy only supports 'userPools' (default) and 'oidc' providers, but \ -found '${rule.provider}' assigned.`, - ); - } - } - - // - // Public - // - - if (rule.allow === 'public') { - if (rule.provider !== null && rule.provider !== 'apiKey' && rule.provider !== 'iam') { - throw new InvalidDirectiveError( - `@auth directive with 'public' strategy only supports 'apiKey' (default) and 'iam' providers, but \ -found '${rule.provider}' assigned.`, - ); - } - } - - // - // Private - // - - if (rule.allow === 'private') { - if (rule.provider !== null && rule.provider !== 'userPools' && rule.provider !== 'iam') { - throw new InvalidDirectiveError( - `@auth directive with 'private' strategy only supports 'userPools' (default) and 'iam' providers, but \ -found '${rule.provider}' assigned.`, - ); - } - } - - // - // Validate provider values against project configuration. - // - - if (rule.provider === 'apiKey' && this.configuredAuthProviders.hasApiKey === false) { - throw new InvalidDirectiveError( - `@auth directive with 'apiKey' provider found, but the project has no API Key authentication provider configured.`, - ); - } else if (rule.provider === 'oidc' && this.configuredAuthProviders.hasOIDC === false) { - throw new InvalidDirectiveError( - `@auth directive with 'oidc' provider found, but the project has no OPENID_CONNECT authentication provider configured.`, - ); - } else if (rule.provider === 'userPools' && this.configuredAuthProviders.hasUserPools === false) { - throw new InvalidDirectiveError( - `@auth directive with 'userPools' provider found, but the project has no Cognito User Pools authentication provider configured.`, - ); - } else if (rule.provider === 'iam' && this.configuredAuthProviders.hasIAM === false) { - throw new InvalidDirectiveError( - `@auth directive with 'iam' provider found, but the project has no IAM authentication provider configured.`, - ); - } - } - - private getConfiguredAuthProviders(): ConfiguredAuthProviders { - const providers = [ - this.config.authConfig.defaultAuthentication.authenticationType, - ...this.config.authConfig.additionalAuthenticationProviders.map((p) => p.authenticationType), - ]; - - const getAuthProvider = (authType: AppSyncAuthMode): AuthProvider => { - switch (authType) { - case 'AMAZON_COGNITO_USER_POOLS': - return 'userPools'; - case 'API_KEY': - return 'apiKey'; - case 'AWS_IAM': - return 'iam'; - case 'OPENID_CONNECT': - return 'oidc'; - } - }; - - return { - default: getAuthProvider(this.config.authConfig.defaultAuthentication.authenticationType), - onlyDefaultAuthProviderConfigured: this.config.authConfig.additionalAuthenticationProviders.length === 0, - hasApiKey: !!providers.find((p) => p === 'API_KEY'), - hasUserPools: !!providers.find((p) => p === 'AMAZON_COGNITO_USER_POOLS'), - hasOIDC: !!providers.find((p) => p === 'OPENID_CONNECT'), - hasIAM: !!providers.find((p) => p === 'AWS_IAM'), - }; - } - - private setAuthPolicyFlag(rules: AuthRule[]): void { - if (!rules || rules.length === 0 || this.generateIAMPolicyforAuthRole === true) { - return; - } - - for (const rule of rules) { - if ((rule.allow === 'private' || rule.allow === 'public') && rule.provider === 'iam') { - this.generateIAMPolicyforAuthRole = true; - return; - } - } - } - - private setUnauthPolicyFlag(rules: AuthRule[]): void { - if (!rules || rules.length === 0 || this.generateIAMPolicyforUnauthRole === true) { - return; - } - - for (const rule of rules) { - if (rule.allow === 'public' && rule.provider === 'iam') { - this.generateIAMPolicyforUnauthRole = true; - return; - } - } - } - - private getAuthRulesFromDirective(directive: DirectiveNode): AuthRule[] { - const get = (s: string) => (arg: ArgumentNode) => arg.name.value === s; - const getArg = (arg: string, dflt?: any) => { - const argument = directive.arguments.find(get(arg)); - return argument ? valueFromASTUntyped(argument.value) : dflt; - }; - - // Get and validate the auth rules. - const authRules = getArg('rules', []) as AuthRule[]; - - // All the IAM auth rules that are added using @auth directive need IAM policy to be generated. AuthRules added for AdminUI don't - return authRules.map((rule) => (rule.provider === 'iam' ? { ...rule, generateIAMPolicy: true } : rule)); - } - - private isTypeNeedsDefaultProviderAccess(def: ObjectTypeDefinitionNode): boolean { - const authDirective = def.directives.find((dir) => dir.name.value === 'auth'); - if (!authDirective) { - return true; - } - - // Get and validate the auth rules. - const rules = this.getAuthRulesFromDirective(authDirective); - // Assign default providers to rules where no provider was explicitly defined - this.ensureDefaultAuthProviderAssigned(rules); - - return Boolean(rules.find((r) => r.provider === this.configuredAuthProviders.default)); - } - - private doesTypeHaveRulesForOperation(def: ObjectTypeDefinitionNode, operation: ModelDirectiveOperationType): boolean { - const authDirective = def.directives.find((dir) => dir.name.value === 'auth'); - if (!authDirective) { - return this.shouldAddDefaultAuthDirective(); - } - - // Get and validate the auth rules. - const rules = this.getAuthRulesFromDirective(authDirective); - // Assign default providers to rules where no provider was explicitly defined - this.ensureDefaultAuthProviderAssigned(rules); - - const { operationRules, queryRules } = this.splitRules(rules); - - const hasRulesForDefaultProvider = (operationRules: AuthRule[]) => { - return Boolean(operationRules.find((r) => r.provider === this.configuredAuthProviders.default)); - }; - - switch (operation) { - case 'create': - return ( - hasRulesForDefaultProvider(operationRules.create) || (operationRules.create.length === 0 && this.shouldAddDefaultAuthDirective()) - ); - case 'update': - return ( - hasRulesForDefaultProvider(operationRules.update) || (operationRules.update.length === 0 && this.shouldAddDefaultAuthDirective()) - ); - case 'delete': - return ( - hasRulesForDefaultProvider(operationRules.delete) || (operationRules.delete.length === 0 && this.shouldAddDefaultAuthDirective()) - ); - case 'get': - return ( - hasRulesForDefaultProvider(operationRules.read) || - hasRulesForDefaultProvider(queryRules.get) || - (operationRules.read.length === 0 && queryRules.list.length === 0 && this.shouldAddDefaultAuthDirective()) - ); - case 'list': - return ( - hasRulesForDefaultProvider(operationRules.read) || - hasRulesForDefaultProvider(queryRules.list) || - (operationRules.read.length === 0 && queryRules.list.length === 0 && this.shouldAddDefaultAuthDirective()) - ); - } - - return false; - } - - private addTypeToResourceReferences(typeName: string, rules: AuthRule[]): void { - const iamPublicRules = rules.filter((r) => r.allow === 'public' && r.provider === 'iam' && r.generateIAMPolicy); - const iamPrivateRules = rules.filter((r) => r.allow === 'private' && r.provider === 'iam' && r.generateIAMPolicy); - - if (iamPublicRules.length > 0) { - this.unauthPolicyResources.add(`${typeName}/null`); - this.authPolicyResources.add(`${typeName}/null`); - } - if (iamPrivateRules.length > 0) { - this.authPolicyResources.add(`${typeName}/null`); - } - } - - private addFieldToResourceReferences(typeName: string, fieldName: string, rules: AuthRule[]): void { - const iamPublicRules = rules.filter((r) => r.allow === 'public' && r.provider === 'iam' && r.generateIAMPolicy); - const iamPrivateRules = rules.filter((r) => r.allow === 'private' && r.provider === 'iam' && r.generateIAMPolicy); - - if (iamPublicRules.length > 0) { - this.unauthPolicyResources.add(`${typeName}/${fieldName}`); - this.authPolicyResources.add(`${typeName}/${fieldName}`); - } - if (iamPrivateRules.length > 0) { - this.authPolicyResources.add(`${typeName}/${fieldName}`); - } - } - - private isOperationExpressionSet(operationTypeName: string, template: string): boolean { - return template.includes(`$ctx.result.put("operation", "${operationTypeName}")`); - } - - private updateMutationConditionInput(ctx: TransformerContext, type: ObjectTypeDefinitionNode, rules: Array): void { - // Get the existing ModelXConditionInput - const tableXMutationConditionInputName = ModelResourceIDs.ModelConditionInputTypeName(type.name.value); - - if (this.typeExist(tableXMutationConditionInputName, ctx)) { - const tableXMutationConditionInput = ctx.getType(tableXMutationConditionInputName); - - const fieldNames = new Set(); - - // Get auth related field names from @auth directive rules - const getAuthFieldNames = (): void => { - if (rules.length > 0) { - // Process owner rules - const ownerRules = this.getOwnerRules(rules); - const ownerFieldNameArgs = ownerRules.filter((rule) => !!rule.ownerField).map((rule) => rule.ownerField); - - ownerFieldNameArgs.forEach((f: string) => fieldNames.add(f)); - - // Add 'owner' to field list if we've owner rules without ownerField argument - if (ownerRules.find((rule) => !rule.ownerField)) { - fieldNames.add('owner'); - } - - // Process owner rules - const groupsRules = rules.filter((rule) => rule.allow === 'groups'); - const groupFieldNameArgs = groupsRules.filter((rule) => !!rule.groupsField).map((rule) => rule.groupsField); - - groupFieldNameArgs.forEach((f: string) => fieldNames.add(f)); - - // Add 'groups' to field list if we've groups rules without groupsField argument - if (groupsRules.find((rule) => !rule.groupsField)) { - fieldNames.add('groups'); - } - } - }; - - getAuthFieldNames(); - - if (fieldNames.size > 0) { - const reducedFields = tableXMutationConditionInput.fields.filter((field) => !fieldNames.has(field.name.value)); - - const updatedInput = { - ...tableXMutationConditionInput, - fields: reducedFields, - }; - - ctx.putType(updatedInput); - } - } - } - - private isAdminUIEnabled(): boolean { - return this.configuredAuthProviders.hasIAM && this.config.addAwsIamAuthInOutputSchema; - } - - /** - * When AdminUI is enabled, all the types and operations get IAM auth. If the default auth mode is - * not IAM all the fields will need to have the default auth mode directive to ensure both IAM and deault - * auth modes are allowed to access - * default auth provider needs to be added if AdminUI is enabled and default auth type is not IAM - * @returns boolean - */ - private shouldAddDefaultAuthDirective(): boolean { - return this.isAdminUIEnabled() && this.config.authConfig.defaultAuthentication.authenticationType !== 'AWS_IAM'; - } - - private typeExist(type: string, ctx: TransformerContext): boolean { - return Boolean(type in ctx.nodeMap); - } - - private isSyncEnabled(ctx: TransformerContext, typeName: string): boolean { - const resolverConfig = ctx.getResolverConfig(); - if (resolverConfig && resolverConfig.project) { - return true; - } - if (resolverConfig && resolverConfig.models && resolverConfig.models[typeName]) { - return true; - } - return false; - } -} - -function fieldHasDirective(field: FieldDefinitionNode, directiveName: string): boolean { - return ( - field.directives && field.directives.length && Boolean(field.directives.find((d: DirectiveNode) => d.name.value === directiveName)) - ); -} - -function isTruthyOrNull(obj: any): boolean { - return obj || obj === null; -} - -function isUndefined(obj: any): boolean { - return obj === undefined; -} diff --git a/packages/graphql-auth-transformer/src/ModelDirectiveConfiguration.ts b/packages/graphql-auth-transformer/src/ModelDirectiveConfiguration.ts deleted file mode 100644 index 673e78fd09..0000000000 --- a/packages/graphql-auth-transformer/src/ModelDirectiveConfiguration.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { getDirectiveArguments } from 'graphql-transformer-core'; -import { graphqlName, toUpper, plurality } from 'graphql-transformer-common'; -import { DirectiveNode, ObjectTypeDefinitionNode } from 'graphql'; -import { ModelQuery, ModelMutation } from './AuthRule'; - -export interface QueryNameMap { - get?: string; - list?: string; - query?: string; -} - -export interface MutationNameMap { - create?: string; - update?: string; - delete?: string; -} - -export type ModelSubscriptionLevel = 'off' | 'public' | 'on'; - -export interface SubscriptionNameMap { - onCreate?: string[]; - onUpdate?: string[]; - onDelete?: string[]; - level?: ModelSubscriptionLevel; -} - -export interface ModelDirectiveArgs { - queries?: QueryNameMap; - mutations?: MutationNameMap; - subscriptions?: SubscriptionNameMap; -} - -export type ModelDirectiveOperationType = ModelQuery | ModelMutation | 'onCreate' | 'onUpdate' | 'onDelete' | 'level'; - -type ModelDirectiveOperation = { - shouldHave: boolean; - name?: string; - names?: string[]; -}; - -export class ModelDirectiveConfiguration { - map: Map = new Map(); - - constructor(directive: DirectiveNode, def: ObjectTypeDefinitionNode, improvePluralization: boolean) { - const typeName = def.name.value; - const directiveArguments: ModelDirectiveArgs = getDirectiveArguments(directive); - - const makeName = (operation: ModelDirectiveOperationType, nameOverride?: string, isList: boolean = false) => - nameOverride - ? nameOverride - : graphqlName(operation + (isList ? plurality(toUpper(typeName), improvePluralization) : toUpper(typeName))); - - let shouldHaveCreate = true; - let shouldHaveUpdate = true; - let shouldHaveDelete = true; - let shouldHaveGet = true; - let shouldHaveList = true; - let shouldHaveOnCreate = true; - let shouldHaveOnUpdate = true; - let shouldHaveOnDelete = true; - let shouldHaveLevel = true; - let createName: string; - let updateName: string; - let deleteName: string; - let getName: string; - let listName: string; - let onCreateNames: string[] = []; - let onUpdateNames: string[] = []; - let onDeleteNames: string[] = []; - let level: ModelSubscriptionLevel = 'on'; - - // Figure out which mutations to make and if they have name overrides - if (directiveArguments.mutations === null) { - shouldHaveCreate = false; - shouldHaveUpdate = false; - shouldHaveDelete = false; - } else if (directiveArguments.mutations) { - if (!directiveArguments.mutations.create) { - shouldHaveCreate = false; - } else { - createName = makeName('create', directiveArguments.mutations.create); - } - if (!directiveArguments.mutations.update) { - shouldHaveUpdate = false; - } else { - updateName = makeName('update', directiveArguments.mutations.update); - } - if (!directiveArguments.mutations.delete) { - shouldHaveDelete = false; - } else { - deleteName = makeName('delete', directiveArguments.mutations.delete); - } - } else { - createName = makeName('create'); - updateName = makeName('update'); - deleteName = makeName('delete'); - } - - // Figure out which queries to make and if they have name overrides. - // If queries is undefined (default), create all queries - // If queries is explicetly set to null, do not create any - // else if queries is defined, check overrides - if (directiveArguments.queries === null) { - shouldHaveGet = false; - shouldHaveList = false; - } else if (directiveArguments.queries) { - if (!directiveArguments.queries.get) { - shouldHaveGet = false; - } else { - getName = makeName('get', directiveArguments.queries.get); - } - if (!directiveArguments.queries.list) { - shouldHaveList = false; - } else { - listName = makeName('list', directiveArguments.queries.list, true); - } - } else { - getName = makeName('get'); - listName = makeName('list', null, true); - } - - const subscriptions = directiveArguments.subscriptions; - if (subscriptions === null) { - shouldHaveOnCreate = false; - shouldHaveOnUpdate = false; - shouldHaveOnDelete = false; - level = 'off'; - } else if (subscriptions && (subscriptions.onCreate || subscriptions.onUpdate || subscriptions.onDelete)) { - if (!directiveArguments.subscriptions.onCreate) { - shouldHaveOnCreate = false; - } else { - directiveArguments.subscriptions.onCreate.forEach((name) => { - onCreateNames.push(makeName('onCreate', name)); - }); - } - if (!directiveArguments.subscriptions.onUpdate) { - shouldHaveOnUpdate = false; - } else { - directiveArguments.subscriptions.onUpdate.forEach((name) => { - onUpdateNames.push(makeName('onUpdate', name)); - }); - } - if (!directiveArguments.subscriptions.onDelete) { - shouldHaveOnDelete = false; - } else { - directiveArguments.subscriptions.onDelete.forEach((name) => { - onDeleteNames.push(makeName('onDelete', name)); - }); - } - } else { - onCreateNames.push(makeName('onCreate')); - onUpdateNames.push(makeName('onUpdate')); - onDeleteNames.push(makeName('onDelete')); - } - - // seperate check for level to see if it was specified in subscriptions - if (directiveArguments.subscriptions && directiveArguments.subscriptions.level) { - level = directiveArguments.subscriptions.level; - } - - // if a mutation operation is missing there shouldn't be subscription operation around it - shouldHaveOnCreate = shouldHaveCreate; - shouldHaveOnUpdate = shouldHaveUpdate; - shouldHaveOnDelete = shouldHaveDelete; - - this.map.set('create', { shouldHave: shouldHaveCreate, name: createName }); - this.map.set('update', { shouldHave: shouldHaveUpdate, name: updateName }); - this.map.set('delete', { shouldHave: shouldHaveDelete, name: deleteName }); - this.map.set('get', { shouldHave: shouldHaveGet, name: getName }); - this.map.set('list', { shouldHave: shouldHaveList, name: listName }); - this.map.set('onCreate', { shouldHave: shouldHaveOnCreate, names: onCreateNames }); - this.map.set('onUpdate', { shouldHave: shouldHaveOnUpdate, names: onUpdateNames }); - this.map.set('onDelete', { shouldHave: shouldHaveOnDelete, names: onDeleteNames }); - this.map.set('level', { shouldHave: shouldHaveLevel, name: level }); - } - - public shouldHave(op: ModelDirectiveOperationType): boolean { - return this.map.get(op).shouldHave; - } - - public getName(op: ModelDirectiveOperationType): string | undefined { - const { shouldHave, name } = this.map.get(op); - - if (shouldHave) { - return name; - } - } - - public getNames(op: ModelDirectiveOperationType): string[] | undefined { - const { shouldHave, names } = this.map.get(op); - - if (shouldHave) { - return names; - } - } -} diff --git a/packages/graphql-auth-transformer/src/__tests__/AmplifyAdminAuth.test.ts b/packages/graphql-auth-transformer/src/__tests__/AmplifyAdminAuth.test.ts deleted file mode 100644 index 7df213a3d8..0000000000 --- a/packages/graphql-auth-transformer/src/__tests__/AmplifyAdminAuth.test.ts +++ /dev/null @@ -1,324 +0,0 @@ -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import _ from 'lodash'; -import { ModelAuthTransformer } from '../ModelAuthTransformer'; - -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -test('simple model with public auth rule and amplify admin app is present', () => { - const validSchema = ` - type Post @model @auth(rules: [{allow: public}]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }, - addAwsIamAuthInOutputSchema: true, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.schema).toContain('Post @aws_api_key @aws_iam'); -}); - -test('simple model with public auth rule and amplify admin app is not enabled', () => { - const validSchema = ` - type Post @model @auth(rules: [{allow: public}]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }, - addAwsIamAuthInOutputSchema: false, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.schema).not.toContain('Post @aws_api_key @aws_iam'); -}); - -test('simple model with private auth rule and amplify admin app is present', () => { - const validSchema = ` - type Post @model @auth(rules: [{allow: groups, groups: ["Admin", "Dev"]}]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }, - addAwsIamAuthInOutputSchema: true, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.schema).toContain('Post @aws_iam @aws_cognito_user_pools'); -}); - -test('simple model with private auth rule and amplify admin app not enabled', () => { - const validSchema = ` - type Post @model @auth(rules: [{allow: groups, groups: ["Admin", "Dev"]}]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }, - addAwsIamAuthInOutputSchema: false, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.schema).not.toContain('Post @aws_cognito_user_pools @aws_iam'); -}); - -test('model with public auth rule without all operations and amplify admin app is present', () => { - const validSchema = ` - type Post @model @auth(rules: [{allow: public, operations: [read, update]}]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }, - addAwsIamAuthInOutputSchema: true, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - expect(out.schema).toContain('Post @aws_api_key @aws_iam'); - expect(out.schema).toContain('createPost(input: CreatePostInput!): Post @aws_api_key @aws_iam'); - expect(out.schema).toContain('deletePost(input: DeletePostInput!): Post @aws_api_key @aws_iam'); - expect(out.schema).toContain('updatePost(input: UpdatePostInput!): Post @aws_api_key @aws_iam'); - - // No parameter for Auth and UnAuth policy - expect(out.rootStack.Parameters.authRoleName).toBeUndefined(); - expect(out.rootStack.Parameters.unauthRoleName).toBeUndefined(); - - // No Resource extending Auth and UnAuth role - const policyResources = Object.values(out.rootStack.Resources).filter((r) => r.Type === 'AWS::IAM::ManagedPolicy'); - expect(policyResources).toHaveLength(0); -}); - -test('simple model with private auth rule, few operations, and amplify admin app enabled', () => { - const validSchema = ` - type Post @model @auth(rules: [{allow: groups, groups: ["Admin", "Dev"], operations: [read]}]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }, - addAwsIamAuthInOutputSchema: true, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.schema).toContain('Post @aws_iam @aws_cognito_user_pools'); - expect(out.schema).toContain('createPost(input: CreatePostInput!): Post @aws_iam'); - expect(out.schema).toContain('deletePost(input: DeletePostInput!): Post @aws_iam'); - expect(out.schema).toContain('updatePost(input: UpdatePostInput!): Post @aws_iam'); - - // No parameter for Auth and UnAuth policy - expect(out.rootStack.Parameters.authRoleName).toBeUndefined(); - expect(out.rootStack.Parameters.unauthRoleName).toBeUndefined(); - - // No Resource extending Auth and UnAuth role - const policyResources = Object.values(out.rootStack.Resources).filter((r) => r.Type === 'AWS::IAM::ManagedPolicy'); - expect(policyResources).toHaveLength(0); -}); - -test('simple model with private IAM auth rule, few operations, and amplify admin app is not enabled', () => { - const validSchema = ` - type Post @model @auth(rules: [{allow: private, provider: iam, operations: [read]}]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }, - addAwsIamAuthInOutputSchema: false, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.schema).toContain('Post @aws_iam'); - expect(out.schema).not.toContain('createPost(input: CreatePostInput!): Post @aws_iam'); - expect(out.schema).not.toContain('deletePost(input: DeletePostInput!): Post @aws_iam'); - expect(out.schema).not.toContain('updatePost(input: UpdatePostInput!): Post @aws_iam'); - - expect(out.schema).toContain('getPost(id: ID!): Post @aws_iam'); - expect(out.schema).toContain('listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection @aws_iam'); -}); - -test('simple model with AdminUI enabled should add IAM policy only for fields that have explicit IAM auth', () => { - const validSchema = ` - type Post @model @auth(rules: [{allow: private, provider: iam, operations: [read]}]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }, - addAwsIamAuthInOutputSchema: true, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.schema).toContain('Post @aws_iam @aws_cognito_user_pool'); - expect(out.schema).toContain('createPost(input: CreatePostInput!): Post @aws_iam @aws_cognito_user_pool'); - expect(out.schema).toContain('deletePost(input: DeletePostInput!): Post @aws_iam @aws_cognito_user_pool'); - expect(out.schema).toContain('updatePost(input: UpdatePostInput!): Post @aws_iam @aws_cognito_user_pool'); - - expect(out.schema).toContain('getPost(id: ID!): Post @aws_iam'); - expect(out.schema).toContain('listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection @aws_iam'); - const policyResources = _.filter(out.rootStack.Resources, (r) => r.Type === 'AWS::IAM::ManagedPolicy'); - expect(policyResources).toHaveLength(1); - const resources = _.get(policyResources, '[0].Properties.PolicyDocument.Statement[0].Resource'); - const typeFieldList = _.map(resources, (r) => _.get(r, 'Fn::Sub[1]')).map((r) => `${_.get(r, 'typeName')}.${_.get(r, 'fieldName', '*')}`); - expect(typeFieldList).toEqual([ - 'Post.*', - 'Query.getPost', - 'Query.listPosts', - 'Subscription.onCreatePost', - 'Subscription.onUpdatePost', - 'Subscription.onDeletePost', - ]); - - ['Mutation.createPost', 'Mutation.updatePost', 'Mutation.deletePost'].forEach((field) => expect(typeFieldList).not.toContain(field)); -}); diff --git a/packages/graphql-auth-transformer/src/__tests__/GroupAuthTransformer.test.ts b/packages/graphql-auth-transformer/src/__tests__/GroupAuthTransformer.test.ts deleted file mode 100644 index 9e11b975f0..0000000000 --- a/packages/graphql-auth-transformer/src/__tests__/GroupAuthTransformer.test.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { GraphQLTransform } from 'graphql-transformer-core'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelAuthTransformer } from '../ModelAuthTransformer'; - -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -test('ModelAuthTransformer validation happy case w/ static groups', () => { - const validSchema = ` - type Post @model @auth(rules: [{allow: groups, groups: ["Admin", "Dev"]}]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.rootStack.Resources[ResourceConstants.RESOURCES.GraphQLAPILogicalID].Properties.AuthenticationType).toEqual( - 'AMAZON_COGNITO_USER_POOLS', - ); -}); - -test('ModelAuthTransformer validation happy case w/ dynamic groups', () => { - const validSchema = ` - type Post @model @auth(rules: [{allow: groups, groupsField: "groups"}]) { - id: ID! - title: String! - groups: [String] - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.rootStack.Resources[ResourceConstants.RESOURCES.GraphQLAPILogicalID].Properties.AuthenticationType).toEqual( - 'AMAZON_COGNITO_USER_POOLS', - ); -}); - -test('ModelAuthTransformer validation happy case w/ dynamic group', () => { - const validSchema = ` - type Post @model @auth(rules: [{allow: groups, groupsField: "group"}]) { - id: ID! - title: String! - group: String - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.rootStack.Resources[ResourceConstants.RESOURCES.GraphQLAPILogicalID].Properties.AuthenticationType).toEqual( - 'AMAZON_COGNITO_USER_POOLS', - ); -}); - -test('ModelAuthTransformer validation @auth on non @model. Should fail.', () => { - try { - const validSchema = ` - type Post @auth(rules: [{allow: groups, groupsField: "groups"}]) { - id: ID! - title: String! - group: String - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(true).toEqual(false); - } catch (e) { - expect(e).toBeDefined(); - } -}); diff --git a/packages/graphql-auth-transformer/src/__tests__/MultiAuth.test.ts b/packages/graphql-auth-transformer/src/__tests__/MultiAuth.test.ts deleted file mode 100644 index c2efacedc8..0000000000 --- a/packages/graphql-auth-transformer/src/__tests__/MultiAuth.test.ts +++ /dev/null @@ -1,886 +0,0 @@ -import { ObjectTypeDefinitionNode, FieldDefinitionNode, parse, DocumentNode, Kind, InputValueDefinitionNode, NamedTypeNode } from 'graphql'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { ModelAuthTransformer, AppSyncAuthConfiguration, AppSyncAuthMode } from '../ModelAuthTransformer'; -import { KeyTransformer } from '../../../graphql-key-transformer/src/KeyTransformer'; - -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -const noAuthModeDefaultConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: undefined, - }, - additionalAuthenticationProviders: [], -}; - -const userPoolsDefaultConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], -}; - -const apiKeyDefaultConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], -}; - -const openIdDefaultConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'OPENID_CONNECT', - }, - additionalAuthenticationProviders: [], -}; - -const iamDefaultConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'AWS_IAM', - }, - additionalAuthenticationProviders: [], -}; - -const withAuthModes = (authConfig: AppSyncAuthConfiguration, authModes: AppSyncAuthMode[]): AppSyncAuthConfiguration => { - const newAuthConfig = { - defaultAuthentication: { - authenticationType: authConfig.defaultAuthentication.authenticationType, - }, - additionalAuthenticationProviders: [], - }; - - for (const authMode of authModes) { - newAuthConfig.additionalAuthenticationProviders.push({ - authenticationType: authMode, - }); - } - - return newAuthConfig; -}; - -const apiKeyDirectiveName = 'aws_api_key'; -const userPoolsDirectiveName = 'aws_cognito_user_pools'; -const iamDirectiveName = 'aws_iam'; -const openIdDirectiveName = 'aws_oidc'; - -const multiAuthDirective = - '@auth(rules: [{allow: private}, {allow: public}, {allow: private, provider: iam }, {allow: owner, provider: oidc }])'; -const ownerAuthDirective = '@auth(rules: [{allow: owner}])'; -const ownerWithIAMAuthDirective = '@auth(rules: [{allow: owner, provider: iam }])'; -const ownerRestrictedPublicAuthDirective = '@auth(rules: [{allow: owner},{allow: public, operations: [read]}])'; -const ownerRestrictedIAMPrivateAuthDirective = '@auth(rules: [{allow: owner},{allow: private, operations: [read], provider: iam }])'; -const groupsAuthDirective = '@auth(rules: [{allow: groups}])'; -const groupsWithApiKeyAuthDirective = '@auth(rules: [{allow: groups}, {allow: public, operations: [read]}])'; -const groupsWithProviderAuthDirective = '@auth(rules: [{allow: groups, provider: iam }])'; -const ownerOpenIdAuthDirective = '@auth(rules: [{allow: owner, provider: oidc }])'; -const privateAuthDirective = '@auth(rules: [{allow: private}])'; -const publicIAMAuthDirective = '@auth(rules: [{allow: public, provider: iam }])'; -const privateWithApiKeyAuthDirective = '@auth(rules: [{allow: private, provider: apiKey }])'; -const publicAuthDirective = '@auth(rules: [{allow: public}])'; -const publicUserPoolsAuthDirective = '@auth(rules: [{allow: public, provider: userPools}])'; -const privateAndPublicDirective = '@auth(rules: [{allow: private}, {allow: public}])'; -const privateAndPrivateIAMDirective = '@auth(rules: [{allow: private}, {allow: private, provider: iam}])'; -const privateIAMDirective = '@auth(rules: [{allow: private, provider: iam}])'; - -const getSchema = (authDirective: string) => { - return ` - type Post @model ${authDirective} { - id: ID! - title: String! - createdAt: String - updatedAt: String - }`; -}; - -const getSchemaWithFieldAuth = (authDirective: string) => { - return ` - type Post @model { - id: ID! - title: String! - createdAt: String - updatedAt: String - protected: String ${authDirective} - }`; -}; - -const getSchemaWithTypeAndFieldAuth = (typeAuthDirective: string, fieldAuthDirective: string) => { - return ` - type Post @model ${typeAuthDirective} { - id: ID! - title: String! - createdAt: String - updatedAt: String - protected: String ${fieldAuthDirective} - }`; -}; - -const getSchemaWithNonModelField = (authDirective: string) => { - return ` - type Post @model ${authDirective} { - id: ID! - title: String! - location: Location - status: Status - createdAt: String - updatedAt: String - } - - type Location { - name: String - address: Address - } - - type Address { - street: String - city: String - state: String - zip: String - } - - enum Status { - PUBLISHED, - DRAFT - }`; -}; - -const getSchemaWithRecursiveNonModelField = (authDirective: string) => { - return ` - type Post @model ${authDirective} { - id: ID! - title: String! - tags: [Tag] - } - - type Tag { - id: ID - tags: [Tag] - } - `; -}; - -const getRecursiveSchemaWithDiffModesOnParentType = (authDir1: string, authDir2: string) => { - return ` - type Post @model ${authDir1} { - id: ID! - title: String! - tags: [Tag] - } - - type Comment @model ${authDir2} { - id: ID! - content: String - tags: [Tag] - } - - type Tag { - id: ID - tags: [Tag] - } - `; -}; - -const getTransformer = (authConfig: AppSyncAuthConfiguration) => - new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new KeyTransformer(), - new ModelConnectionTransformer(), - new ModelAuthTransformer({ authConfig }), - ], - }); - -const getObjectType = (doc: DocumentNode, type: string): ObjectTypeDefinitionNode | undefined => { - return doc.definitions.find((def) => def.kind === Kind.OBJECT_TYPE_DEFINITION && def.name.value === type) as - | ObjectTypeDefinitionNode - | undefined; -}; - -const expectNone = (fieldOrType) => { - expect(fieldOrType.directives.length === 0); -}; - -const expectOne = (fieldOrType, directiveName) => { - expect(fieldOrType.directives.length).toBe(1); - expect(fieldOrType.directives.find((d) => d.name.value === directiveName)).toBeDefined(); -}; - -const expectTwo = (fieldOrType, directiveNames) => { - expect(directiveNames).toBeDefined(); - expect(directiveNames).toHaveLength(2); - expect(fieldOrType.directives.length === 2); - expect(fieldOrType.directives.find((d) => d.name.value === directiveNames[0])).toBeDefined(); - expect(fieldOrType.directives.find((d) => d.name.value === directiveNames[1])).toBeDefined(); -}; - -const expectMultiple = (fieldOrType: ObjectTypeDefinitionNode | FieldDefinitionNode, directiveNames: string[]) => { - expect(directiveNames).toBeDefined(); - expect(directiveNames).toHaveLength(directiveNames.length); - expect(fieldOrType.directives.length).toEqual(directiveNames.length); - directiveNames.forEach((directiveName) => { - expect(fieldOrType.directives).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - name: expect.objectContaining({ value: directiveName }), - }), - ]), - ); - }); -}; - -const getField = (type, name) => type.fields.find((f) => f.name.value === name); - -describe('Validation tests', () => { - const validationTest = (authDirective, authConfig, expectedError) => { - const schema = getSchema(authDirective); - const transformer = getTransformer(authConfig); - - const t = () => { - const out = transformer.transform(schema); - }; - - expect(t).toThrowError(expectedError); - }; - - test('AMAZON_COGNITO_USER_POOLS not configured for project', () => { - validationTest( - privateAuthDirective, - apiKeyDefaultConfig, - `@auth directive with 'userPools' provider found, but the project has no Cognito User \ -Pools authentication provider configured.`, - ); - }); - - test('API_KEY not configured for project', () => { - validationTest( - publicAuthDirective, - userPoolsDefaultConfig, - `@auth directive with 'apiKey' provider found, but the project has no API Key \ -authentication provider configured.`, - ); - }); - - test('AWS_IAM not configured for project', () => { - validationTest( - publicIAMAuthDirective, - userPoolsDefaultConfig, - `@auth directive with 'iam' provider found, but the project has no IAM \ -authentication provider configured.`, - ); - }); - - test('OPENID_CONNECT not configured for project', () => { - validationTest( - ownerOpenIdAuthDirective, - userPoolsDefaultConfig, - `@auth directive with 'oidc' provider found, but the project has no OPENID_CONNECT \ -authentication provider configured.`, - ); - }); - - test(`'group' cannot have provider`, () => { - validationTest( - groupsWithProviderAuthDirective, - userPoolsDefaultConfig, - `@auth directive with 'groups' strategy only supports 'userPools' and 'oidc' providers, but found \ -'iam' assigned`, - ); - }); - - test(`'owner' has invalid IAM provider`, () => { - validationTest( - ownerWithIAMAuthDirective, - userPoolsDefaultConfig, - `@auth directive with 'owner' strategy only supports 'userPools' (default) and \ -'oidc' providers, but found 'iam' assigned.`, - ); - }); - - test(`'public' has invalid 'userPools' provider`, () => { - validationTest( - publicUserPoolsAuthDirective, - userPoolsDefaultConfig, - `@auth directive with 'public' strategy only supports 'apiKey' (default) and 'iam' providers, but \ -found 'userPools' assigned.`, - ); - }); - - test(`'private' has invalid 'apiKey' provider`, () => { - validationTest( - privateWithApiKeyAuthDirective, - userPoolsDefaultConfig, - `@auth directive with 'private' strategy only supports 'userPools' (default) and 'iam' providers, but \ -found 'apiKey' assigned.`, - ); - }); -}); - -describe('Type directive transformation tests', () => { - const transformTest = (authDirective, authConfig, expectedDirectiveNames?: string[] | undefined) => { - const schema = getSchema(authDirective); - const transformer = getTransformer(authConfig); - - const out = transformer.transform(schema); - - const schemaDoc = parse(out.schema); - - const postType = getObjectType(schemaDoc, 'Post'); - - if (expectedDirectiveNames && expectedDirectiveNames.length > 0) { - let expectedDireciveNameCount = 0; - - for (const expectedDirectiveName of expectedDirectiveNames) { - expect(postType.directives.find((d) => d.name.value === expectedDirectiveName)).toBeDefined(); - expectedDireciveNameCount++; - } - - expect(expectedDireciveNameCount).toEqual(postType.directives.length); - } - }; - - test(`When provider is the same as default, then no directive added`, () => { - transformTest(ownerAuthDirective, userPoolsDefaultConfig); - }); - - // Disabling until troubleshooting the changes - // test(`When provider is not the same as default directive is added`, () => { - // transformTest( - // ownerAuthDirective, - // withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS']), - // [userPoolsDirectiveName, apiKeyDirectiveName] - // ); - // }); - - test(`When all providers are configured all of them are added`, () => { - const authConfig = withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS', 'AWS_IAM', 'OPENID_CONNECT']); - - authConfig.additionalAuthenticationProviders[2].openIDConnectConfig = { - name: 'Test Provider', - issuerUrl: 'https://abc.def/', - }; - - transformTest(multiAuthDirective, authConfig, [userPoolsDirectiveName, iamDirectiveName, openIdDirectiveName, apiKeyDirectiveName]); - }); - - test(`Operation fields are getting the directive added, when type has the @auth for all operations`, () => { - const schema = getSchema(ownerAuthDirective); - const transformer = getTransformer(withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); - - const out = transformer.transform(schema); - const schemaDoc = parse(out.schema); - const queryType = getObjectType(schemaDoc, 'Query'); - const mutationType = getObjectType(schemaDoc, 'Mutation'); - const subscriptionType = getObjectType(schemaDoc, 'Subscription'); - - const fields = [...queryType.fields, ...mutationType.fields]; - - for (const field of fields) { - expect(field.directives.length === 1); - expect(field.directives.find((d) => d.name.value === userPoolsDirectiveName)).toBeDefined(); - } - - // Check that owner is required when only using owner auth rules - for (const field of subscriptionType.fields) { - expect(field.arguments).toHaveLength(1); - let arg: InputValueDefinitionNode = field.arguments[0]; - expect(arg.name.value).toEqual('owner'); - expect(arg.type.kind).toEqual(Kind.NON_NULL_TYPE); - } - - // Check that resolvers containing the authMode check block - const authModeCheckSnippet = '## [Start] Determine request authentication mode'; - - expect(out.resolvers['Query.getPost.res.vtl']).toContain(authModeCheckSnippet); - expect(out.resolvers['Query.listPosts.res.vtl']).toContain(authModeCheckSnippet); - expect(out.resolvers['Mutation.createPost.req.vtl']).toContain(authModeCheckSnippet); - expect(out.resolvers['Mutation.updatePost.req.vtl']).toContain(authModeCheckSnippet); - expect(out.resolvers['Mutation.deletePost.req.vtl']).toContain(authModeCheckSnippet); - }); - - test(`Operation fields are getting the directive added, when type has the @auth only for allowed operations`, () => { - const schema = getSchema(ownerRestrictedPublicAuthDirective); - const transformer = getTransformer(withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); - - const out = transformer.transform(schema); - const schemaDoc = parse(out.schema); - const queryType = getObjectType(schemaDoc, 'Query'); - const mutationType = getObjectType(schemaDoc, 'Mutation'); - const subscriptionType = getObjectType(schemaDoc, 'Subscription'); - - expectTwo(getField(queryType, 'getPost'), ['aws_cognito_user_pools', 'aws_api_key']); - expectTwo(getField(queryType, 'listPosts'), ['aws_cognito_user_pools', 'aws_api_key']); - - expectOne(getField(mutationType, 'createPost'), 'aws_cognito_user_pools'); - expectOne(getField(mutationType, 'updatePost'), 'aws_cognito_user_pools'); - expectOne(getField(mutationType, 'deletePost'), 'aws_cognito_user_pools'); - - const onCreate = getField(subscriptionType, 'onCreatePost'); - expectMultiple(onCreate, ['aws_subscribe', 'aws_api_key', 'aws_cognito_user_pools']); - expectMultiple(getField(subscriptionType, 'onUpdatePost'), ['aws_subscribe', 'aws_api_key', 'aws_cognito_user_pools']); - expectMultiple(getField(subscriptionType, 'onDeletePost'), ['aws_subscribe', 'aws_api_key', 'aws_cognito_user_pools']); - expect(onCreate.arguments).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - name: expect.objectContaining({ value: 'owner' }), - type: expect.objectContaining({ kind: 'NamedType' }), - }), - ]), - ); - }); - - test(`'public' with IAM provider adds policy for Unauth role`, () => { - const schema = getSchema(publicIAMAuthDirective); - const transformer = getTransformer(withAuthModes(userPoolsDefaultConfig, ['AWS_IAM'])); - - const out = transformer.transform(schema); - - expect(out.rootStack.Resources.UnauthRolePolicy01).toBeDefined(); - }); - - test(`Field level @auth is propagated to type and the type related operations`, () => { - const schema = getSchemaWithFieldAuth(ownerRestrictedPublicAuthDirective); - const transformer = getTransformer(withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); - - const out = transformer.transform(schema); - const schemaDoc = parse(out.schema); - const queryType = getObjectType(schemaDoc, 'Query'); - const mutationType = getObjectType(schemaDoc, 'Mutation'); - - expectTwo(getField(queryType, 'getPost'), ['aws_cognito_user_pools', 'aws_api_key']); - expectTwo(getField(queryType, 'listPosts'), ['aws_cognito_user_pools', 'aws_api_key']); - - expectOne(getField(mutationType, 'createPost'), 'aws_cognito_user_pools'); - expectOne(getField(mutationType, 'updatePost'), 'aws_cognito_user_pools'); - expectOne(getField(mutationType, 'deletePost'), 'aws_cognito_user_pools'); - - const postType = getObjectType(schemaDoc, 'Post'); - expectTwo(getField(postType, 'protected'), ['aws_cognito_user_pools', 'aws_api_key']); - - // Check that resolvers containing the authMode check block - const authModeCheckSnippet = '## [Start] Determine request authentication mode'; - - expect(out.resolvers['Post.protected.req.vtl']).toContain(authModeCheckSnippet); - }); - - test(`'groups' @auth at field level is propagated to type and the type related operations`, () => { - const schema = getSchemaWithFieldAuth(groupsAuthDirective); - const transformer = getTransformer(withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); - - const out = transformer.transform(schema); - const schemaDoc = parse(out.schema); - const queryType = getObjectType(schemaDoc, 'Query'); - const mutationType = getObjectType(schemaDoc, 'Mutation'); - - expectOne(getField(queryType, 'getPost'), 'aws_cognito_user_pools'); - expectOne(getField(queryType, 'listPosts'), 'aws_cognito_user_pools'); - - expectOne(getField(mutationType, 'createPost'), 'aws_cognito_user_pools'); - expectOne(getField(mutationType, 'updatePost'), 'aws_cognito_user_pools'); - expectOne(getField(mutationType, 'deletePost'), 'aws_cognito_user_pools'); - - const postType = getObjectType(schemaDoc, 'Post'); - expectOne(getField(postType, 'protected'), 'aws_cognito_user_pools'); - - // Check that resolvers containing the authMode check block - const authModeCheckSnippet = '## [Start] Determine request authentication mode'; - - expect(out.resolvers['Post.protected.req.vtl']).toContain(authModeCheckSnippet); - }); - - test(`'groups' @auth at field level is propagated to type and the type related operations, also default provider for read`, () => { - const schema = getSchemaWithTypeAndFieldAuth(groupsAuthDirective, groupsWithApiKeyAuthDirective); - const transformer = getTransformer(withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); - - const out = transformer.transform(schema); - const schemaDoc = parse(out.schema); - const queryType = getObjectType(schemaDoc, 'Query'); - const mutationType = getObjectType(schemaDoc, 'Mutation'); - - expectTwo(getField(queryType, 'getPost'), ['aws_cognito_user_pools', 'aws_api_key']); - expectTwo(getField(queryType, 'listPosts'), ['aws_cognito_user_pools', 'aws_api_key']); - - expectOne(getField(mutationType, 'createPost'), 'aws_cognito_user_pools'); - expectOne(getField(mutationType, 'updatePost'), 'aws_cognito_user_pools'); - expectOne(getField(mutationType, 'deletePost'), 'aws_cognito_user_pools'); - - const postType = getObjectType(schemaDoc, 'Post'); - expectTwo(getField(postType, 'protected'), ['aws_cognito_user_pools', 'aws_api_key']); - - // Check that resolvers containing the authMode check block - const authModeCheckSnippet = '## [Start] Determine request authentication mode'; - - expect(out.resolvers['Post.protected.req.vtl']).toContain(authModeCheckSnippet); - }); - - test(`Nested types without @model getting directives applied (cognito default, api key additional)`, () => { - const schema = getSchemaWithNonModelField(privateAndPublicDirective); - const transformer = getTransformer(withAuthModes(userPoolsDefaultConfig, ['API_KEY'])); - - const out = transformer.transform(schema); - const schemaDoc = parse(out.schema); - - const locationType = getObjectType(schemaDoc, 'Location'); - const addressType = getObjectType(schemaDoc, 'Address'); - const expectedDirectiveNames = [userPoolsDirectiveName, apiKeyDirectiveName]; - - if (expectedDirectiveNames && expectedDirectiveNames.length > 0) { - let expectedDireciveNameCount = 0; - - for (const expectedDirectiveName of expectedDirectiveNames) { - expect(locationType.directives.find((d) => d.name.value === expectedDirectiveName)).toBeDefined(); - expectedDireciveNameCount++; - } - - expect(expectedDireciveNameCount).toEqual(locationType.directives.length); - - expectedDireciveNameCount = 0; - - for (const expectedDirectiveName of expectedDirectiveNames) { - expect(addressType.directives.find((d) => d.name.value === expectedDirectiveName)).toBeDefined(); - expectedDireciveNameCount++; - } - - expect(expectedDireciveNameCount).toEqual(addressType.directives.length); - } - }); - - test(`Recursive types without @model`, () => { - const schema = getSchemaWithRecursiveNonModelField(ownerRestrictedIAMPrivateAuthDirective); - const transformer = getTransformer(withAuthModes(userPoolsDefaultConfig, ['AWS_IAM'])); - - const out = transformer.transform(schema); - const schemaDoc = parse(out.schema); - - const tagType = getObjectType(schemaDoc, 'Tag'); - const expectedDirectiveNames = [userPoolsDirectiveName, iamDirectiveName]; - - expectMultiple(tagType, expectedDirectiveNames); - }); - - test(`Recursive types with diff auth modes on parent @model types`, () => { - const schema = getRecursiveSchemaWithDiffModesOnParentType(ownerAuthDirective, privateIAMDirective); - const transformer = getTransformer(withAuthModes(userPoolsDefaultConfig, ['AWS_IAM'])); - - const out = transformer.transform(schema); - const schemaDoc = parse(out.schema); - - const tagType = getObjectType(schemaDoc, 'Tag'); - const expectedDirectiveNames = [userPoolsDirectiveName, iamDirectiveName]; - - expectMultiple(tagType, expectedDirectiveNames); - }); - - test(`Nested types without @model getting directives applied (cognito default, iam additional)`, () => { - const schema = getSchemaWithNonModelField(privateAndPrivateIAMDirective); - const transformer = getTransformer(withAuthModes(userPoolsDefaultConfig, ['AWS_IAM'])); - - const out = transformer.transform(schema); - const schemaDoc = parse(out.schema); - - const locationType = getObjectType(schemaDoc, 'Location'); - const addressType = getObjectType(schemaDoc, 'Address'); - const expectedDirectiveNames = [userPoolsDirectiveName, iamDirectiveName]; - - if (expectedDirectiveNames && expectedDirectiveNames.length > 0) { - let expectedDireciveNameCount = 0; - - for (const expectedDirectiveName of expectedDirectiveNames) { - expect(locationType.directives.find((d) => d.name.value === expectedDirectiveName)).toBeDefined(); - expectedDireciveNameCount++; - } - - expect(expectedDireciveNameCount).toEqual(locationType.directives.length); - - expectedDireciveNameCount = 0; - - for (const expectedDirectiveName of expectedDirectiveNames) { - expect(addressType.directives.find((d) => d.name.value === expectedDirectiveName)).toBeDefined(); - expectedDireciveNameCount++; - } - - expect(expectedDireciveNameCount).toEqual(addressType.directives.length); - - expect(out.rootStack.Resources.AuthRolePolicy01).toBeDefined(); - - const locationPolicy = out.rootStack.Resources.AuthRolePolicy01.Properties.PolicyDocument.Statement[0].Resource.filter( - (r) => - r['Fn::Sub'] && - r['Fn::Sub'].length && - r['Fn::Sub'].length === 2 && - r['Fn::Sub'][1].typeName && - r['Fn::Sub'][1].typeName === 'Location', - ); - expect(locationPolicy).toBeDefined(); - - const addressPolicy = out.rootStack.Resources.AuthRolePolicy01.Properties.PolicyDocument.Statement[0].Resource.filter( - (r) => - r['Fn::Sub'] && - r['Fn::Sub'].length && - r['Fn::Sub'].length === 2 && - r['Fn::Sub'][1].typeName && - r['Fn::Sub'][1].typeName === 'Address', - ); - expect(addressPolicy).toBeDefined(); - } - }); - - test(`Nested types without @model not getting directives applied for iam, and no policy is generated`, () => { - const schema = getSchemaWithNonModelField(''); - const transformer = getTransformer(withAuthModes(iamDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); - - const out = transformer.transform(schema); - const schemaDoc = parse(out.schema); - - const locationType = getObjectType(schemaDoc, 'Location'); - const addressType = getObjectType(schemaDoc, 'Address'); - - expect(locationType.directives.length).toBe(0); - expect(addressType.directives.length).toBe(0); - - expect(out.rootStack.Resources.AuthRolePolicy01).toBeUndefined(); - }); - - test(`Nested types without @model not getting directives applied for iam, but policy is generated`, () => { - const schema = getSchemaWithNonModelField(privateIAMDirective); - const transformer = getTransformer(withAuthModes(iamDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); - - const out = transformer.transform(schema); - const schemaDoc = parse(out.schema); - - const locationType = getObjectType(schemaDoc, 'Location'); - const addressType = getObjectType(schemaDoc, 'Address'); - - expect(locationType.directives.length).toBe(0); - expect(addressType.directives.length).toBe(0); - - expect(out.rootStack.Resources.AuthRolePolicy01).toBeDefined(); - - const locationPolicy = out.rootStack.Resources.AuthRolePolicy01.Properties.PolicyDocument.Statement[0].Resource.filter( - (r) => - r['Fn::Sub'] && - r['Fn::Sub'].length && - r['Fn::Sub'].length === 2 && - r['Fn::Sub'][1].typeName && - r['Fn::Sub'][1].typeName === 'Location', - ); - expect(locationPolicy).toBeDefined(); - - const addressPolicy = out.rootStack.Resources.AuthRolePolicy01.Properties.PolicyDocument.Statement[0].Resource.filter( - (r) => - r['Fn::Sub'] && - r['Fn::Sub'].length && - r['Fn::Sub'].length === 2 && - r['Fn::Sub'][1].typeName && - r['Fn::Sub'][1].typeName === 'Address', - ); - expect(addressPolicy).toBeDefined(); - }); - - // Disabling until troubleshooting the changes - // test(`Connected type is also getting the directives added, when a field has @connection`, () => { - // const schema = ` - // type Post @model @auth(rules:[{allow: private}]){ - // id: ID! - // title: String! - // comments: [Comment] @connection(name: "PostComments") - // } - - // type Comment @model { - // id: ID! - // content: String! - // post: Post @connection(name: "PostComments") - // } - // `; - - // const transformer = getTransformer(withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); - // const out = transformer.transform(schema); - // const schemaDoc = parse(out.schema); - // const queryType = getObjectType(schemaDoc, 'Query'); - // const mutationType = getObjectType(schemaDoc, 'Mutation'); - - // expect (expectOne(getField(queryType, 'getPost'), 'aws_cognito_user_pools')); - // expect (expectOne(getField(queryType, 'listPosts'), 'aws_cognito_user_pools')); - - // expect (expectOne(getField(mutationType, 'createPost'), 'aws_cognito_user_pools')); - // expect (expectOne(getField(mutationType, 'updatePost'), 'aws_cognito_user_pools')); - // expect (expectOne(getField(mutationType, 'deletePost'), 'aws_cognito_user_pools')); - - // const postType = getObjectType(schemaDoc, 'Post'); - // expect (expectTwo(postType, ['aws_api_key', 'aws_cognito_user_pools'])); - // expect (expectNone(getField(postType, 'comments'))); - - // const commentType = getObjectType(schemaDoc, 'Comment'); - // expect (expectOne(getField(commentType, 'post'), 'aws_cognito_user_pools')); - - // const modelPostConnectionType = getObjectType(schemaDoc, 'ModelPostConnection'); - // expect (expectOne(modelPostConnectionType, 'aws_cognito_user_pools')); - // }); - - test(`ModelXConnection type is getting the directives added, when a field has @connection but one of the types has no queries defined`, () => { - const schema = ` - type User @model - @auth(rules: [ - { allow: private, provider: iam, operations: [read] } - { allow: groups, groups: ["Group"], operations: [read, update, delete] }, - ]) { - id: ID! - posts: [Post!] @connection(keyName:"byUser", fields: ["id"]) - } - - type Post @model( - queries: null) - @auth(rules: [ - { allow: private, provider: iam, operations: [read] }, - { allow: groups, groups: ["Group"], operations: [read, update, delete] } - ]) - @key(name: "byUser", fields: ["postUserId"]) - { - id: ID! - postUserId: ID! - message: String - } - `; - - const transformer = getTransformer(withAuthModes(iamDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); - const out = transformer.transform(schema); - const schemaDoc = parse(out.schema); - const queryType = getObjectType(schemaDoc, 'Query'); - const mutationType = getObjectType(schemaDoc, 'Mutation'); - - expectTwo(getField(queryType, 'getUser'), ['aws_iam', 'aws_cognito_user_pools']); - expectTwo(getField(queryType, 'listUsers'), ['aws_iam', 'aws_cognito_user_pools']); - - expectNone(getField(mutationType, 'createUser')); - expectOne(getField(mutationType, 'updateUser'), 'aws_cognito_user_pools'); - expectOne(getField(mutationType, 'deleteUser'), 'aws_cognito_user_pools'); - - const userType = getObjectType(schemaDoc, 'User'); - expectTwo(userType, ['aws_iam', 'aws_cognito_user_pools']); - expectNone(getField(userType, 'posts')); - - const modelPostConnectionType = getObjectType(schemaDoc, 'ModelPostConnection'); - expect(modelPostConnectionType).toBeDefined(); - expectTwo(modelPostConnectionType, ['aws_iam', 'aws_cognito_user_pools']); - }); - - test(`ModelXConnection type is getting the directives added, when a field has @connection but one of the types has no queries defined. Many to Many`, () => { - const schema = ` - type Post @model @auth(rules: [{ allow: owner }]) { - id: ID! - title: String! - editors: [PostEditor] @connection(keyName: "byPost", fields: ["id"]) - } - - # Create a join model and disable queries as you don't need them - # and can query through Post.editors and User.posts - type PostEditor - @model(queries: null) - @auth(rules: [{ allow: owner }]) - @key(name: "byPost", fields: ["postID", "editorID"]) - @key(name: "byEditor", fields: ["editorID", "postID"]) { - id: ID! - postID: ID! - editorID: ID! - post: Post! @connection(fields: ["postID"]) - editor: User! @connection(fields: ["editorID"]) - } - - type User @model @auth(rules: [{ allow: owner }]) { - id: ID! - username: String! - posts: [PostEditor] @connection(keyName: "byEditor", fields: ["id"]) - } - `; - - const transformer = getTransformer(withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); - const out = transformer.transform(schema); - const schemaDoc = parse(out.schema); - - const modelPostEditorConnectionType = getObjectType(schemaDoc, 'ModelPostEditorConnection'); - expect(modelPostEditorConnectionType).toBeDefined(); - expectOne(modelPostEditorConnectionType, 'aws_cognito_user_pools'); - }); -}); - -describe(`Policy slicing tests`, () => { - test(`'For the long Todo type there should be 2 auth role managed policies generated`, () => { - const schema = ` - type TodoWithExtraLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongName @model(subscriptions:null) @auth(rules:[{allow: private, provider: iam}]) - { - id: ID! - namenamenamenamenamenamenamenamenamenamenamenamenamenamename001: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename002: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename003: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename004: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename005: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename006: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename007: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename008: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename009: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename010: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename011: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename012: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename013: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename014: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename015: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename016: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename017: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename018: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename019: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename020: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename021: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename022: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename023: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename024: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename025: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename026: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename027: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename028: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename029: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename030: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename031: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename032: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename033: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename034: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename035: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename036: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename037: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename038: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename039: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename040: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename041: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename042: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename043: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename044: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename045: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename046: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename047: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename048: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename049: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename050: String! @auth(rules:[{allow: private, provider: iam}]) - description: String - } - `; - const authConfig = withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS', 'AWS_IAM']); - const transformer = getTransformer(authConfig); - const out = transformer.transform(schema); - - expect(out.rootStack.Resources.AuthRolePolicy01).toBeTruthy(); - expect(out.rootStack.Resources.AuthRolePolicy01.Properties.PolicyDocument.Statement[0].Resource.length).toEqual(26); - expect(out.rootStack.Resources.AuthRolePolicy02).toBeTruthy(); - expect(out.rootStack.Resources.AuthRolePolicy02.Properties.PolicyDocument.Statement[0].Resource.length).toEqual(26); - expect(out.rootStack.Resources.AuthRolePolicy03).toBeTruthy(); - expect(out.rootStack.Resources.AuthRolePolicy03.Properties.PolicyDocument.Statement[0].Resource.length).toEqual(4); - expect(out.rootStack.Resources.UnauthRolePolicy01).toBeFalsy(); - }); -}); diff --git a/packages/graphql-auth-transformer/src/__tests__/NonModelAuthTransformer.test.ts b/packages/graphql-auth-transformer/src/__tests__/NonModelAuthTransformer.test.ts deleted file mode 100644 index b9ce5479f7..0000000000 --- a/packages/graphql-auth-transformer/src/__tests__/NonModelAuthTransformer.test.ts +++ /dev/null @@ -1,337 +0,0 @@ -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { FunctionTransformer } from 'graphql-function-transformer'; -import { ObjectTypeDefinitionNode, DocumentNode, Kind, parse, FieldDefinitionNode } from 'graphql'; -import { ModelAuthTransformer } from '../ModelAuthTransformer'; - -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -describe('@auth directive without @model', () => { - const getObjectType = (doc: DocumentNode, type: string): ObjectTypeDefinitionNode | undefined => { - return doc.definitions.find((def) => def.kind === Kind.OBJECT_TYPE_DEFINITION && def.name.value === type) as - | ObjectTypeDefinitionNode - | undefined; - }; - - const getField = (type: ObjectTypeDefinitionNode | undefined, name: string): FieldDefinitionNode | undefined => - type?.fields?.find((f) => f.name.value === name); - - const expectNone = (fieldOrType: ObjectTypeDefinitionNode | FieldDefinitionNode | undefined): void => { - expect(fieldOrType?.directives?.length).toBe(0); - }; - - const expectOne = (fieldOrType: ObjectTypeDefinitionNode | FieldDefinitionNode | undefined, directiveName: string): void => { - expect(fieldOrType?.directives?.length).toBe(1); - expect(fieldOrType?.directives?.find((d) => d.name.value === directiveName)).toBeDefined(); - }; - - test('that @auth with no @model on type is failing validation as model is required', () => { - const validSchema = ` - type Post - @auth ( - rules: [ - { allow: owner, operations: [read] }, - ]) { - id: ID! - text: String! - owner: String - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - - const t = () => { - const out = transformer.transform(validSchema); - }; - - expect(t).toThrowError(`Types annotated with @auth must also be annotated with @model.`); - }); - - test('that @auth with no @model on field is failing validation when operations specified', () => { - const validSchema = ` - type Post { - id: ID! - text: String! - @auth ( - rules: [ - { allow: owner, operations: [read] }, - ]) - owner: String - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - - const t = () => { - const out = transformer.transform(validSchema); - }; - - expect(t) - .toThrowError(`@auth rules on fields within types that does not have @model directive cannot specify 'operations' argument as there are \ -operations will be generated by the CLI.`); - }); - - test('that @auth on Query field is failing validation when operations specified', () => { - const validSchema = ` - type Query { - getSecret: String! - @auth ( - rules: [ - { allow: owner, operations: [read] }, - ]) - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - - const t = () => { - const out = transformer.transform(validSchema); - }; - - expect(t).toThrowError(`@auth rules on fields within Query, Mutation, Subscription cannot specify 'operations' argument as these rules \ -are already on an operation already.`); - }); - - test('that @auth on Query field is not getting auth directive added', () => { - const validSchema = ` - type Query { - getSecret: String! - @auth ( - rules: [ - { allow: private, provider: iam }, - ]) - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }, - }), - ], - }); - - const out = transformer.transform(validSchema); - const schemaDoc = parse(out.schema); - - const queryType = getObjectType(schemaDoc, 'Query'); - - expectNone(queryType); - }); - - test('that @auth on getSecret will not get directive with default auth', () => { - const validSchema = ` - type Query { - getSecret: String! - @auth ( - rules: [ - { allow: private }, - ]) - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }, - }), - ], - }); - - const out = transformer.transform(validSchema); - const schemaDoc = parse(out.schema); - - const queryType = getObjectType(schemaDoc, 'Query'); - - expectNone(queryType); - expectNone(getField(queryType, 'getSecret')); - }); - - test('that @auth on getSecret gets the right directive', () => { - const validSchema = ` - type Query { - getSecret: String! - @auth ( - rules: [ - { allow: private, provider: iam }, - ]) - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }, - }), - ], - }); - - const out = transformer.transform(validSchema); - const schemaDoc = parse(out.schema); - - const queryType = getObjectType(schemaDoc, 'Query'); - - expectNone(queryType); - expectOne(getField(queryType, 'getSecret'), 'aws_iam'); - }); - - test('that IAM on getSecret gets the right IAM policy for AuthRole', () => { - const validSchema = ` - type Query { - getSecret: String! - @auth ( - rules: [ - { allow: private, provider: iam }, - ]) - @function (name: "getSecret-\${env}") - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new FunctionTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }, - }), - ], - }); - - const out = transformer.transform(validSchema); - - expect(out.rootStack.Resources.AuthRolePolicy01).toBeTruthy(); - expect(out.rootStack.Resources.AuthRolePolicy01.Properties.PolicyDocument.Statement[0].Resource.length).toEqual(1); - expect(out.rootStack.Resources.UnauthRolePolicy01).toBeUndefined(); - }); - - test('that IAM on getSecret gets the right IAM policy for AuthRole and UnauthRole', () => { - const validSchema = ` - type Query { - getSecret: String! - @auth ( - rules: [ - { allow: public, provider: iam }, - ]) - @function (name: "getSecret-\${env}") - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new FunctionTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }, - }), - ], - }); - - const out = transformer.transform(validSchema); - - expect(out.rootStack.Resources.AuthRolePolicy01).toBeTruthy(); - expect(out.rootStack.Resources.AuthRolePolicy01.Properties.PolicyDocument.Statement[0].Resource.length).toEqual(1); - expect(out.rootStack.Resources.UnauthRolePolicy01).toBeTruthy(); - expect(out.rootStack.Resources.UnauthRolePolicy01.Properties.PolicyDocument.Statement[0].Resource.length).toEqual(1); - }); -}); diff --git a/packages/graphql-auth-transformer/src/__tests__/OperationsArgument.test.ts b/packages/graphql-auth-transformer/src/__tests__/OperationsArgument.test.ts deleted file mode 100644 index d9d13eb541..0000000000 --- a/packages/graphql-auth-transformer/src/__tests__/OperationsArgument.test.ts +++ /dev/null @@ -1,250 +0,0 @@ -import { GraphQLTransform } from 'graphql-transformer-core'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelAuthTransformer } from '../ModelAuthTransformer'; - -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -test('"read" auth operation', () => { - const validSchema = ` - type Post @model @auth(rules: [{allow: groups, groups: ["Admin", "Dev"], operations: [read]}]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.rootStack.Resources[ResourceConstants.RESOURCES.GraphQLAPILogicalID].Properties.AuthenticationType).toEqual( - 'AMAZON_COGNITO_USER_POOLS', - ); - expect(out.resolvers['Query.getPost.res.vtl']).toContain('Authorization rule:'); - expect(out.resolvers['Query.listPosts.res.vtl']).toContain('Authorization rule:'); -}); - -test('"create", "update", "delete" auth operations', () => { - const validSchema = ` - type Post @model @auth(rules: [{allow: groups, groups: ["Admin", "Dev"], operations: [create, update, delete]}]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.rootStack.Resources[ResourceConstants.RESOURCES.GraphQLAPILogicalID].Properties.AuthenticationType).toEqual( - 'AMAZON_COGNITO_USER_POOLS', - ); - expect(out.resolvers['Query.getPost.res.vtl']).not.toContain('Authorization rule:'); - expect(out.resolvers['Query.getPost.res.vtl']).toMatchSnapshot(); - expect(out.resolvers['Query.listPosts.res.vtl']).not.toContain('Authorization rule:'); - expect(out.resolvers['Query.listPosts.res.vtl']).toMatchSnapshot(); - expect(out.resolvers['Mutation.createPost.req.vtl']).toContain('Authorization rule:'); - expect(out.resolvers['Mutation.createPost.req.vtl']).toMatchSnapshot(); - expect(out.resolvers['Mutation.updatePost.req.vtl']).toContain('Authorization rule:'); - expect(out.resolvers['Mutation.updatePost.req.vtl']).toMatchSnapshot(); - expect(out.resolvers['Mutation.deletePost.req.vtl']).toContain('Authorization rule:'); - expect(out.resolvers['Mutation.deletePost.req.vtl']).toMatchSnapshot(); -}); - -test('that operation overwrites queries in auth operations', () => { - const validSchema = ` - type Post @model @auth(rules: [{allow: groups, groups: ["Admin", "Dev"], queries: [get, list], operations: [create, update, delete]}]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.rootStack.Resources[ResourceConstants.RESOURCES.GraphQLAPILogicalID].Properties.AuthenticationType).toEqual( - 'AMAZON_COGNITO_USER_POOLS', - ); - expect(out.resolvers['Query.getPost.res.vtl']).not.toContain('Authorization rule:'); - expect(out.resolvers['Query.getPost.res.vtl']).toMatchSnapshot(); - expect(out.resolvers['Query.listPosts.res.vtl']).not.toContain('Authorization rule:'); - expect(out.resolvers['Query.listPosts.res.vtl']).toMatchSnapshot(); - expect(out.resolvers['Mutation.createPost.req.vtl']).toContain('Authorization rule:'); - expect(out.resolvers['Mutation.createPost.req.vtl']).toMatchSnapshot(); - expect(out.resolvers['Mutation.updatePost.req.vtl']).toContain('Authorization rule:'); - expect(out.resolvers['Mutation.updatePost.req.vtl']).toMatchSnapshot(); - expect(out.resolvers['Mutation.deletePost.req.vtl']).toContain('Authorization rule:'); - expect(out.resolvers['Mutation.deletePost.req.vtl']).toMatchSnapshot(); -}); - -test('that checks subscription resolvers are generated with auth logic', () => { - const validSchema = ` - type Salary @model - @auth( rules: [ - {allow: owner}, - {allow: groups, groups: ["Admin"]}]){ - id: ID! - wage: Int - owner: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - // expect to generate subcriptions resolvers - expect(out).toBeDefined(); - expect(out.rootStack.Resources[ResourceConstants.RESOURCES.GraphQLAPILogicalID].Properties.AuthenticationType).toEqual( - 'AMAZON_COGNITO_USER_POOLS', - ); - expect(out.resolvers['Subscription.onCreateSalary.res.vtl']).toContain('Authorization rule:'); - expect(out.resolvers['Subscription.onCreateSalary.res.vtl']).toMatchSnapshot(); - expect(out.resolvers['Subscription.onDeleteSalary.res.vtl']).toContain('Authorization rule:'); - expect(out.resolvers['Subscription.onDeleteSalary.res.vtl']).toMatchSnapshot(); - expect(out.resolvers['Subscription.onUpdateSalary.res.vtl']).toContain('Authorization rule:'); - expect(out.resolvers['Subscription.onUpdateSalary.res.vtl']).toMatchSnapshot(); -}); - -test('that checks subscription resolvers are created without auth logic', () => { - const validSchema = ` - type Salary @model( - subscriptions: { - level: public - }) @auth( rules: [ - {allow: owner}, - {allow: groups, groups: ["Admin"]}]){ - id: ID! - wage: Int - owner: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - // expect to generate subcriptions resolvers - expect(out).toBeDefined(); - expect(out.rootStack.Resources[ResourceConstants.RESOURCES.GraphQLAPILogicalID].Properties.AuthenticationType).toEqual( - 'AMAZON_COGNITO_USER_POOLS', - ); - expect(out.resolvers['Subscription.onCreateSalary.res.vtl']).not.toContain('Authorization rule:'); - expect(out.resolvers['Subscription.onCreateSalary.res.vtl']).toMatchSnapshot(); - expect(out.resolvers['Subscription.onDeleteSalary.res.vtl']).not.toContain('Authorization rule:'); - expect(out.resolvers['Subscription.onDeleteSalary.res.vtl']).toMatchSnapshot(); - expect(out.resolvers['Subscription.onUpdateSalary.res.vtl']).not.toContain('Authorization rule:'); - expect(out.resolvers['Subscription.onUpdateSalary.res.vtl']).toMatchSnapshot(); -}); - -test('that subscriptions are only generated if the respective mutation operation exists', () => { - const validSchema = ` - type Salary @model( - mutations: { - create: "makeIT", - update: "updateIT", - })@auth( - rules: [ - {allow: owner}, - {allow: groups, groups: ["Moderator"], operations: [create]} - ]){ - id: ID! - wage: Int - owner: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - // expect to generate subscription resolvers for create and update only - expect(out).toBeDefined(); - expect(out.rootStack.Resources[ResourceConstants.RESOURCES.GraphQLAPILogicalID].Properties.AuthenticationType).toEqual( - 'AMAZON_COGNITO_USER_POOLS', - ); - expect(out.resolvers['Subscription.onCreateSalary.res.vtl']).toContain('Authorization rule:'); - expect(out.resolvers['Subscription.onCreateSalary.res.vtl']).toMatchSnapshot(); - expect(out.resolvers['Subscription.onUpdateSalary.res.vtl']).toContain('Authorization rule:'); - expect(out.resolvers['Subscription.onUpdateSalary.res.vtl']).toMatchSnapshot(); - expect(out.resolvers['Subscription.onDeleteSalary.res.vtl']).toBeUndefined(); -}); diff --git a/packages/graphql-auth-transformer/src/__tests__/OwnerAuthTransformer.test.ts b/packages/graphql-auth-transformer/src/__tests__/OwnerAuthTransformer.test.ts deleted file mode 100644 index 3820854e6a..0000000000 --- a/packages/graphql-auth-transformer/src/__tests__/OwnerAuthTransformer.test.ts +++ /dev/null @@ -1,279 +0,0 @@ -import { parse } from 'graphql'; -import { FeatureFlagProvider, GraphQLTransform } from 'graphql-transformer-core'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelAuthTransformer } from '../ModelAuthTransformer'; -import { getObjectType, getField } from './test-helpers'; - -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -test('ModelAuthTransformer validation happy case', () => { - const validSchema = ` - type Post @model @auth(rules: [{allow: owner}]) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.rootStack.Resources[ResourceConstants.RESOURCES.GraphQLAPILogicalID].Properties.AuthenticationType).toEqual( - 'AMAZON_COGNITO_USER_POOLS', - ); -}); - -test('OwnerField with Subscriptions', () => { - const validSchema = ` - type Post @model - @auth(rules: [ - {allow: owner, ownerField: "postOwner"} - ]) - { - id: ID! - title: String - postOwner: String - }`; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - // expect 'postOwner' as an argument for subscription operations - expect(out.schema).toContain('onCreatePost(postOwner: String!)'); - expect(out.schema).toContain('onUpdatePost(postOwner: String!)'); - expect(out.schema).toContain('onDeletePost(postOwner: String!)'); - - // expect logic in the resolvers to check for postOwner args as an allowerOwner - expect(out.resolvers['Subscription.onCreatePost.res.vtl']).toContain( - '#set( $allowedOwners0 = $util.defaultIfNull($ctx.args.postOwner, null) )', - ); - expect(out.resolvers['Subscription.onUpdatePost.res.vtl']).toContain( - '#set( $allowedOwners0 = $util.defaultIfNull($ctx.args.postOwner, null) )', - ); - expect(out.resolvers['Subscription.onDeletePost.res.vtl']).toContain( - '#set( $allowedOwners0 = $util.defaultIfNull($ctx.args.postOwner, null) )', - ); -}); - -test('multiple owner rules with Subscriptions', () => { - const validSchema = ` - type Post @model - @auth(rules: [ - { allow: owner }, - { allow: owner, ownerField: "editors", operations: [read, update] } - ]) - { - id: ID! - title: String - owner: String - editors: [String] - }`; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - // expect 'owner' and 'editors' as arguments for subscription operations - expect(out.schema).toContain('onCreatePost(owner: String, editors: String)'); - expect(out.schema).toContain('onUpdatePost(owner: String, editors: String)'); - expect(out.schema).toContain('onDeletePost(owner: String, editors: String)'); - - // expect logic in the resolvers to check for owner args as an allowedOwner - expect(out.resolvers['Subscription.onCreatePost.res.vtl']).toContain( - '#set( $allowedOwners0 = $util.defaultIfNull($ctx.args.owner, null) )', - ); - expect(out.resolvers['Subscription.onUpdatePost.res.vtl']).toContain( - '#set( $allowedOwners0 = $util.defaultIfNull($ctx.args.owner, null) )', - ); - expect(out.resolvers['Subscription.onDeletePost.res.vtl']).toContain( - '#set( $allowedOwners0 = $util.defaultIfNull($ctx.args.owner, null) )', - ); - - // expect logic in the resolvers to check for editors args as an allowedOwner - expect(out.resolvers['Subscription.onCreatePost.res.vtl']).toContain( - '#set( $allowedOwners1 = $util.defaultIfNull($ctx.args.editors, null) )', - ); - expect(out.resolvers['Subscription.onUpdatePost.res.vtl']).toContain( - '#set( $allowedOwners1 = $util.defaultIfNull($ctx.args.editors, null) )', - ); - expect(out.resolvers['Subscription.onDeletePost.res.vtl']).toContain( - '#set( $allowedOwners1 = $util.defaultIfNull($ctx.args.editors, null) )', - ); -}); - -describe('add missing implicit owner fields to type', () => { - let ff: FeatureFlagProvider; - const runTransformer = (validSchema: string) => { - return new GraphQLTransform({ - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - featureFlags: ff, - }); - }; - beforeEach(() => { - ff = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'addMissingOwnerFields') { - return true; - } - if (name === 'improvePluralization') { - return true; - } - }), - getNumber: jest.fn(), - getObject: jest.fn(), - }; - }); - describe('object level', () => { - let transformer; - const validSchema = ` - type Post @model - @auth(rules: [ - {allow: owner, ownerField: "postOwner"} - { allow: owner, ownerField: "customOwner", identityClaim: "sub"} - ]) - { - id: ID! - title: String - }`; - - beforeEach(() => { - transformer = runTransformer(validSchema); - }); - - test('implicit owner fields get added to the type when addMissingOwnerFields feature flag is set', () => { - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const schema = parse(out.schema); - const postType = getObjectType(schema, 'Post'); - expect(postType).toBeDefined(); - - const postOwnerField = getField(postType, 'postOwner'); - expect(postOwnerField).toBeDefined(); - expect((postOwnerField as any).type.name.value).toEqual('String'); - - const customOwner = getField(postType, 'customOwner'); - expect(customOwner).toBeDefined(); - expect((customOwner as any).type.name.value).toEqual('String'); - }); - - test('implicit owner fields does not get added to the type when addMissingOwnerFields feature flag is not set', () => { - (ff.getBoolean as any).mockImplementation(() => false); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const schema = parse(out.schema); - const postType = getObjectType(schema, 'Post'); - expect(postType).toBeDefined(); - - const postOwnerField = getField(postType, 'postOwner'); - expect(postOwnerField).not.toBeDefined(); - - const customOwner = getField(postType, 'customOwner'); - expect(customOwner).not.toBeDefined(); - }); - }); - - describe('field level', () => { - let transformer; - const validSchema = ` - type Post @model - { - id: ID! - title: String - protectedField: String @auth(rules: [ - {allow: owner, ownerField: "postOwner"} - { allow: owner, ownerField: "customOwner", identityClaim: "sub"} - ]) - }`; - beforeEach(() => { - transformer = runTransformer(validSchema); - }); - test('implicit owner fields from field level auth get added to the type when addMissingOwnerFields feature flag is set', () => { - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const schema = parse(out.schema); - const postType = getObjectType(schema, 'Post'); - expect(postType).toBeDefined(); - - const postOwnerField = getField(postType, 'postOwner'); - expect(postOwnerField).toBeDefined(); - expect((postOwnerField as any).type.name.value).toEqual('String'); - - const customOwner = getField(postType, 'customOwner'); - expect(customOwner).toBeDefined(); - expect((customOwner as any).type.name.value).toEqual('String'); - }); - - test('implicit owner fields from field level auth does not get added to the type when addMissingOwnerFields feature flag is not set', () => { - (ff.getBoolean as any).mockImplementation(() => false); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const schema = parse(out.schema); - const postType = getObjectType(schema, 'Post'); - expect(postType).toBeDefined(); - - const postOwnerField = getField(postType, 'postOwner'); - expect(postOwnerField).not.toBeDefined(); - - const customOwner = getField(postType, 'customOwner'); - expect(customOwner).not.toBeDefined(); - }); - }); -}); diff --git a/packages/graphql-auth-transformer/src/__tests__/PerFieldAuthArgument.test.ts b/packages/graphql-auth-transformer/src/__tests__/PerFieldAuthArgument.test.ts deleted file mode 100644 index becd94a866..0000000000 --- a/packages/graphql-auth-transformer/src/__tests__/PerFieldAuthArgument.test.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { GraphQLTransform } from 'graphql-transformer-core'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { KeyTransformer } from 'graphql-key-transformer'; -import { ModelAuthTransformer } from '../ModelAuthTransformer'; - -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -test('that subscriptions are only generated if the respective mutation operation exists', () => { - const validSchema = ` - type Salary - @model - @auth(rules: [ - {allow: owner}, - {allow: groups, groups: ["Moderator"]} - ]) { - id: ID! - wage: Int - owner: String - secret: String @auth(rules: [{allow: owner}]) - }`; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - // expect to generate subscription resolvers for create and update only - expect(out).toBeDefined(); - expect(out.rootStack.Resources[ResourceConstants.RESOURCES.GraphQLAPILogicalID].Properties.AuthenticationType).toEqual( - 'AMAZON_COGNITO_USER_POOLS', - ); - expect(out.resolvers['Salary.secret.res.vtl']).toContain('#if( $operation == "Mutation" )'); - expect(out.resolvers['Salary.secret.res.vtl']).toMatchSnapshot(); - - expect(out.resolvers['Mutation.createSalary.res.vtl']).toContain('$util.qr($ctx.result.put("operation", "Mutation"))'); - expect(out.resolvers['Mutation.createSalary.res.vtl']).toMatchSnapshot(); - - expect(out.resolvers['Mutation.updateSalary.res.vtl']).toContain('$util.qr($ctx.result.put("operation", "Mutation"))'); - expect(out.resolvers['Mutation.updateSalary.res.vtl']).toMatchSnapshot(); - - expect(out.resolvers['Mutation.deleteSalary.res.vtl']).toContain('$util.qr($ctx.result.put("operation", "Mutation"))'); - expect(out.resolvers['Mutation.deleteSalary.res.vtl']).toMatchSnapshot(); -}); - -test('per-field @auth on a @connection field', () => { - const validSchema = ` - type Post - @model - @auth(rules: [ - { allow: groups, groups: ["admin"] } - { allow: owner, ownerField: "moderator" } - ]) - { - id: ID! - name: String! - tags: [Tag] - @connection(keyName: "byTags", fields: ["id"]) - @auth(rules: [ { allow: groups, groups: ["admin"] } ]) - } - type Tag - @model - @key(name: "byTags", fields: ["postID"]) - @auth(rules: [ { allow: groups, groups: ["admin"] } ]) - { - id: ID! - postID: ID! - post: Post @connection(fields: ["postID"]) - createdAt: AWSDateTime - updatedAt: AWSDateTime - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new KeyTransformer(), - new ModelConnectionTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [{ authenticationType: 'AWS_IAM' }], - }, - }), - ], - }); - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - const resolvers = out.resolvers; - expect(resolvers['Tag.post.res.vtl']).toMatchSnapshot(); - expect(resolvers['Tag.post.res.vtl']).toContain('$util.toJson($ctx.result)'); -}); - -test('per-field @auth without model', () => { - const validSchema = ` - type Query { - listContext: String @auth(rules: [{ allow: groups, groups: ["Allowed"] }, { allow: private, provider: iam }]) - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }, - }), - ], - }); - - const out = transformer.transform(validSchema); - - expect(out).toBeDefined(); - const resources = out.rootStack.Resources; - expect(resources['AuthRolePolicy01']).toMatchSnapshot(); - expect(out.resolvers['Query.listContext.req.vtl']).toContain('#if( $authMode == "userPools" )'); - expect(out.resolvers['Query.listContext.req.vtl']).toContain( - '## Authorization rule: { allow: groups, groups: ["Allowed"], groupClaim: "cognito:groups" } **', - ); - expect(out.resolvers['Query.listContext.req.vtl']).toMatchSnapshot(); -}); diff --git a/packages/graphql-auth-transformer/src/__tests__/SearchableAuthTransformer.test.ts b/packages/graphql-auth-transformer/src/__tests__/SearchableAuthTransformer.test.ts deleted file mode 100644 index 5e7d719c90..0000000000 --- a/packages/graphql-auth-transformer/src/__tests__/SearchableAuthTransformer.test.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { SearchableModelTransformer } from 'graphql-elasticsearch-transformer'; -import { ModelAuthTransformer } from '../ModelAuthTransformer'; - -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -test('auth logic is enabled on owner/static rules in resposne es resolver', () => { - const validSchema = ` - type Comment @model - @searchable - @auth(rules: [ - { allow: owner } - { allow: groups, groups: ["writer"]} - ]) - { - id: ID! - content: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new SearchableModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - - const out = transformer.transform(validSchema); - // expect response resolver to contain auth logic for owner rule - expect(out).toBeDefined(); - expect(out.resolvers['Query.searchComments.res.vtl']).toContain( - '## Authorization rule: { allow: owner, ownerField: "owner", identityClaim: "cognito:username" } **', - ); - // expect response resolver to contain auth logic for group rule - expect(out.resolvers['Query.searchComments.res.vtl']).toContain( - '## Authorization rule: { allow: groups, groups: ["writer"], groupClaim: "cognito:groups" } **', - ); -}); - -test('auth logic is enabled for iam/apiKey auth rules in response es resolver', () => { - const validSchema = ` - type Post @model - @searchable - @auth(rules: [ - { allow: public, provider: apiKey } # api key is allowed - { allow: private, provider: iam } # auth roles are allowed - ]) { - id: ID! - content: String - secret: String @auth(rules: [{ allow: private, provider: iam }]) # only auth role can do crud on this - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new SearchableModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'API_KEY', - apiKeyConfig: { - description: 'E2E Test API Key', - apiKeyExpirationDays: 300, - }, - }, - { - authenticationType: 'AWS_IAM', - }, - ], - }, - }), - ], - }); - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.schema).toContain('SearchablePostConnection @aws_api_key @aws_iam'); - expect(out.schema).toMatchSnapshot(); -}); diff --git a/packages/graphql-auth-transformer/src/__tests__/__snapshots__/OperationsArgument.test.ts.snap b/packages/graphql-auth-transformer/src/__tests__/__snapshots__/OperationsArgument.test.ts.snap deleted file mode 100644 index 7c3471765f..0000000000 --- a/packages/graphql-auth-transformer/src/__tests__/__snapshots__/OperationsArgument.test.ts.snap +++ /dev/null @@ -1,1256 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`"create", "update", "delete" auth operations 1`] = ` -"#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type) -#else -$util.toJson($ctx.result) -#end" -`; - -exports[`"create", "update", "delete" auth operations 2`] = ` -"#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type) -#else -$util.toJson($ctx.result) -#end" -`; - -exports[`"create", "update", "delete" auth operations 3`] = ` -"## [Start] Set default values. ** -$util.qr($context.args.input.put(\\"id\\", $util.defaultIfNull($ctx.args.input.id, $util.autoId()))) -#set( $createdAt = $util.time.nowISO8601() ) -## Automatically set the createdAt timestamp. ** -$util.qr($context.args.input.put(\\"createdAt\\", $util.defaultIfNull($ctx.args.input.createdAt, $createdAt))) -## Automatically set the updatedAt timestamp. ** -$util.qr($context.args.input.put(\\"updatedAt\\", $util.defaultIfNull($ctx.args.input.updatedAt, $createdAt))) -## [End] Set default values. ** -## [Start] Determine request authentication mode ** -#if( $util.isNullOrEmpty($authMode) && !$util.isNull($ctx.identity) && !$util.isNull($ctx.identity.sub) && !$util.isNull($ctx.identity.issuer) && !$util.isNull($ctx.identity.username) && !$util.isNull($ctx.identity.claims) && !$util.isNull($ctx.identity.sourceIp) && !$util.isNull($ctx.identity.defaultAuthStrategy) ) - #set( $authMode = \\"userPools\\" ) -#end -## [End] Determine request authentication mode ** -## [Start] Check authMode and execute owner/group checks ** -#if( $authMode == \\"userPools\\" ) - ## [Start] Static Group Authorization Checks ** - #set($isStaticGroupAuthorized = $util.defaultIfNull( - $isStaticGroupAuthorized, false)) - ## Authorization rule: { allow: groups, groups: [\\"Admin\\",\\"Dev\\"], groupClaim: \\"cognito:groups\\" } ** - #set( $userGroups = $util.defaultIfNull($ctx.identity.claims.get(\\"cognito:groups\\"), []) ) - #set( $allowedGroups = [\\"Admin\\", \\"Dev\\"] ) - #foreach( $userGroup in $userGroups ) - #if( $allowedGroups.contains($userGroup) ) - #set( $isStaticGroupAuthorized = true ) - #break - #end - #end - ## [End] Static Group Authorization Checks ** - - - ## No Dynamic Group Authorization Rules ** - - - ## No Owner Authorization Rules ** - - - ## [Start] Throw if unauthorized ** - #if( !($isStaticGroupAuthorized == true || $isDynamicGroupAuthorized == true || $isOwnerAuthorized == true) ) - $util.unauthorized() - #end - ## [End] Throw if unauthorized ** -#end -## [End] Check authMode and execute owner/group checks ** - -## [Start] Prepare DynamoDB PutItem Request. ** -$util.qr($context.args.input.put(\\"__typename\\", \\"Post\\")) -#if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_not_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_not_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end -#else - #set( $condition = { - \\"expression\\": \\"attribute_not_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) -#end -#if( $context.args.condition ) - #set( $condition.expressionValues = {} ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"PutItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": $util.dynamodb.toDynamoDBJson($ctx.args.input.id) -} #end, - \\"attributeValues\\": $util.dynamodb.toMapValuesJson($context.args.input), - \\"condition\\": $util.toJson($condition) -} -## [End] Prepare DynamoDB PutItem Request. **" -`; - -exports[`"create", "update", "delete" auth operations 4`] = ` -"## [Start] Determine request authentication mode ** -#if( $util.isNullOrEmpty($authMode) && !$util.isNull($ctx.identity) && !$util.isNull($ctx.identity.sub) && !$util.isNull($ctx.identity.issuer) && !$util.isNull($ctx.identity.username) && !$util.isNull($ctx.identity.claims) && !$util.isNull($ctx.identity.sourceIp) && !$util.isNull($ctx.identity.defaultAuthStrategy) ) - #set( $authMode = \\"userPools\\" ) -#end -## [End] Determine request authentication mode ** -## [Start] Check authMode and execute owner/group checks ** -#if( $authMode == \\"userPools\\" ) - ## [Start] Static Group Authorization Checks ** - #set($isStaticGroupAuthorized = $util.defaultIfNull( - $isStaticGroupAuthorized, false)) - ## Authorization rule: { allow: groups, groups: [\\"Admin\\",\\"Dev\\"], groupClaim: \\"cognito:groups\\" } ** - #set( $userGroups = $util.defaultIfNull($ctx.identity.claims.get(\\"cognito:groups\\"), []) ) - #set( $allowedGroups = [\\"Admin\\", \\"Dev\\"] ) - #foreach( $userGroup in $userGroups ) - #if( $allowedGroups.contains($userGroup) ) - #set( $isStaticGroupAuthorized = true ) - #break - #end - #end - ## [End] Static Group Authorization Checks ** - - - #if( ! $isStaticGroupAuthorized ) - ## No dynamic group authorization rules ** - - - ## No owner authorization rules ** - - - ## [Start] Collect Auth Condition ** - #set( $authCondition = $util.defaultIfNull($authCondition, { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -}) ) - #set( $totalAuthExpression = \\"\\" ) - ## Add dynamic group auth conditions if they exist ** - #if( $groupAuthExpressions ) - #foreach( $authExpr in $groupAuthExpressions ) - #set( $totalAuthExpression = \\"$totalAuthExpression $authExpr\\" ) - #if( $foreach.hasNext ) - #set( $totalAuthExpression = \\"$totalAuthExpression OR\\" ) - #end - #end - #end - #if( $groupAuthExpressionNames ) - $util.qr($authCondition.expressionNames.putAll($groupAuthExpressionNames)) - #end - #if( $groupAuthExpressionValues ) - $util.qr($authCondition.expressionValues.putAll($groupAuthExpressionValues)) - #end - ## Add owner auth conditions if they exist ** - #if( $totalAuthExpression != \\"\\" && $ownerAuthExpressions && $ownerAuthExpressions.size() > 0 ) - #set( $totalAuthExpression = \\"$totalAuthExpression OR\\" ) - #end - #if( $ownerAuthExpressions ) - #foreach( $authExpr in $ownerAuthExpressions ) - #set( $totalAuthExpression = \\"$totalAuthExpression $authExpr\\" ) - #if( $foreach.hasNext ) - #set( $totalAuthExpression = \\"$totalAuthExpression OR\\" ) - #end - #end - #end - #if( $ownerAuthExpressionNames ) - $util.qr($authCondition.expressionNames.putAll($ownerAuthExpressionNames)) - #end - #if( $ownerAuthExpressionValues ) - $util.qr($authCondition.expressionValues.putAll($ownerAuthExpressionValues)) - #end - ## Set final expression if it has changed. ** - #if( $totalAuthExpression != \\"\\" ) - #if( $util.isNullOrEmpty($authCondition.expression) ) - #set( $authCondition.expression = \\"($totalAuthExpression)\\" ) - #else - #set( $authCondition.expression = \\"$authCondition.expression AND ($totalAuthExpression)\\" ) - #end - #end - ## [End] Collect Auth Condition ** - #end - - - ## [Start] Throw if unauthorized ** - #if( !($isStaticGroupAuthorized == true || ($totalAuthExpression != \\"\\")) ) - $util.unauthorized() - #end - ## [End] Throw if unauthorized ** -#end -## [End] Check authMode and execute owner/group checks ** - -#set( $optionalNonNullableFields = [\\"title\\"] ) -#foreach( $field in $optionalNonNullableFields ) - #if( $context.arguments.input.keySet().contains($field) && $util.isNull($context.args.input.get($field)) ) -$util.error(\\"An argument you marked as Non-Null is set to Null in the query or the body of your request.\\") - #end -#end -#if( $authCondition && $authCondition.expression != \\"\\" ) - #set( $condition = $authCondition ) - #if( $modelObjectKey ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#id)\\")) - $util.qr($condition.expressionNames.put(\\"#id\\", \\"id\\")) - #end -#else - #if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - #set( $condition = { - \\"expression\\": \\"attribute_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) - #end -#end -## Automatically set the updatedAt timestamp. ** -$util.qr($context.args.input.put(\\"updatedAt\\", $util.defaultIfNull($ctx.args.input.updatedAt, $util.time.nowISO8601()))) -$util.qr($context.args.input.put(\\"__typename\\", \\"Post\\")) -## Update condition if type is @versioned ** -#if( $versionedCondition ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $versionedCondition.expression\\")) - $util.qr($condition.expressionNames.putAll($versionedCondition.expressionNames)) - $util.qr($condition.expressionValues.putAll($versionedCondition.expressionValues)) -#end -#if( $context.args.condition ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -#set( $expNames = {} ) -#set( $expValues = {} ) -#set( $expSet = {} ) -#set( $expAdd = {} ) -#set( $expRemove = [] ) -#if( $modelObjectKey ) - #set( $keyFields = [] ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($keyFields.add(\\"$entry.key\\")) - #end -#else - #set( $keyFields = [\\"id\\"] ) -#end -#foreach( $entry in $util.map.copyAndRemoveAllKeys($context.args.input, $keyFields).entrySet() ) - #if( !$util.isNull($dynamodbNameOverrideMap) && $dynamodbNameOverrideMap.containsKey(\\"$entry.key\\") ) - #set( $entryKeyAttributeName = $dynamodbNameOverrideMap.get(\\"$entry.key\\") ) - #else - #set( $entryKeyAttributeName = $entry.key ) - #end - #if( $util.isNull($entry.value) ) - #set( $discard = $expRemove.add(\\"#$entryKeyAttributeName\\") ) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - #else - $util.qr($expSet.put(\\"#$entryKeyAttributeName\\", \\":$entryKeyAttributeName\\")) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - $util.qr($expValues.put(\\":$entryKeyAttributeName\\", $util.dynamodb.toDynamoDB($entry.value))) - #end -#end -#set( $expression = \\"\\" ) -#if( !$expSet.isEmpty() ) - #set( $expression = \\"SET\\" ) - #foreach( $entry in $expSet.entrySet() ) - #set( $expression = \\"$expression $entry.key = $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expAdd.isEmpty() ) - #set( $expression = \\"$expression ADD\\" ) - #foreach( $entry in $expAdd.entrySet() ) - #set( $expression = \\"$expression $entry.key $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expRemove.isEmpty() ) - #set( $expression = \\"$expression REMOVE\\" ) - #foreach( $entry in $expRemove ) - #set( $expression = \\"$expression $entry\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#set( $update = {} ) -$util.qr($update.put(\\"expression\\", \\"$expression\\")) -#if( !$expNames.isEmpty() ) - $util.qr($update.put(\\"expressionNames\\", $expNames)) -#end -#if( !$expValues.isEmpty() ) - $util.qr($update.put(\\"expressionValues\\", $expValues)) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"UpdateItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": { - \\"S\\": $util.toJson($context.args.input.id) - } -} #end, - \\"update\\": $util.toJson($update), - \\"condition\\": $util.toJson($condition) -}" -`; - -exports[`"create", "update", "delete" auth operations 5`] = ` -"## [Start] Determine request authentication mode ** -#if( $util.isNullOrEmpty($authMode) && !$util.isNull($ctx.identity) && !$util.isNull($ctx.identity.sub) && !$util.isNull($ctx.identity.issuer) && !$util.isNull($ctx.identity.username) && !$util.isNull($ctx.identity.claims) && !$util.isNull($ctx.identity.sourceIp) && !$util.isNull($ctx.identity.defaultAuthStrategy) ) - #set( $authMode = \\"userPools\\" ) -#end -## [End] Determine request authentication mode ** -## [Start] Check authMode and execute owner/group checks ** -#if( $authMode == \\"userPools\\" ) - ## [Start] Static Group Authorization Checks ** - #set($isStaticGroupAuthorized = $util.defaultIfNull( - $isStaticGroupAuthorized, false)) - ## Authorization rule: { allow: groups, groups: [\\"Admin\\",\\"Dev\\"], groupClaim: \\"cognito:groups\\" } ** - #set( $userGroups = $util.defaultIfNull($ctx.identity.claims.get(\\"cognito:groups\\"), []) ) - #set( $allowedGroups = [\\"Admin\\", \\"Dev\\"] ) - #foreach( $userGroup in $userGroups ) - #if( $allowedGroups.contains($userGroup) ) - #set( $isStaticGroupAuthorized = true ) - #break - #end - #end - ## [End] Static Group Authorization Checks ** - - - #if( ! $isStaticGroupAuthorized ) - ## No dynamic group authorization rules ** - - - ## No owner authorization rules ** - - - ## [Start] Collect Auth Condition ** - #set( $authCondition = $util.defaultIfNull($authCondition, { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -}) ) - #set( $totalAuthExpression = \\"\\" ) - ## Add dynamic group auth conditions if they exist ** - #if( $groupAuthExpressions ) - #foreach( $authExpr in $groupAuthExpressions ) - #set( $totalAuthExpression = \\"$totalAuthExpression $authExpr\\" ) - #if( $foreach.hasNext ) - #set( $totalAuthExpression = \\"$totalAuthExpression OR\\" ) - #end - #end - #end - #if( $groupAuthExpressionNames ) - $util.qr($authCondition.expressionNames.putAll($groupAuthExpressionNames)) - #end - #if( $groupAuthExpressionValues ) - $util.qr($authCondition.expressionValues.putAll($groupAuthExpressionValues)) - #end - ## Add owner auth conditions if they exist ** - #if( $totalAuthExpression != \\"\\" && $ownerAuthExpressions && $ownerAuthExpressions.size() > 0 ) - #set( $totalAuthExpression = \\"$totalAuthExpression OR\\" ) - #end - #if( $ownerAuthExpressions ) - #foreach( $authExpr in $ownerAuthExpressions ) - #set( $totalAuthExpression = \\"$totalAuthExpression $authExpr\\" ) - #if( $foreach.hasNext ) - #set( $totalAuthExpression = \\"$totalAuthExpression OR\\" ) - #end - #end - #end - #if( $ownerAuthExpressionNames ) - $util.qr($authCondition.expressionNames.putAll($ownerAuthExpressionNames)) - #end - #if( $ownerAuthExpressionValues ) - $util.qr($authCondition.expressionValues.putAll($ownerAuthExpressionValues)) - #end - ## Set final expression if it has changed. ** - #if( $totalAuthExpression != \\"\\" ) - #if( $util.isNullOrEmpty($authCondition.expression) ) - #set( $authCondition.expression = \\"($totalAuthExpression)\\" ) - #else - #set( $authCondition.expression = \\"$authCondition.expression AND ($totalAuthExpression)\\" ) - #end - #end - ## [End] Collect Auth Condition ** - #end - - - ## [Start] Throw if unauthorized ** - #if( !($isStaticGroupAuthorized == true || ($totalAuthExpression != \\"\\")) ) - $util.unauthorized() - #end - ## [End] Throw if unauthorized ** -#end -## [End] Check authMode and execute owner/group checks ** - -#if( $authCondition ) - #set( $condition = $authCondition ) - #if( $modelObjectKey ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#id)\\")) - $util.qr($condition.expressionNames.put(\\"#id\\", \\"id\\")) - #end -#else - #if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - #set( $condition = { - \\"expression\\": \\"attribute_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) - #end -#end -#if( $versionedCondition ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $versionedCondition.expression\\")) - $util.qr($condition.expressionNames.putAll($versionedCondition.expressionNames)) - #set( $expressionValues = $util.defaultIfNull($condition.expressionValues, {}) ) - $util.qr($expressionValues.putAll($versionedCondition.expressionValues)) - #set( $condition.expressionValues = $expressionValues ) -#end -#if( $context.args.condition ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - #set( $conditionExpressionValues = $util.defaultIfNull($condition.expressionValues, {}) ) - $util.qr($conditionExpressionValues.putAll($conditionFilterExpressions.expressionValues)) - #set( $condition.expressionValues = $conditionExpressionValues ) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"DeleteItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": $util.dynamodb.toDynamoDBJson($ctx.args.input.id) -} #end, - \\"condition\\": $util.toJson($condition) -}" -`; - -exports[`that checks subscription resolvers are created without auth logic 1`] = `"$util.toJson(null)"`; - -exports[`that checks subscription resolvers are created without auth logic 2`] = `"$util.toJson(null)"`; - -exports[`that checks subscription resolvers are created without auth logic 3`] = `"$util.toJson(null)"`; - -exports[`that checks subscription resolvers are generated with auth logic 1`] = ` -"## [Start] Determine request authentication mode ** -#if( $util.isNullOrEmpty($authMode) && !$util.isNull($ctx.identity) && !$util.isNull($ctx.identity.sub) && !$util.isNull($ctx.identity.issuer) && !$util.isNull($ctx.identity.username) && !$util.isNull($ctx.identity.claims) && !$util.isNull($ctx.identity.sourceIp) && !$util.isNull($ctx.identity.defaultAuthStrategy) ) - #set( $authMode = \\"userPools\\" ) -#end -## [End] Determine request authentication mode ** -## [Start] Check authMode and execute owner/group checks ** -#if( $authMode == \\"userPools\\" ) - ## [Start] Static Group Authorization Checks ** - #set($isStaticGroupAuthorized = $util.defaultIfNull( - $isStaticGroupAuthorized, false)) - ## Authorization rule: { allow: groups, groups: [\\"Admin\\"], groupClaim: \\"cognito:groups\\" } ** - #set( $userGroups = $util.defaultIfNull($ctx.identity.claims.get(\\"cognito:groups\\"), []) ) - #set( $allowedGroups = [\\"Admin\\"] ) - #foreach( $userGroup in $userGroups ) - #if( $allowedGroups.contains($userGroup) ) - #set( $isStaticGroupAuthorized = true ) - #break - #end - #end - ## [End] Static Group Authorization Checks ** - - - ## [Start] Owner Authorization Checks ** - #set( $isOwnerAuthorized = false ) - ## Authorization rule: { allow: owner, ownerField: \\"owner\\", identityClaim: \\"cognito:username\\" } ** - #set( $allowedOwners0 = $util.defaultIfNull($ctx.args.owner, null) ) - #set( $identityValue = $util.defaultIfNull($ctx.identity.claims.get(\\"username\\"), - $util.defaultIfNull($ctx.identity.claims.get(\\"cognito:username\\"), \\"___xamznone____\\")) ) - #if( $util.isList($allowedOwners0) ) - #foreach( $allowedOwner in $allowedOwners0 ) - #if( $allowedOwner == $identityValue ) - #set( $isOwnerAuthorized = true ) - #end - #end - #end - #if( $util.isString($allowedOwners0) ) - #if( $allowedOwners0 == $identityValue ) - #set( $isOwnerAuthorized = true ) - #end - #end - ## [End] Owner Authorization Checks ** - - - ## [Start] Throw if unauthorized ** - #if( !($isStaticGroupAuthorized == true || $isOwnerAuthorized == true) ) - $util.unauthorized() - #end - ## [End] Throw if unauthorized ** -#end -## [End] Check authMode and execute owner/group checks ** - -$util.toJson(null)" -`; - -exports[`that checks subscription resolvers are generated with auth logic 2`] = ` -"## [Start] Determine request authentication mode ** -#if( $util.isNullOrEmpty($authMode) && !$util.isNull($ctx.identity) && !$util.isNull($ctx.identity.sub) && !$util.isNull($ctx.identity.issuer) && !$util.isNull($ctx.identity.username) && !$util.isNull($ctx.identity.claims) && !$util.isNull($ctx.identity.sourceIp) && !$util.isNull($ctx.identity.defaultAuthStrategy) ) - #set( $authMode = \\"userPools\\" ) -#end -## [End] Determine request authentication mode ** -## [Start] Check authMode and execute owner/group checks ** -#if( $authMode == \\"userPools\\" ) - ## [Start] Static Group Authorization Checks ** - #set($isStaticGroupAuthorized = $util.defaultIfNull( - $isStaticGroupAuthorized, false)) - ## Authorization rule: { allow: groups, groups: [\\"Admin\\"], groupClaim: \\"cognito:groups\\" } ** - #set( $userGroups = $util.defaultIfNull($ctx.identity.claims.get(\\"cognito:groups\\"), []) ) - #set( $allowedGroups = [\\"Admin\\"] ) - #foreach( $userGroup in $userGroups ) - #if( $allowedGroups.contains($userGroup) ) - #set( $isStaticGroupAuthorized = true ) - #break - #end - #end - ## [End] Static Group Authorization Checks ** - - - ## [Start] Owner Authorization Checks ** - #set( $isOwnerAuthorized = false ) - ## Authorization rule: { allow: owner, ownerField: \\"owner\\", identityClaim: \\"cognito:username\\" } ** - #set( $allowedOwners0 = $util.defaultIfNull($ctx.args.owner, null) ) - #set( $identityValue = $util.defaultIfNull($ctx.identity.claims.get(\\"username\\"), - $util.defaultIfNull($ctx.identity.claims.get(\\"cognito:username\\"), \\"___xamznone____\\")) ) - #if( $util.isList($allowedOwners0) ) - #foreach( $allowedOwner in $allowedOwners0 ) - #if( $allowedOwner == $identityValue ) - #set( $isOwnerAuthorized = true ) - #end - #end - #end - #if( $util.isString($allowedOwners0) ) - #if( $allowedOwners0 == $identityValue ) - #set( $isOwnerAuthorized = true ) - #end - #end - ## [End] Owner Authorization Checks ** - - - ## [Start] Throw if unauthorized ** - #if( !($isStaticGroupAuthorized == true || $isOwnerAuthorized == true) ) - $util.unauthorized() - #end - ## [End] Throw if unauthorized ** -#end -## [End] Check authMode and execute owner/group checks ** - -$util.toJson(null)" -`; - -exports[`that checks subscription resolvers are generated with auth logic 3`] = ` -"## [Start] Determine request authentication mode ** -#if( $util.isNullOrEmpty($authMode) && !$util.isNull($ctx.identity) && !$util.isNull($ctx.identity.sub) && !$util.isNull($ctx.identity.issuer) && !$util.isNull($ctx.identity.username) && !$util.isNull($ctx.identity.claims) && !$util.isNull($ctx.identity.sourceIp) && !$util.isNull($ctx.identity.defaultAuthStrategy) ) - #set( $authMode = \\"userPools\\" ) -#end -## [End] Determine request authentication mode ** -## [Start] Check authMode and execute owner/group checks ** -#if( $authMode == \\"userPools\\" ) - ## [Start] Static Group Authorization Checks ** - #set($isStaticGroupAuthorized = $util.defaultIfNull( - $isStaticGroupAuthorized, false)) - ## Authorization rule: { allow: groups, groups: [\\"Admin\\"], groupClaim: \\"cognito:groups\\" } ** - #set( $userGroups = $util.defaultIfNull($ctx.identity.claims.get(\\"cognito:groups\\"), []) ) - #set( $allowedGroups = [\\"Admin\\"] ) - #foreach( $userGroup in $userGroups ) - #if( $allowedGroups.contains($userGroup) ) - #set( $isStaticGroupAuthorized = true ) - #break - #end - #end - ## [End] Static Group Authorization Checks ** - - - ## [Start] Owner Authorization Checks ** - #set( $isOwnerAuthorized = false ) - ## Authorization rule: { allow: owner, ownerField: \\"owner\\", identityClaim: \\"cognito:username\\" } ** - #set( $allowedOwners0 = $util.defaultIfNull($ctx.args.owner, null) ) - #set( $identityValue = $util.defaultIfNull($ctx.identity.claims.get(\\"username\\"), - $util.defaultIfNull($ctx.identity.claims.get(\\"cognito:username\\"), \\"___xamznone____\\")) ) - #if( $util.isList($allowedOwners0) ) - #foreach( $allowedOwner in $allowedOwners0 ) - #if( $allowedOwner == $identityValue ) - #set( $isOwnerAuthorized = true ) - #end - #end - #end - #if( $util.isString($allowedOwners0) ) - #if( $allowedOwners0 == $identityValue ) - #set( $isOwnerAuthorized = true ) - #end - #end - ## [End] Owner Authorization Checks ** - - - ## [Start] Throw if unauthorized ** - #if( !($isStaticGroupAuthorized == true || $isOwnerAuthorized == true) ) - $util.unauthorized() - #end - ## [End] Throw if unauthorized ** -#end -## [End] Check authMode and execute owner/group checks ** - -$util.toJson(null)" -`; - -exports[`that operation overwrites queries in auth operations 1`] = ` -"#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type) -#else -$util.toJson($ctx.result) -#end" -`; - -exports[`that operation overwrites queries in auth operations 2`] = ` -"#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type) -#else -$util.toJson($ctx.result) -#end" -`; - -exports[`that operation overwrites queries in auth operations 3`] = ` -"## [Start] Set default values. ** -$util.qr($context.args.input.put(\\"id\\", $util.defaultIfNull($ctx.args.input.id, $util.autoId()))) -#set( $createdAt = $util.time.nowISO8601() ) -## Automatically set the createdAt timestamp. ** -$util.qr($context.args.input.put(\\"createdAt\\", $util.defaultIfNull($ctx.args.input.createdAt, $createdAt))) -## Automatically set the updatedAt timestamp. ** -$util.qr($context.args.input.put(\\"updatedAt\\", $util.defaultIfNull($ctx.args.input.updatedAt, $createdAt))) -## [End] Set default values. ** -## [Start] Determine request authentication mode ** -#if( $util.isNullOrEmpty($authMode) && !$util.isNull($ctx.identity) && !$util.isNull($ctx.identity.sub) && !$util.isNull($ctx.identity.issuer) && !$util.isNull($ctx.identity.username) && !$util.isNull($ctx.identity.claims) && !$util.isNull($ctx.identity.sourceIp) && !$util.isNull($ctx.identity.defaultAuthStrategy) ) - #set( $authMode = \\"userPools\\" ) -#end -## [End] Determine request authentication mode ** -## [Start] Check authMode and execute owner/group checks ** -#if( $authMode == \\"userPools\\" ) - ## [Start] Static Group Authorization Checks ** - #set($isStaticGroupAuthorized = $util.defaultIfNull( - $isStaticGroupAuthorized, false)) - ## Authorization rule: { allow: groups, groups: [\\"Admin\\",\\"Dev\\"], groupClaim: \\"cognito:groups\\" } ** - #set( $userGroups = $util.defaultIfNull($ctx.identity.claims.get(\\"cognito:groups\\"), []) ) - #set( $allowedGroups = [\\"Admin\\", \\"Dev\\"] ) - #foreach( $userGroup in $userGroups ) - #if( $allowedGroups.contains($userGroup) ) - #set( $isStaticGroupAuthorized = true ) - #break - #end - #end - ## [End] Static Group Authorization Checks ** - - - ## No Dynamic Group Authorization Rules ** - - - ## No Owner Authorization Rules ** - - - ## [Start] Throw if unauthorized ** - #if( !($isStaticGroupAuthorized == true || $isDynamicGroupAuthorized == true || $isOwnerAuthorized == true) ) - $util.unauthorized() - #end - ## [End] Throw if unauthorized ** -#end -## [End] Check authMode and execute owner/group checks ** - -## [Start] Prepare DynamoDB PutItem Request. ** -$util.qr($context.args.input.put(\\"__typename\\", \\"Post\\")) -#if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_not_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_not_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end -#else - #set( $condition = { - \\"expression\\": \\"attribute_not_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) -#end -#if( $context.args.condition ) - #set( $condition.expressionValues = {} ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"PutItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": $util.dynamodb.toDynamoDBJson($ctx.args.input.id) -} #end, - \\"attributeValues\\": $util.dynamodb.toMapValuesJson($context.args.input), - \\"condition\\": $util.toJson($condition) -} -## [End] Prepare DynamoDB PutItem Request. **" -`; - -exports[`that operation overwrites queries in auth operations 4`] = ` -"## [Start] Determine request authentication mode ** -#if( $util.isNullOrEmpty($authMode) && !$util.isNull($ctx.identity) && !$util.isNull($ctx.identity.sub) && !$util.isNull($ctx.identity.issuer) && !$util.isNull($ctx.identity.username) && !$util.isNull($ctx.identity.claims) && !$util.isNull($ctx.identity.sourceIp) && !$util.isNull($ctx.identity.defaultAuthStrategy) ) - #set( $authMode = \\"userPools\\" ) -#end -## [End] Determine request authentication mode ** -## [Start] Check authMode and execute owner/group checks ** -#if( $authMode == \\"userPools\\" ) - ## [Start] Static Group Authorization Checks ** - #set($isStaticGroupAuthorized = $util.defaultIfNull( - $isStaticGroupAuthorized, false)) - ## Authorization rule: { allow: groups, groups: [\\"Admin\\",\\"Dev\\"], groupClaim: \\"cognito:groups\\" } ** - #set( $userGroups = $util.defaultIfNull($ctx.identity.claims.get(\\"cognito:groups\\"), []) ) - #set( $allowedGroups = [\\"Admin\\", \\"Dev\\"] ) - #foreach( $userGroup in $userGroups ) - #if( $allowedGroups.contains($userGroup) ) - #set( $isStaticGroupAuthorized = true ) - #break - #end - #end - ## [End] Static Group Authorization Checks ** - - - #if( ! $isStaticGroupAuthorized ) - ## No dynamic group authorization rules ** - - - ## No owner authorization rules ** - - - ## [Start] Collect Auth Condition ** - #set( $authCondition = $util.defaultIfNull($authCondition, { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -}) ) - #set( $totalAuthExpression = \\"\\" ) - ## Add dynamic group auth conditions if they exist ** - #if( $groupAuthExpressions ) - #foreach( $authExpr in $groupAuthExpressions ) - #set( $totalAuthExpression = \\"$totalAuthExpression $authExpr\\" ) - #if( $foreach.hasNext ) - #set( $totalAuthExpression = \\"$totalAuthExpression OR\\" ) - #end - #end - #end - #if( $groupAuthExpressionNames ) - $util.qr($authCondition.expressionNames.putAll($groupAuthExpressionNames)) - #end - #if( $groupAuthExpressionValues ) - $util.qr($authCondition.expressionValues.putAll($groupAuthExpressionValues)) - #end - ## Add owner auth conditions if they exist ** - #if( $totalAuthExpression != \\"\\" && $ownerAuthExpressions && $ownerAuthExpressions.size() > 0 ) - #set( $totalAuthExpression = \\"$totalAuthExpression OR\\" ) - #end - #if( $ownerAuthExpressions ) - #foreach( $authExpr in $ownerAuthExpressions ) - #set( $totalAuthExpression = \\"$totalAuthExpression $authExpr\\" ) - #if( $foreach.hasNext ) - #set( $totalAuthExpression = \\"$totalAuthExpression OR\\" ) - #end - #end - #end - #if( $ownerAuthExpressionNames ) - $util.qr($authCondition.expressionNames.putAll($ownerAuthExpressionNames)) - #end - #if( $ownerAuthExpressionValues ) - $util.qr($authCondition.expressionValues.putAll($ownerAuthExpressionValues)) - #end - ## Set final expression if it has changed. ** - #if( $totalAuthExpression != \\"\\" ) - #if( $util.isNullOrEmpty($authCondition.expression) ) - #set( $authCondition.expression = \\"($totalAuthExpression)\\" ) - #else - #set( $authCondition.expression = \\"$authCondition.expression AND ($totalAuthExpression)\\" ) - #end - #end - ## [End] Collect Auth Condition ** - #end - - - ## [Start] Throw if unauthorized ** - #if( !($isStaticGroupAuthorized == true || ($totalAuthExpression != \\"\\")) ) - $util.unauthorized() - #end - ## [End] Throw if unauthorized ** -#end -## [End] Check authMode and execute owner/group checks ** - -#set( $optionalNonNullableFields = [\\"title\\"] ) -#foreach( $field in $optionalNonNullableFields ) - #if( $context.arguments.input.keySet().contains($field) && $util.isNull($context.args.input.get($field)) ) -$util.error(\\"An argument you marked as Non-Null is set to Null in the query or the body of your request.\\") - #end -#end -#if( $authCondition && $authCondition.expression != \\"\\" ) - #set( $condition = $authCondition ) - #if( $modelObjectKey ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#id)\\")) - $util.qr($condition.expressionNames.put(\\"#id\\", \\"id\\")) - #end -#else - #if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - #set( $condition = { - \\"expression\\": \\"attribute_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) - #end -#end -## Automatically set the updatedAt timestamp. ** -$util.qr($context.args.input.put(\\"updatedAt\\", $util.defaultIfNull($ctx.args.input.updatedAt, $util.time.nowISO8601()))) -$util.qr($context.args.input.put(\\"__typename\\", \\"Post\\")) -## Update condition if type is @versioned ** -#if( $versionedCondition ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $versionedCondition.expression\\")) - $util.qr($condition.expressionNames.putAll($versionedCondition.expressionNames)) - $util.qr($condition.expressionValues.putAll($versionedCondition.expressionValues)) -#end -#if( $context.args.condition ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -#set( $expNames = {} ) -#set( $expValues = {} ) -#set( $expSet = {} ) -#set( $expAdd = {} ) -#set( $expRemove = [] ) -#if( $modelObjectKey ) - #set( $keyFields = [] ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($keyFields.add(\\"$entry.key\\")) - #end -#else - #set( $keyFields = [\\"id\\"] ) -#end -#foreach( $entry in $util.map.copyAndRemoveAllKeys($context.args.input, $keyFields).entrySet() ) - #if( !$util.isNull($dynamodbNameOverrideMap) && $dynamodbNameOverrideMap.containsKey(\\"$entry.key\\") ) - #set( $entryKeyAttributeName = $dynamodbNameOverrideMap.get(\\"$entry.key\\") ) - #else - #set( $entryKeyAttributeName = $entry.key ) - #end - #if( $util.isNull($entry.value) ) - #set( $discard = $expRemove.add(\\"#$entryKeyAttributeName\\") ) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - #else - $util.qr($expSet.put(\\"#$entryKeyAttributeName\\", \\":$entryKeyAttributeName\\")) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - $util.qr($expValues.put(\\":$entryKeyAttributeName\\", $util.dynamodb.toDynamoDB($entry.value))) - #end -#end -#set( $expression = \\"\\" ) -#if( !$expSet.isEmpty() ) - #set( $expression = \\"SET\\" ) - #foreach( $entry in $expSet.entrySet() ) - #set( $expression = \\"$expression $entry.key = $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expAdd.isEmpty() ) - #set( $expression = \\"$expression ADD\\" ) - #foreach( $entry in $expAdd.entrySet() ) - #set( $expression = \\"$expression $entry.key $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expRemove.isEmpty() ) - #set( $expression = \\"$expression REMOVE\\" ) - #foreach( $entry in $expRemove ) - #set( $expression = \\"$expression $entry\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#set( $update = {} ) -$util.qr($update.put(\\"expression\\", \\"$expression\\")) -#if( !$expNames.isEmpty() ) - $util.qr($update.put(\\"expressionNames\\", $expNames)) -#end -#if( !$expValues.isEmpty() ) - $util.qr($update.put(\\"expressionValues\\", $expValues)) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"UpdateItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": { - \\"S\\": $util.toJson($context.args.input.id) - } -} #end, - \\"update\\": $util.toJson($update), - \\"condition\\": $util.toJson($condition) -}" -`; - -exports[`that operation overwrites queries in auth operations 5`] = ` -"## [Start] Determine request authentication mode ** -#if( $util.isNullOrEmpty($authMode) && !$util.isNull($ctx.identity) && !$util.isNull($ctx.identity.sub) && !$util.isNull($ctx.identity.issuer) && !$util.isNull($ctx.identity.username) && !$util.isNull($ctx.identity.claims) && !$util.isNull($ctx.identity.sourceIp) && !$util.isNull($ctx.identity.defaultAuthStrategy) ) - #set( $authMode = \\"userPools\\" ) -#end -## [End] Determine request authentication mode ** -## [Start] Check authMode and execute owner/group checks ** -#if( $authMode == \\"userPools\\" ) - ## [Start] Static Group Authorization Checks ** - #set($isStaticGroupAuthorized = $util.defaultIfNull( - $isStaticGroupAuthorized, false)) - ## Authorization rule: { allow: groups, groups: [\\"Admin\\",\\"Dev\\"], groupClaim: \\"cognito:groups\\" } ** - #set( $userGroups = $util.defaultIfNull($ctx.identity.claims.get(\\"cognito:groups\\"), []) ) - #set( $allowedGroups = [\\"Admin\\", \\"Dev\\"] ) - #foreach( $userGroup in $userGroups ) - #if( $allowedGroups.contains($userGroup) ) - #set( $isStaticGroupAuthorized = true ) - #break - #end - #end - ## [End] Static Group Authorization Checks ** - - - #if( ! $isStaticGroupAuthorized ) - ## No dynamic group authorization rules ** - - - ## No owner authorization rules ** - - - ## [Start] Collect Auth Condition ** - #set( $authCondition = $util.defaultIfNull($authCondition, { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -}) ) - #set( $totalAuthExpression = \\"\\" ) - ## Add dynamic group auth conditions if they exist ** - #if( $groupAuthExpressions ) - #foreach( $authExpr in $groupAuthExpressions ) - #set( $totalAuthExpression = \\"$totalAuthExpression $authExpr\\" ) - #if( $foreach.hasNext ) - #set( $totalAuthExpression = \\"$totalAuthExpression OR\\" ) - #end - #end - #end - #if( $groupAuthExpressionNames ) - $util.qr($authCondition.expressionNames.putAll($groupAuthExpressionNames)) - #end - #if( $groupAuthExpressionValues ) - $util.qr($authCondition.expressionValues.putAll($groupAuthExpressionValues)) - #end - ## Add owner auth conditions if they exist ** - #if( $totalAuthExpression != \\"\\" && $ownerAuthExpressions && $ownerAuthExpressions.size() > 0 ) - #set( $totalAuthExpression = \\"$totalAuthExpression OR\\" ) - #end - #if( $ownerAuthExpressions ) - #foreach( $authExpr in $ownerAuthExpressions ) - #set( $totalAuthExpression = \\"$totalAuthExpression $authExpr\\" ) - #if( $foreach.hasNext ) - #set( $totalAuthExpression = \\"$totalAuthExpression OR\\" ) - #end - #end - #end - #if( $ownerAuthExpressionNames ) - $util.qr($authCondition.expressionNames.putAll($ownerAuthExpressionNames)) - #end - #if( $ownerAuthExpressionValues ) - $util.qr($authCondition.expressionValues.putAll($ownerAuthExpressionValues)) - #end - ## Set final expression if it has changed. ** - #if( $totalAuthExpression != \\"\\" ) - #if( $util.isNullOrEmpty($authCondition.expression) ) - #set( $authCondition.expression = \\"($totalAuthExpression)\\" ) - #else - #set( $authCondition.expression = \\"$authCondition.expression AND ($totalAuthExpression)\\" ) - #end - #end - ## [End] Collect Auth Condition ** - #end - - - ## [Start] Throw if unauthorized ** - #if( !($isStaticGroupAuthorized == true || ($totalAuthExpression != \\"\\")) ) - $util.unauthorized() - #end - ## [End] Throw if unauthorized ** -#end -## [End] Check authMode and execute owner/group checks ** - -#if( $authCondition ) - #set( $condition = $authCondition ) - #if( $modelObjectKey ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#id)\\")) - $util.qr($condition.expressionNames.put(\\"#id\\", \\"id\\")) - #end -#else - #if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - #set( $condition = { - \\"expression\\": \\"attribute_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) - #end -#end -#if( $versionedCondition ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $versionedCondition.expression\\")) - $util.qr($condition.expressionNames.putAll($versionedCondition.expressionNames)) - #set( $expressionValues = $util.defaultIfNull($condition.expressionValues, {}) ) - $util.qr($expressionValues.putAll($versionedCondition.expressionValues)) - #set( $condition.expressionValues = $expressionValues ) -#end -#if( $context.args.condition ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - #set( $conditionExpressionValues = $util.defaultIfNull($condition.expressionValues, {}) ) - $util.qr($conditionExpressionValues.putAll($conditionFilterExpressions.expressionValues)) - #set( $condition.expressionValues = $conditionExpressionValues ) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"DeleteItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": $util.dynamodb.toDynamoDBJson($ctx.args.input.id) -} #end, - \\"condition\\": $util.toJson($condition) -}" -`; - -exports[`that subscriptions are only generated if the respective mutation operation exists 1`] = ` -"## [Start] Determine request authentication mode ** -#if( $util.isNullOrEmpty($authMode) && !$util.isNull($ctx.identity) && !$util.isNull($ctx.identity.sub) && !$util.isNull($ctx.identity.issuer) && !$util.isNull($ctx.identity.username) && !$util.isNull($ctx.identity.claims) && !$util.isNull($ctx.identity.sourceIp) && !$util.isNull($ctx.identity.defaultAuthStrategy) ) - #set( $authMode = \\"userPools\\" ) -#end -## [End] Determine request authentication mode ** -## [Start] Check authMode and execute owner/group checks ** -#if( $authMode == \\"userPools\\" ) - ## No Static Group Authorization Rules ** - - - ## [Start] Owner Authorization Checks ** - #set( $isOwnerAuthorized = false ) - ## Authorization rule: { allow: owner, ownerField: \\"owner\\", identityClaim: \\"cognito:username\\" } ** - #set( $allowedOwners0 = $util.defaultIfNull($ctx.args.owner, null) ) - #set( $identityValue = $util.defaultIfNull($ctx.identity.claims.get(\\"username\\"), - $util.defaultIfNull($ctx.identity.claims.get(\\"cognito:username\\"), \\"___xamznone____\\")) ) - #if( $util.isList($allowedOwners0) ) - #foreach( $allowedOwner in $allowedOwners0 ) - #if( $allowedOwner == $identityValue ) - #set( $isOwnerAuthorized = true ) - #end - #end - #end - #if( $util.isString($allowedOwners0) ) - #if( $allowedOwners0 == $identityValue ) - #set( $isOwnerAuthorized = true ) - #end - #end - ## [End] Owner Authorization Checks ** - - - ## [Start] Throw if unauthorized ** - #if( !($isStaticGroupAuthorized == true || $isOwnerAuthorized == true) ) - $util.unauthorized() - #end - ## [End] Throw if unauthorized ** -#end -## [End] Check authMode and execute owner/group checks ** - -$util.toJson(null)" -`; - -exports[`that subscriptions are only generated if the respective mutation operation exists 2`] = ` -"## [Start] Determine request authentication mode ** -#if( $util.isNullOrEmpty($authMode) && !$util.isNull($ctx.identity) && !$util.isNull($ctx.identity.sub) && !$util.isNull($ctx.identity.issuer) && !$util.isNull($ctx.identity.username) && !$util.isNull($ctx.identity.claims) && !$util.isNull($ctx.identity.sourceIp) && !$util.isNull($ctx.identity.defaultAuthStrategy) ) - #set( $authMode = \\"userPools\\" ) -#end -## [End] Determine request authentication mode ** -## [Start] Check authMode and execute owner/group checks ** -#if( $authMode == \\"userPools\\" ) - ## No Static Group Authorization Rules ** - - - ## [Start] Owner Authorization Checks ** - #set( $isOwnerAuthorized = false ) - ## Authorization rule: { allow: owner, ownerField: \\"owner\\", identityClaim: \\"cognito:username\\" } ** - #set( $allowedOwners0 = $util.defaultIfNull($ctx.args.owner, null) ) - #set( $identityValue = $util.defaultIfNull($ctx.identity.claims.get(\\"username\\"), - $util.defaultIfNull($ctx.identity.claims.get(\\"cognito:username\\"), \\"___xamznone____\\")) ) - #if( $util.isList($allowedOwners0) ) - #foreach( $allowedOwner in $allowedOwners0 ) - #if( $allowedOwner == $identityValue ) - #set( $isOwnerAuthorized = true ) - #end - #end - #end - #if( $util.isString($allowedOwners0) ) - #if( $allowedOwners0 == $identityValue ) - #set( $isOwnerAuthorized = true ) - #end - #end - ## [End] Owner Authorization Checks ** - - - ## [Start] Throw if unauthorized ** - #if( !($isStaticGroupAuthorized == true || $isOwnerAuthorized == true) ) - $util.unauthorized() - #end - ## [End] Throw if unauthorized ** -#end -## [End] Check authMode and execute owner/group checks ** - -$util.toJson(null)" -`; diff --git a/packages/graphql-auth-transformer/src/__tests__/__snapshots__/PerFieldAuthArgument.test.ts.snap b/packages/graphql-auth-transformer/src/__tests__/__snapshots__/PerFieldAuthArgument.test.ts.snap deleted file mode 100644 index 419254f7d6..0000000000 --- a/packages/graphql-auth-transformer/src/__tests__/__snapshots__/PerFieldAuthArgument.test.ts.snap +++ /dev/null @@ -1,190 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`per-field @auth on a @connection field 1`] = ` -"#if( $util.isNullOrEmpty($ctx.result) ) - #return -#end -## [Start] Determine request authentication mode ** -#if( $util.isNullOrEmpty($authMode) && !$util.isNull($ctx.identity) && !$util.isNull($ctx.identity.sub) && !$util.isNull($ctx.identity.issuer) && !$util.isNull($ctx.identity.username) && !$util.isNull($ctx.identity.claims) && !$util.isNull($ctx.identity.sourceIp) && !$util.isNull($ctx.identity.defaultAuthStrategy) ) - #set( $authMode = \\"userPools\\" ) -#end -## [End] Determine request authentication mode ** -## [Start] Check authMode and execute owner/group checks ** -#if( $authMode == \\"userPools\\" ) - ## [Start] Static Group Authorization Checks ** - #set($isStaticGroupAuthorized = $util.defaultIfNull( - $isStaticGroupAuthorized, false)) - ## Authorization rule: { allow: groups, groups: [\\"admin\\"], groupClaim: \\"cognito:groups\\" } ** - #set( $userGroups = $util.defaultIfNull($ctx.identity.claims.get(\\"cognito:groups\\"), []) ) - #set( $allowedGroups = [\\"admin\\"] ) - #foreach( $userGroup in $userGroups ) - #if( $allowedGroups.contains($userGroup) ) - #set( $isStaticGroupAuthorized = true ) - #break - #end - #end - ## [End] Static Group Authorization Checks ** - - - ## No Dynamic Group Authorization Rules ** - - - ## [Start] Owner Authorization Checks ** - #set( $isOwnerAuthorized = $util.defaultIfNull($isOwnerAuthorized, false) ) - ## Authorization rule: { allow: owner, ownerField: \\"moderator\\", identityClaim: \\"cognito:username\\" } ** - #set( $allowedOwners0 = $util.defaultIfNull($ctx.result.moderator, []) ) - #set( $identityValue = $util.defaultIfNull($ctx.identity.claims.get(\\"username\\"), $util.defaultIfNull($ctx.identity.claims.get(\\"cognito:username\\"), \\"___xamznone____\\")) ) - #if( $util.isList($allowedOwners0) ) - #foreach( $allowedOwner in $allowedOwners0 ) - #if( $allowedOwner == $identityValue ) - #set( $isOwnerAuthorized = true ) - #end - #end - #end - #if( $util.isString($allowedOwners0) ) - #if( $allowedOwners0 == $identityValue ) - #set( $isOwnerAuthorized = true ) - #end - #end - ## [End] Owner Authorization Checks ** - - - ## [Start] Throw if unauthorized ** - #if( !($isStaticGroupAuthorized == true || $isDynamicGroupAuthorized == true || $isOwnerAuthorized == true) ) - $util.unauthorized() - #end - ## [End] Throw if unauthorized ** -#end -## [End] Check authMode and execute owner/group checks ** - -#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type) -#else -$util.toJson($ctx.result) -#end" -`; - -exports[`per-field @auth without model 1`] = ` -Object { - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "appsync:GraphQL", - ], - "Effect": "Allow", - "Resource": Array [ - Object { - "Fn::Sub": Array [ - "arn:aws:appsync:\${AWS::Region}:\${AWS::AccountId}:apis/\${apiId}/types/\${typeName}/fields/\${fieldName}", - Object { - "apiId": Object { - "Fn::GetAtt": Array [ - "GraphQLAPI", - "ApiId", - ], - }, - "fieldName": "listContext", - "typeName": "Query", - }, - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "Roles": Array [ - Object { - "Ref": "authRoleName", - }, - ], - }, - "Type": "AWS::IAM::ManagedPolicy", -} -`; - -exports[`per-field @auth without model 2`] = ` -"## [Start] Determine request authentication mode ** -#if( $util.isNullOrEmpty($authMode) && !$util.isNull($ctx.identity) && !$util.isNull($ctx.identity.sub) && !$util.isNull($ctx.identity.issuer) && !$util.isNull($ctx.identity.username) && !$util.isNull($ctx.identity.claims) && !$util.isNull($ctx.identity.sourceIp) && !$util.isNull($ctx.identity.defaultAuthStrategy) ) - #set( $authMode = \\"userPools\\" ) -#end -## [End] Determine request authentication mode ** -## [Start] Check authMode and execute owner/group checks ** -#if( $authMode == \\"userPools\\" ) - ## [Start] Static Group Authorization Checks ** - #set($listContext_isStaticGroupAuthorized = $util.defaultIfNull( - $listContext_isStaticGroupAuthorized, false)) - ## Authorization rule: { allow: groups, groups: [\\"Allowed\\"], groupClaim: \\"cognito:groups\\" } ** - #set( $userGroups = $util.defaultIfNull($ctx.identity.claims.get(\\"cognito:groups\\"), []) ) - #set( $allowedGroups = [\\"Allowed\\"] ) - #foreach( $userGroup in $userGroups ) - #if( $allowedGroups.contains($userGroup) ) - #set( $listContext_isStaticGroupAuthorized = true ) - #break - #end - #end - ## [End] Static Group Authorization Checks ** - - - ## [Start] Throw if unauthorized ** - #if( $listContext_isStaticGroupAuthorized == false ) - $util.unauthorized() - #end - ## [End] Throw if unauthorized ** -#end -## [End] Check authMode and execute owner/group checks ** - -{ - \\"version\\": \\"2018-05-29\\", - \\"payload\\": {} -}" -`; - -exports[`that subscriptions are only generated if the respective mutation operation exists 1`] = ` -"## [Start] Checking for allowed operations which can return this field ** -#set( $operation = $util.defaultIfNull($context.source.operation, \\"null\\") ) -#if( $operation == \\"Mutation\\" ) -$util.toJson(null) -#else - $util.toJson($context.source.secret) -#end -## [End] Checking for allowed operations which can return this field **" -`; - -exports[`that subscriptions are only generated if the respective mutation operation exists 2`] = ` -"## [Start] Setting the operation ** -$util.qr($ctx.result.put(\\"operation\\", \\"Mutation\\")) -## [End] Setting the operation ** - -#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type) -#else -$util.toJson($ctx.result) -#end" -`; - -exports[`that subscriptions are only generated if the respective mutation operation exists 3`] = ` -"## [Start] Setting the operation ** -$util.qr($ctx.result.put(\\"operation\\", \\"Mutation\\")) -## [End] Setting the operation ** - -#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type) -#else -$util.toJson($ctx.result) -#end" -`; - -exports[`that subscriptions are only generated if the respective mutation operation exists 4`] = ` -"## [Start] Setting the operation ** -$util.qr($ctx.result.put(\\"operation\\", \\"Mutation\\")) -## [End] Setting the operation ** - -#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type) -#else -$util.toJson($ctx.result) -#end" -`; diff --git a/packages/graphql-auth-transformer/src/__tests__/__snapshots__/SearchableAuthTransformer.test.ts.snap b/packages/graphql-auth-transformer/src/__tests__/__snapshots__/SearchableAuthTransformer.test.ts.snap deleted file mode 100644 index ca56e04c0c..0000000000 --- a/packages/graphql-auth-transformer/src/__tests__/__snapshots__/SearchableAuthTransformer.test.ts.snap +++ /dev/null @@ -1,206 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`auth logic is enabled for iam/apiKey auth rules in response es resolver 1`] = ` -"type Post @aws_api_key @aws_iam { - id: ID! - content: String - createdAt: AWSDateTime! - updatedAt: AWSDateTime! - secret: String @aws_iam -} - -enum ModelSortDirection { - ASC - DESC -} - -type ModelPostConnection @aws_api_key @aws_iam { - items: [Post]! - nextToken: String -} - -input ModelStringFilterInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String -} - -input ModelIDFilterInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID -} - -input ModelIntFilterInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelFloatFilterInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] -} - -input ModelBooleanFilterInput { - ne: Boolean - eq: Boolean -} - -input ModelPostFilterInput { - id: ModelIDFilterInput - content: ModelStringFilterInput - secret: ModelStringFilterInput - and: [ModelPostFilterInput] - or: [ModelPostFilterInput] - not: ModelPostFilterInput -} - -type Query { - searchPosts(filter: SearchablePostFilterInput, sort: SearchablePostSortInput, limit: Int, nextToken: String, from: Int): SearchablePostConnection @aws_api_key @aws_iam - getPost(id: ID!): Post @aws_api_key @aws_iam - listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection @aws_api_key @aws_iam -} - -input CreatePostInput { - id: ID - content: String - secret: String -} - -input UpdatePostInput { - id: ID! - content: String - secret: String -} - -input DeletePostInput { - id: ID! -} - -type Mutation { - createPost(input: CreatePostInput!): Post @aws_api_key @aws_iam - updatePost(input: UpdatePostInput!): Post @aws_api_key @aws_iam - deletePost(input: DeletePostInput!): Post @aws_api_key @aws_iam -} - -type Subscription { - onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) @aws_api_key @aws_iam - onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) @aws_api_key @aws_iam - onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) @aws_api_key @aws_iam -} - -input SearchableStringFilterInput { - ne: String - gt: String - lt: String - gte: String - lte: String - eq: String - match: String - matchPhrase: String - matchPhrasePrefix: String - multiMatch: String - exists: Boolean - wildcard: String - regexp: String - range: [String] -} - -input SearchableIntFilterInput { - ne: Int - gt: Int - lt: Int - gte: Int - lte: Int - eq: Int - range: [Int] -} - -input SearchableFloatFilterInput { - ne: Float - gt: Float - lt: Float - gte: Float - lte: Float - eq: Float - range: [Float] -} - -input SearchableBooleanFilterInput { - eq: Boolean - ne: Boolean -} - -input SearchableIDFilterInput { - ne: ID - gt: ID - lt: ID - gte: ID - lte: ID - eq: ID - match: ID - matchPhrase: ID - matchPhrasePrefix: ID - multiMatch: ID - exists: Boolean - wildcard: ID - regexp: ID - range: [ID] -} - -input SearchablePostFilterInput { - id: SearchableIDFilterInput - content: SearchableStringFilterInput - secret: SearchableStringFilterInput - and: [SearchablePostFilterInput] - or: [SearchablePostFilterInput] - not: SearchablePostFilterInput -} - -enum SearchableSortDirection { - asc - desc -} - -enum SearchablePostSortableFields { - id - content - secret -} - -input SearchablePostSortInput { - field: SearchablePostSortableFields - direction: SearchableSortDirection -} - -type SearchablePostConnection @aws_api_key @aws_iam { - items: [Post]! - nextToken: String - total: Int -} -" -`; diff --git a/packages/graphql-auth-transformer/src/__tests__/test-helpers.ts b/packages/graphql-auth-transformer/src/__tests__/test-helpers.ts deleted file mode 100644 index 9f50bd4e52..0000000000 --- a/packages/graphql-auth-transformer/src/__tests__/test-helpers.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ObjectTypeDefinitionNode, FieldDefinitionNode, DocumentNode, Kind } from 'graphql'; - -export const getObjectType = (doc: DocumentNode, type: string): ObjectTypeDefinitionNode | undefined => { - return doc.definitions.find((def) => def.kind === Kind.OBJECT_TYPE_DEFINITION && def.name.value === type) as - | ObjectTypeDefinitionNode - | undefined; -}; -export const getField = (obj: ObjectTypeDefinitionNode, fieldName: string): FieldDefinitionNode | void => { - return obj.fields?.find((f) => f.name.value === fieldName); -}; diff --git a/packages/graphql-auth-transformer/src/constants.ts b/packages/graphql-auth-transformer/src/constants.ts deleted file mode 100644 index 38eaeca120..0000000000 --- a/packages/graphql-auth-transformer/src/constants.ts +++ /dev/null @@ -1,10 +0,0 @@ -export const OWNER_AUTH_STRATEGY = 'owner'; -export const DEFAULT_OWNER_FIELD = 'owner'; -export const DEFAULT_IDENTITY_FIELD = 'username'; -export const GROUPS_AUTH_STRATEGY = 'groups'; -export const DEFAULT_GROUPS_FIELD = 'groups'; -export const DEFAULT_GROUP_CLAIM = 'cognito:groups'; -export const ON_CREATE_FIELD = 'onCreate'; -export const ON_UPDATE_FIELD = 'onUpdate'; -export const ON_DELETE_FIELD = 'onDelete'; -export const AUTH_NON_MODEL_TYPES = 'authNonModelTypes'; diff --git a/packages/graphql-auth-transformer/src/index.ts b/packages/graphql-auth-transformer/src/index.ts deleted file mode 100644 index 12b0a664d6..0000000000 --- a/packages/graphql-auth-transformer/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './ModelAuthTransformer'; -// No-op change to trigger re-publish diff --git a/packages/graphql-auth-transformer/src/resources.ts b/packages/graphql-auth-transformer/src/resources.ts deleted file mode 100644 index 61c4be740b..0000000000 --- a/packages/graphql-auth-transformer/src/resources.ts +++ /dev/null @@ -1,1135 +0,0 @@ -import Template from 'cloudform-types/types/template'; -import { AppSync, Fn, StringParameter, Refs, NumberParameter, IAM, Value } from 'cloudform-types'; -import { - str, - ref, - obj, - set, - iff, - list, - raw, - forEach, - compoundExpression, - qref, - equals, - comment, - or, - Expression, - and, - not, - parens, - toJson, - block, - print, - ifElse, - newline, - methodCall, - RESOLVER_VERSION_ID, - isNullOrEmpty, - ret, -} from 'graphql-mapping-template'; -import { ResourceConstants, NONE_VALUE } from 'graphql-transformer-common'; -import GraphQLApi, { - GraphQLApiProperties, - UserPoolConfig, - AdditionalAuthenticationProvider, - OpenIDConnectConfig, -} from 'cloudform-types/types/appSync/graphQlApi'; -import { FieldDefinitionNode } from 'graphql'; -import ManagedPolicy from 'cloudform-types/types/iam/managedPolicy'; -import * as Transformer from './ModelAuthTransformer'; - -import { DEFAULT_OWNER_FIELD, DEFAULT_IDENTITY_FIELD, DEFAULT_GROUPS_FIELD, DEFAULT_GROUP_CLAIM } from './constants'; -import { AuthRule, AuthProvider } from './AuthRule'; - -function replaceIfUsername(identityClaim: string): string { - return identityClaim === 'username' ? 'cognito:username' : identityClaim; -} - -function isUsername(identityClaim: string): boolean { - return identityClaim === 'username'; -} - -export class ResourceFactory { - public makeParams() { - return { - [ResourceConstants.PARAMETERS.AppSyncApiName]: new StringParameter({ - Description: 'The name of the AppSync API', - Default: 'AppSyncSimpleTransform', - }), - [ResourceConstants.PARAMETERS.APIKeyExpirationEpoch]: new NumberParameter({ - Description: - 'The epoch time in seconds when the API Key should expire.' + - ' Setting this to 0 will default to 7 days from the deployment date.' + - ' Setting this to -1 will not create an API Key.', - Default: 0, - MinValue: -1, - }), - [ResourceConstants.PARAMETERS.CreateAPIKey]: new NumberParameter({ - Description: - 'The boolean value to control if an API Key will be created or not.' + - ' The value of the property is automatically set by the CLI.' + - ' If the value is set to 0 no API Key will be created.', - Default: 0, - MinValue: 0, - MaxValue: 1, - }), - [ResourceConstants.PARAMETERS.AuthCognitoUserPoolId]: new StringParameter({ - Description: 'The id of an existing User Pool to connect. If this is changed, a user pool will not be created for you.', - Default: ResourceConstants.NONE, - }), - }; - } - - /** - * Creates the barebones template for an application. - */ - public initTemplate(apiKeyConfig: Transformer.ApiKeyConfig): Template { - return { - Parameters: this.makeParams(), - Resources: { - [ResourceConstants.RESOURCES.APIKeyLogicalID]: this.makeAppSyncApiKey(apiKeyConfig), - }, - Outputs: { - [ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput]: this.makeApiKeyOutput(), - }, - Conditions: { - [ResourceConstants.CONDITIONS.ShouldCreateAPIKey]: Fn.Equals(Fn.Ref(ResourceConstants.PARAMETERS.CreateAPIKey), 1), - [ResourceConstants.CONDITIONS.APIKeyExpirationEpochIsPositive]: Fn.And([ - Fn.Not(Fn.Equals(Fn.Ref(ResourceConstants.PARAMETERS.APIKeyExpirationEpoch), -1)), - Fn.Not(Fn.Equals(Fn.Ref(ResourceConstants.PARAMETERS.APIKeyExpirationEpoch), 0)), - ]), - }, - }; - } - - public makeAppSyncApiKey(apiKeyConfig: Transformer.ApiKeyConfig) { - let expirationDays = 7; - if (apiKeyConfig && apiKeyConfig.apiKeyExpirationDays) { - expirationDays = apiKeyConfig.apiKeyExpirationDays; - } - // add delay expiration time is valid upon resource creation - let expirationDateInSeconds = 60 * 60 * 24 * expirationDays; // sec * min * hour * days - // Add a 30 minute time delay if set to 1 day: https://github.com/aws-amplify/amplify-cli/issues/4460 - // initially this was 2 minutes but with iterative deployments it is possible for deployments to take much longer than that - // if an iterative deployment takes longer than 30 mins, and API key expiration is set to 1 day, deployments may still fail - if (expirationDays === 1) expirationDateInSeconds += 60 * 30; - const nowEpochTime = Math.floor(Date.now() / 1000); - return new AppSync.ApiKey({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - Description: apiKeyConfig && apiKeyConfig.description ? apiKeyConfig.description : undefined, - Expires: Fn.If( - ResourceConstants.CONDITIONS.APIKeyExpirationEpochIsPositive, - Fn.Ref(ResourceConstants.PARAMETERS.APIKeyExpirationEpoch), - nowEpochTime + expirationDateInSeconds, - ), - }).condition(ResourceConstants.CONDITIONS.ShouldCreateAPIKey); - } - - /** - * Outputs - */ - public makeApiKeyOutput(): any { - return { - Description: "Your GraphQL API key. Provide via 'x-api-key' header.", - Value: Fn.GetAtt(ResourceConstants.RESOURCES.APIKeyLogicalID, 'ApiKey'), - Export: { - Name: Fn.Join(':', [Refs.StackName, 'GraphQLApiKey']), - }, - Condition: ResourceConstants.CONDITIONS.ShouldCreateAPIKey, - }; - } - - public updateGraphQLAPIWithAuth(apiRecord: GraphQLApi, authConfig: Transformer.AppSyncAuthConfiguration) { - let properties: GraphQLApiProperties = { - ...apiRecord.Properties, - Name: apiRecord.Properties.Name, - AuthenticationType: authConfig.defaultAuthentication.authenticationType, - UserPoolConfig: undefined, - OpenIDConnectConfig: undefined, - }; - - switch (authConfig.defaultAuthentication.authenticationType) { - case 'AMAZON_COGNITO_USER_POOLS': - properties.UserPoolConfig = new UserPoolConfig({ - UserPoolId: Fn.Ref(ResourceConstants.PARAMETERS.AuthCognitoUserPoolId), - AwsRegion: Refs.Region, - DefaultAction: 'ALLOW', - }); - break; - case 'OPENID_CONNECT': - if (!authConfig.defaultAuthentication.openIDConnectConfig) { - throw new Error('openIDConnectConfig is not configured for defaultAuthentication'); - } - - properties.OpenIDConnectConfig = this.assignOpenIDConnectConfig(authConfig.defaultAuthentication.openIDConnectConfig); - break; - } - - // Configure additional authentication providers - if (authConfig.additionalAuthenticationProviders && authConfig.additionalAuthenticationProviders.length > 0) { - const additionalAuthenticationProviders = new Array(); - - for (const sourceProvider of authConfig.additionalAuthenticationProviders) { - let provider: AdditionalAuthenticationProvider; - - switch (sourceProvider.authenticationType) { - case 'AMAZON_COGNITO_USER_POOLS': - provider = { - AuthenticationType: 'AMAZON_COGNITO_USER_POOLS', - UserPoolConfig: new UserPoolConfig({ - UserPoolId: Fn.Ref(ResourceConstants.PARAMETERS.AuthCognitoUserPoolId), - AwsRegion: Refs.Region, - }), - }; - break; - case 'API_KEY': - provider = { - AuthenticationType: 'API_KEY', - }; - break; - case 'AWS_IAM': - provider = { - AuthenticationType: 'AWS_IAM', - }; - break; - case 'OPENID_CONNECT': - if (!sourceProvider.openIDConnectConfig) { - throw new Error('openIDConnectConfig is not configured for provider'); - } - - provider = { - AuthenticationType: 'OPENID_CONNECT', - OpenIDConnectConfig: this.assignOpenIDConnectConfig(sourceProvider.openIDConnectConfig), - }; - break; - } - - additionalAuthenticationProviders.push(provider); - } - - properties.AdditionalAuthenticationProviders = additionalAuthenticationProviders; - } - - return new GraphQLApi(properties); - } - - private assignOpenIDConnectConfig(config: Transformer.OpenIDConnectConfig) { - return new OpenIDConnectConfig({ - Issuer: config.issuerUrl, - ClientId: config.clientId, - IatTTL: config.iatTTL, - AuthTTL: config.authTTL, - }); - } - - public blankResolver(type: string, field: string) { - return new AppSync.Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: 'NONE', - FieldName: field, - TypeName: type, - RequestMappingTemplate: print( - obj({ - version: str(RESOLVER_VERSION_ID), - payload: obj({}), - }), - ), - ResponseMappingTemplate: print(ref(`util.toJson($context.source.${field})`)), - }); - } - - public noneDataSource() { - return new AppSync.DataSource({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - Name: 'NONE', - Type: 'NONE', - }); - } - - /** - * Builds a VTL expression that will set the - * ResourceConstants.SNIPPETS.IsStaticGroupAuthorizedVariable variable to - * true if the user is static group authorized. - * @param rules The list of static group authorization rules. - */ - public staticGroupAuthorizationExpression(rules: AuthRule[], field?: FieldDefinitionNode): Expression { - if (!rules || rules.length === 0) { - return comment(`No Static Group Authorization Rules`); - } - const variableToSet = this.getStaticAuthorizationVariable(field); - let groupAuthorizationExpressions = []; - for (const rule of rules) { - const groups = rule.groups; - const groupClaimAttribute = rule.groupClaim || DEFAULT_GROUP_CLAIM; - - if (groups) { - groupAuthorizationExpressions = groupAuthorizationExpressions.concat( - comment(`Authorization rule: { allow: groups, groups: ${JSON.stringify(groups)}, groupClaim: "${groupClaimAttribute}" }`), - this.setUserGroups(rule.groupClaim), - set(ref('allowedGroups'), list(groups.map((s) => str(s)))), - forEach(ref('userGroup'), ref('userGroups'), [ - iff(raw(`$allowedGroups.contains($userGroup)`), compoundExpression([set(ref(variableToSet), raw('true')), raw('#break')])), - ]), - ); - } - } - const staticGroupAuthorizedVariable = this.getStaticAuthorizationVariable(field); - - // tslint:disable-next-line - return block('Static Group Authorization Checks', [ - raw(`#set($${staticGroupAuthorizedVariable} = $util.defaultIfNull( - $${staticGroupAuthorizedVariable}, false))`), - ...groupAuthorizationExpressions, - ]); - } - - /** - * Given a set of dynamic group authorization rules verifies that input - * value satisfies at least one dynamic group authorization rule. - * @param rules The list of authorization rules. - * @param variableToCheck The name of the value containing the input. - * @param variableToSet The name of the variable to set when auth is satisfied. - */ - public dynamicGroupAuthorizationExpressionForCreateOperations( - rules: AuthRule[], - variableToCheck: string = 'ctx.args.input', - variableToSet: string = ResourceConstants.SNIPPETS.IsDynamicGroupAuthorizedVariable, - ): Expression { - if (!rules || rules.length === 0) { - return comment(`No Dynamic Group Authorization Rules`); - } - return block('Dynamic Group Authorization Checks', [ - this.dynamicAuthorizationExpressionForCreate(rules, variableToCheck, variableToSet), - ]); - } - - /** - * Given a set of dynamic group authorization rules verifies that input - * value satisfies at least one dynamic group authorization rule. - * @param rules The list of authorization rules. - * @param variableToCheck The name of the value containing the input. - * @param variableToSet The name of the variable to set when auth is satisfied. - */ - public dynamicGroupAuthorizationExpressionForCreateOperationsByField( - rules: AuthRule[], - fieldToCheck: string, - variableToCheck: string = 'ctx.args.input', - variableToSet: string = ResourceConstants.SNIPPETS.IsDynamicGroupAuthorizedVariable, - ): Expression { - if (!rules || rules.length === 0) { - return comment(`No dynamic group authorization rules for field "${fieldToCheck}"`); - } - let groupAuthorizationExpression: Expression = this.dynamicAuthorizationExpressionForCreate( - rules, - variableToCheck, - variableToSet, - (rule) => `Authorization rule on field "${fieldToCheck}": { allow: ${rule.allow}, \ -groupsField: "${rule.groupsField || DEFAULT_GROUPS_FIELD}", groupClaim: "${rule.groupClaim || DEFAULT_GROUP_CLAIM}" }`, - ); - return block(`Dynamic group authorization rules for field "${fieldToCheck}"`, [groupAuthorizationExpression]); - } - - private dynamicAuthorizationExpressionForCreate( - rules: AuthRule[], - variableToCheck: string = 'ctx.args.input', - variableToSet: string = ResourceConstants.SNIPPETS.IsDynamicGroupAuthorizedVariable, - formatComment?: (rule: AuthRule) => string, - ) { - let groupAuthorizationExpressions = []; - for (const rule of rules) { - // for loop do check of rules here - const groupsAttribute = rule.groupsField || DEFAULT_GROUPS_FIELD; - const groupClaimAttribute = rule.groupClaim || DEFAULT_GROUP_CLAIM; - groupAuthorizationExpressions = groupAuthorizationExpressions.concat( - formatComment - ? comment(formatComment(rule)) - : comment(`Authorization rule: { allow: ${rule.allow}, groupsField: "${groupsAttribute}", groupClaim: "${groupClaimAttribute}"`), - this.setUserGroups(rule.groupClaim), - set(ref(variableToSet), raw(`$util.defaultIfNull($${variableToSet}, false)`)), - forEach(ref('userGroup'), ref('userGroups'), [ - iff( - raw(`$util.isList($ctx.args.input.${groupsAttribute})`), - iff(ref(`${variableToCheck}.${groupsAttribute}.contains($userGroup)`), set(ref(variableToSet), raw('true'))), - ), - iff( - raw(`$util.isString($ctx.args.input.${groupsAttribute})`), - iff(raw(`$ctx.args.input.${groupsAttribute} == $userGroup`), set(ref(variableToSet), raw('true'))), - ), - ]), - ); - } - - return compoundExpression(groupAuthorizationExpressions); - } - - /** - * Given a set of owner authorization rules verifies that input - * value satisfies at least one rule. - * @param rules The list of authorization rules. - * @param variableToCheck The name of the value containing the input. - * @param variableToSet The name of the variable to set when auth is satisfied. - */ - public ownerAuthorizationExpressionForCreateOperations( - rules: AuthRule[], - fieldIsList: (fieldName: string) => boolean, - variableToCheck: string = 'ctx.args.input', - variableToSet: string = ResourceConstants.SNIPPETS.IsOwnerAuthorizedVariable, - ): Expression { - if (!rules || rules.length === 0) { - return comment(`No Owner Authorization Rules`); - } - return block('Owner Authorization Checks', [ - this.ownershipAuthorizationExpressionForCreate(rules, fieldIsList, variableToCheck, variableToSet), - ]); - } - - public ownerAuthorizationExpressionForSubscriptions( - rules: AuthRule[], - variableToCheck: string = 'ctx.args', - variableToSet: string = ResourceConstants.SNIPPETS.IsOwnerAuthorizedVariable, - ): Expression { - if (!rules || rules.length === 0) { - return comment(`No Owner Authorization Rules`); - } - return block('Owner Authorization Checks', [ - this.ownershipAuthorizationExpressionForSubscriptions(rules, variableToCheck, variableToSet), - ]); - } - - public ownershipAuthorizationExpressionForSubscriptions( - rules: AuthRule[], - variableToCheck: string = 'ctx.args', - variableToSet: string = ResourceConstants.SNIPPETS.IsOwnerAuthorizedVariable, - formatComment?: (rule: AuthRule) => string, - ) { - let ownershipAuthorizationExpressions = []; - let ruleNumber = 0; - for (const rule of rules) { - const ownerAttribute = rule.ownerField || DEFAULT_OWNER_FIELD; - const rawUsername = rule.identityField || rule.identityClaim || DEFAULT_IDENTITY_FIELD; - const isUser = isUsername(rawUsername); - const identityAttribute = replaceIfUsername(rawUsername); - const allowedOwnersVariable = `allowedOwners${ruleNumber}`; - ownershipAuthorizationExpressions = ownershipAuthorizationExpressions.concat( - formatComment - ? comment(formatComment(rule)) - : comment(`Authorization rule: { allow: ${rule.allow}, ownerField: "${ownerAttribute}", identityClaim: "${identityAttribute}" }`), - set(ref(allowedOwnersVariable), raw(`$util.defaultIfNull($${variableToCheck}.${ownerAttribute}, null)`)), - isUser - ? // tslint:disable-next-line - set( - ref('identityValue'), - raw(`$util.defaultIfNull($ctx.identity.claims.get("${rawUsername}"), - $util.defaultIfNull($ctx.identity.claims.get("${identityAttribute}"), "${NONE_VALUE}"))`), - ) - : set(ref('identityValue'), raw(`$util.defaultIfNull($ctx.identity.claims.get("${identityAttribute}"), "${NONE_VALUE}")`)), - // If a list of owners check for at least one. - iff( - raw(`$util.isList($${allowedOwnersVariable})`), - forEach(ref('allowedOwner'), ref(allowedOwnersVariable), [ - iff(raw(`$allowedOwner == $identityValue`), set(ref(variableToSet), raw('true'))), - ]), - ), - // If a single owner check for at least one. - iff( - raw(`$util.isString($${allowedOwnersVariable})`), - iff(raw(`$${allowedOwnersVariable} == $identityValue`), set(ref(variableToSet), raw('true'))), - ), - ); - ruleNumber++; - } - return compoundExpression([set(ref(variableToSet), raw(`false`)), ...ownershipAuthorizationExpressions]); - } - - /** - * Given a set of owner authorization rules verifies that if the input - * specifies the given input field, the value satisfies at least one rule. - * @param rules The list of authorization rules. - * @param variableToCheck The name of the value containing the input. - * @param variableToSet The name of the variable to set when auth is satisfied. - */ - public ownerAuthorizationExpressionForCreateOperationsByField( - rules: AuthRule[], - fieldToCheck: string, - fieldIsList: (fieldName: string) => boolean, - variableToCheck: string = 'ctx.args.input', - variableToSet: string = ResourceConstants.SNIPPETS.IsOwnerAuthorizedVariable, - ): Expression { - if (!rules || rules.length === 0) { - return comment(`No Owner Authorization Rules`); - } - return block(`Owner authorization rules for field "${fieldToCheck}"`, [ - this.ownershipAuthorizationExpressionForCreate( - rules, - fieldIsList, - variableToCheck, - variableToSet, - (rule) => `Authorization rule: { allow: ${rule.allow}, \ -ownerField: "${rule.ownerField || DEFAULT_OWNER_FIELD}", \ -identityClaim: "${rule.identityField || rule.identityClaim || DEFAULT_IDENTITY_FIELD}" }`, - ), - ]); - } - - public ownershipAuthorizationExpressionForCreate( - rules: AuthRule[], - fieldIsList: (fieldName: string) => boolean, - variableToCheck: string = 'ctx.args.input', - variableToSet: string = ResourceConstants.SNIPPETS.IsOwnerAuthorizedVariable, - formatComment?: (rule: AuthRule) => string, - ) { - let ownershipAuthorizationExpressions = []; - let ruleNumber = 0; - for (const rule of rules) { - const ownerAttribute = rule.ownerField || DEFAULT_OWNER_FIELD; - const rawUsername = rule.identityField || rule.identityClaim || DEFAULT_IDENTITY_FIELD; - const isUser = isUsername(rawUsername); - const identityAttribute = replaceIfUsername(rawUsername); - const ownerFieldIsList = fieldIsList(ownerAttribute); - const allowedOwnersVariable = `allowedOwners${ruleNumber}`; - ownershipAuthorizationExpressions = ownershipAuthorizationExpressions.concat( - formatComment - ? comment(formatComment(rule)) - : comment(`Authorization rule: { allow: ${rule.allow}, ownerField: "${ownerAttribute}", identityClaim: "${identityAttribute}" }`), - set(ref(allowedOwnersVariable), raw(`$util.defaultIfNull($${variableToCheck}.${ownerAttribute}, null)`)), - isUser - ? // tslint:disable-next-line - set( - ref('identityValue'), - raw( - `$util.defaultIfNull($ctx.identity.claims.get("${rawUsername}"), $util.defaultIfNull($ctx.identity.claims.get("${identityAttribute}"), "${NONE_VALUE}"))`, - ), - ) - : set(ref('identityValue'), raw(`$util.defaultIfNull($ctx.identity.claims.get("${identityAttribute}"), "${NONE_VALUE}")`)), - // If a list of owners check for at least one. - iff( - raw(`$util.isList($${allowedOwnersVariable})`), - forEach(ref('allowedOwner'), ref(allowedOwnersVariable), [ - iff(raw(`$allowedOwner == $identityValue`), set(ref(variableToSet), raw('true'))), - ]), - ), - // If a single owner check for at least one. - iff( - raw(`$util.isString($${allowedOwnersVariable})`), - iff(raw(`$${allowedOwnersVariable} == $identityValue`), set(ref(variableToSet), raw('true'))), - ), - ); - // If the owner field is not a list and the user does not - // provide a value for the owner, set the owner automatically. - if (!ownerFieldIsList) { - ownershipAuthorizationExpressions.push( - // If the owner is not provided set it automatically. - // If the user explicitly provides null this will be false and we leave it null. - iff( - and([raw(`$util.isNull($${allowedOwnersVariable})`), parens(raw(`! $${variableToCheck}.containsKey("${ownerAttribute}")`))]), - compoundExpression([ - qref(`$${variableToCheck}.put("${ownerAttribute}", $identityValue)`), - set(ref(variableToSet), raw('true')), - ]), - ), - ); - } else { - // If the owner field is a list and the user does not - // provide a list of values for the owner, set the list with - // the owner as the sole member. - ownershipAuthorizationExpressions.push( - // If the owner is not provided set it automatically. - // If the user explicitly provides null this will be false and we leave it null. - iff( - and([raw(`$util.isNull($${allowedOwnersVariable})`), parens(raw(`! $${variableToCheck}.containsKey("${ownerAttribute}")`))]), - compoundExpression([ - qref(`$${variableToCheck}.put("${ownerAttribute}", ["$identityValue"])`), - set(ref(variableToSet), raw('true')), - ]), - ), - ); - } - ruleNumber++; - } - return compoundExpression([set(ref(variableToSet), raw(`false`)), ...ownershipAuthorizationExpressions]); - } - - /** - * Given a set of dynamic group authorization rules verifies w/ a conditional - * expression that the existing object has the correct group expression. - * @param rules The list of authorization rules. - * @param variableToCheck The name of the value containing the input. - * @param variableToSet The name of the variable to set when auth is satisfied. - */ - public dynamicGroupAuthorizationExpressionForUpdateOrDeleteOperations( - rules: AuthRule[], - fieldIsList: (fieldName: string) => boolean, - fieldBeingProtected?: string, - variableToCheck: string = 'ctx.args.input', - variableToSet: string = ResourceConstants.SNIPPETS.IsDynamicGroupAuthorizedVariable, - ): Expression { - const fieldMention = fieldBeingProtected ? ` for field "${fieldBeingProtected}"` : ''; - if (!rules || rules.length === 0) { - return comment(`No dynamic group authorization rules${fieldMention}`); - } - - let groupAuthorizationExpressions = []; - let ruleNumber = 0; - for (const rule of rules) { - const groupsAttribute = rule.groupsField || DEFAULT_GROUPS_FIELD; - const groupsAttributeName = fieldBeingProtected - ? `${fieldBeingProtected}_groupsAttribute${ruleNumber}` - : `groupsAttribute${ruleNumber}`; - const groupName = fieldBeingProtected ? `${fieldBeingProtected}_group${ruleNumber}` : `group${ruleNumber}`; - const groupClaimAttribute = rule.groupClaim || DEFAULT_GROUP_CLAIM; - - const groupsFieldIsList = fieldIsList(groupsAttribute); - - groupAuthorizationExpressions = groupAuthorizationExpressions.concat( - comment( - `Authorization rule${fieldMention}: { allow: ${rule.allow}, groupsField: "${groupsAttribute}", groupClaim: "${groupClaimAttribute}"}`, - ), - // Add the new auth expression and values - this.setUserGroups(rule.groupClaim), - forEach(ref('userGroup'), ref('userGroups'), [ - groupsFieldIsList - ? raw(`$util.qr($groupAuthExpressions.add("contains(#${groupsAttributeName}, :${groupName}$foreach.count)"))`) - : raw(`$util.qr($groupAuthExpressions.add("#${groupsAttributeName} = :${groupName}$foreach.count"))`), - raw(`$util.qr($groupAuthExpressionValues.put(":${groupName}$foreach.count", { "S": $userGroup }))`), - ]), - iff(raw('$userGroups.size() > 0'), raw(`$util.qr($groupAuthExpressionNames.put("#${groupsAttributeName}", "${groupsAttribute}"))`)), - ); - ruleNumber++; - } - // check for groupclaim here - return block('Dynamic group authorization checks', [ - set(ref('groupAuthExpressions'), list([])), - set(ref('groupAuthExpressionValues'), obj({})), - set(ref('groupAuthExpressionNames'), obj({})), - ...groupAuthorizationExpressions, - ]); - } - - /** - * Given a set of owner authorization rules verifies with a conditional - * expression that the existing object is owned. - * @param rules The list of authorization rules. - * @param variableToCheck The name of the value containing the input. - * @param variableToSet The name of the variable to set when auth is satisfied. - */ - public ownerAuthorizationExpressionForUpdateOrDeleteOperations( - rules: AuthRule[], - fieldIsList: (fieldName: string) => boolean, - fieldBeingProtected?: string, - variableToCheck: string = 'ctx.args.input', - variableToSet: string = ResourceConstants.SNIPPETS.IsOwnerAuthorizedVariable, - ): Expression { - const fieldMention = fieldBeingProtected ? ` for field "${fieldBeingProtected}"` : ''; - if (!rules || rules.length === 0) { - return comment(`No owner authorization rules${fieldMention}`); - } - let ownerAuthorizationExpressions = []; - let ruleNumber = 0; - for (const rule of rules) { - const ownerAttribute = rule.ownerField || DEFAULT_OWNER_FIELD; - const rawUsername = rule.identityField || rule.identityClaim || DEFAULT_IDENTITY_FIELD; - const isUser = isUsername(rawUsername); - const identityAttribute = replaceIfUsername(rawUsername); - const ownerFieldIsList = fieldIsList(ownerAttribute); - const ownerName = fieldBeingProtected ? `${fieldBeingProtected}_owner${ruleNumber}` : `owner${ruleNumber}`; - const identityName = fieldBeingProtected ? `${fieldBeingProtected}_identity${ruleNumber}` : `identity${ruleNumber}`; - - ownerAuthorizationExpressions.push( - // tslint:disable:max-line-length - comment( - `Authorization rule${fieldMention}: { allow: ${rule.allow}, ownerField: "${ownerAttribute}", identityClaim: "${identityAttribute}" }`, - ), - ); - if (ownerFieldIsList) { - ownerAuthorizationExpressions.push(raw(`$util.qr($ownerAuthExpressions.add("contains(#${ownerName}, :${identityName})"))`)); - } else { - ownerAuthorizationExpressions.push(raw(`$util.qr($ownerAuthExpressions.add("#${ownerName} = :${identityName}"))`)); - } - ownerAuthorizationExpressions = ownerAuthorizationExpressions.concat( - raw(`$util.qr($ownerAuthExpressionNames.put("#${ownerName}", "${ownerAttribute}"))`), - // tslint:disable - isUser - ? raw( - `$util.qr($ownerAuthExpressionValues.put(":${identityName}", $util.dynamodb.toDynamoDB($util.defaultIfNull($ctx.identity.claims.get("${rawUsername}"), $util.defaultIfNull($ctx.identity.claims.get("${identityAttribute}"), "${NONE_VALUE}")))))`, - ) - : raw( - `$util.qr($ownerAuthExpressionValues.put(":${identityName}", $util.dynamodb.toDynamoDB($util.defaultIfNull($ctx.identity.claims.get("${identityAttribute}"), "${NONE_VALUE}"))))`, - ), - // tslint:enable - ); - ruleNumber++; - } - return block('Owner Authorization Checks', [ - set(ref('ownerAuthExpressions'), list([])), - set(ref('ownerAuthExpressionValues'), obj({})), - set(ref('ownerAuthExpressionNames'), obj({})), - ...ownerAuthorizationExpressions, - ]); - } - - /** - * Given a list of rules return a VTL expression that checks if the given variableToCheck - * statisies at least one of the auth rules. - * @param rules The list of dynamic group authorization rules. - */ - public dynamicGroupAuthorizationExpressionForReadOperations( - rules: AuthRule[], - variableToCheck: string = 'ctx.result', - variableToSet: string = ResourceConstants.SNIPPETS.IsDynamicGroupAuthorizedVariable, - defaultValue: Expression = raw(`$util.defaultIfNull($${variableToSet}, false)`), - ): Expression { - if (!rules || rules.length === 0) { - return comment(`No Dynamic Group Authorization Rules`); - } - let groupAuthorizationExpressions = []; - for (const rule of rules) { - const groupsAttribute = rule.groupsField || DEFAULT_GROUPS_FIELD; - const groupClaimAttribute = rule.groupClaim || DEFAULT_GROUP_CLAIM; - groupAuthorizationExpressions = groupAuthorizationExpressions.concat( - comment(`Authorization rule: { allow: ${rule.allow}, groupsField: "${groupsAttribute}", groupClaim: "${groupClaimAttribute}" }`), - set(ref('allowedGroups'), ref(`util.defaultIfNull($${variableToCheck}.${groupsAttribute}, [])`)), - this.setUserGroups(rule.groupClaim), - forEach(ref('userGroup'), ref('userGroups'), [ - iff(raw('$util.isList($allowedGroups)'), iff(raw(`$allowedGroups.contains($userGroup)`), set(ref(variableToSet), raw('true')))), - iff(raw(`$util.isString($allowedGroups)`), iff(raw(`$allowedGroups == $userGroup`), set(ref(variableToSet), raw('true')))), - ]), - ); - } - // check for group claim here - return block('Dynamic Group Authorization Checks', [set(ref(variableToSet), defaultValue), ...groupAuthorizationExpressions]); - } - - /** - * Given a list of rules return a VTL expression that checks if the given variableToCheck - * statisies at least one of the auth rules. - * @param rules The list of dynamic group authorization rules. - */ - public ownerAuthorizationExpressionForReadOperations( - rules: AuthRule[], - variableToCheck: string = 'ctx.result', - variableToSet: string = ResourceConstants.SNIPPETS.IsOwnerAuthorizedVariable, - defaultValue: Expression = raw(`$util.defaultIfNull($${variableToSet}, false)`), - ): Expression { - if (!rules || rules.length === 0) { - return comment(`No Owner Authorization Rules`); - } - let ownerAuthorizationExpressions = []; - let ruleNumber = 0; - for (const rule of rules) { - const ownerAttribute = rule.ownerField || DEFAULT_OWNER_FIELD; - const rawUsername = rule.identityField || rule.identityClaim || DEFAULT_IDENTITY_FIELD; - const isUser = isUsername(rawUsername); - const identityAttribute = replaceIfUsername(rawUsername); - const allowedOwnersVariable = `allowedOwners${ruleNumber}`; - ownerAuthorizationExpressions = ownerAuthorizationExpressions.concat( - comment(`Authorization rule: { allow: ${rule.allow}, ownerField: "${ownerAttribute}", identityClaim: "${identityAttribute}" }`), - set(ref(allowedOwnersVariable), ref(`util.defaultIfNull($${variableToCheck}.${ownerAttribute}, [])`)), - isUser - ? // tslint:disable-next-line - set( - ref('identityValue'), - raw( - `$util.defaultIfNull($ctx.identity.claims.get("${rawUsername}"), $util.defaultIfNull($ctx.identity.claims.get("${identityAttribute}"), "${NONE_VALUE}"))`, - ), - ) - : set(ref('identityValue'), raw(`$util.defaultIfNull($ctx.identity.claims.get("${identityAttribute}"), "${NONE_VALUE}")`)), - iff( - raw(`$util.isList($${allowedOwnersVariable})`), - forEach(ref('allowedOwner'), ref(allowedOwnersVariable), [ - iff(raw(`$allowedOwner == $identityValue`), set(ref(variableToSet), raw('true'))), - ]), - ), - iff( - raw(`$util.isString($${allowedOwnersVariable})`), - iff(raw(`$${allowedOwnersVariable} == $identityValue`), set(ref(variableToSet), raw('true'))), - ), - ); - ruleNumber++; - } - return block('Owner Authorization Checks', [set(ref(variableToSet), defaultValue), ...ownerAuthorizationExpressions]); - } - - public throwIfSubscriptionUnauthorized(): Expression { - const ifUnauthThrow = iff( - not( - parens( - or([ - equals(ref(ResourceConstants.SNIPPETS.IsStaticGroupAuthorizedVariable), raw('true')), - equals(ref(ResourceConstants.SNIPPETS.IsOwnerAuthorizedVariable), raw('true')), - ]), - ), - ), - raw('$util.unauthorized()'), - ); - return block('Throw if unauthorized', [ifUnauthThrow]); - } - - public throwIfUnauthorized(field?: FieldDefinitionNode): Expression { - const staticGroupAuthorizedVariable = this.getStaticAuthorizationVariable(field); - const ifUnauthThrow = iff( - not( - parens( - or([ - equals(ref(staticGroupAuthorizedVariable), raw('true')), - equals(ref(ResourceConstants.SNIPPETS.IsDynamicGroupAuthorizedVariable), raw('true')), - equals(ref(ResourceConstants.SNIPPETS.IsOwnerAuthorizedVariable), raw('true')), - ]), - ), - ), - raw('$util.unauthorized()'), - ); - return block('Throw if unauthorized', [ifUnauthThrow]); - } - - public returnIfEmpty(objectPath: string): Expression { - return iff(isNullOrEmpty(ref(objectPath)), ret()); - } - - public throwIfStaticGroupUnauthorized(field?: FieldDefinitionNode): Expression { - const staticGroupAuthorizedVariable = this.getStaticAuthorizationVariable(field); - const ifUnauthThrow = iff(equals(ref(staticGroupAuthorizedVariable), raw('false')), raw('$util.unauthorized()')); - return block('Throw if unauthorized', [ifUnauthThrow]); - } - - // A = IsStaticallyAuthed - // B = AuthConditionIsNotNull - // ! (A OR B) == (!A AND !B) - public throwIfNotStaticGroupAuthorizedOrAuthConditionIsEmpty(field?: FieldDefinitionNode): Expression { - const staticGroupAuthorizedVariable = this.getStaticAuthorizationVariable(field); - const ifUnauthThrow = iff( - not(parens(or([equals(ref(staticGroupAuthorizedVariable), raw('true')), parens(raw('$totalAuthExpression != ""'))]))), - raw('$util.unauthorized()'), - ); - return block('Throw if unauthorized', [ifUnauthThrow]); - } - - public collectAuthCondition(): Expression { - return block('Collect Auth Condition', [ - set( - ref(ResourceConstants.SNIPPETS.AuthCondition), - raw( - `$util.defaultIfNull($authCondition, ${print( - obj({ - expression: str(''), - expressionNames: obj({}), - expressionValues: obj({}), - }), - )})`, - ), - ), - set(ref('totalAuthExpression'), str('')), - comment('Add dynamic group auth conditions if they exist'), - iff( - ref('groupAuthExpressions'), - forEach(ref('authExpr'), ref('groupAuthExpressions'), [ - set(ref('totalAuthExpression'), str(`$totalAuthExpression $authExpr`)), - iff(ref('foreach.hasNext'), set(ref('totalAuthExpression'), str(`$totalAuthExpression OR`))), - ]), - ), - iff( - ref('groupAuthExpressionNames'), - raw(`$util.qr($${ResourceConstants.SNIPPETS.AuthCondition}.expressionNames.putAll($groupAuthExpressionNames))`), - ), - iff( - ref('groupAuthExpressionValues'), - raw(`$util.qr($${ResourceConstants.SNIPPETS.AuthCondition}.expressionValues.putAll($groupAuthExpressionValues))`), - ), - - comment('Add owner auth conditions if they exist'), - iff( - raw(`$totalAuthExpression != "" && $ownerAuthExpressions && $ownerAuthExpressions.size() > 0`), - set(ref('totalAuthExpression'), str(`$totalAuthExpression OR`)), - ), - iff( - ref('ownerAuthExpressions'), - forEach(ref('authExpr'), ref('ownerAuthExpressions'), [ - set(ref('totalAuthExpression'), str(`$totalAuthExpression $authExpr`)), - iff(ref('foreach.hasNext'), set(ref('totalAuthExpression'), str(`$totalAuthExpression OR`))), - ]), - ), - iff( - ref('ownerAuthExpressionNames'), - raw(`$util.qr($${ResourceConstants.SNIPPETS.AuthCondition}.expressionNames.putAll($ownerAuthExpressionNames))`), - ), - - iff( - ref('ownerAuthExpressionValues'), - raw(`$util.qr($${ResourceConstants.SNIPPETS.AuthCondition}.expressionValues.putAll($ownerAuthExpressionValues))`), - ), - - comment('Set final expression if it has changed.'), - iff( - raw(`$totalAuthExpression != ""`), - ifElse( - raw(`$util.isNullOrEmpty($${ResourceConstants.SNIPPETS.AuthCondition}.expression)`), - set(ref(`${ResourceConstants.SNIPPETS.AuthCondition}.expression`), str(`($totalAuthExpression)`)), - set( - ref(`${ResourceConstants.SNIPPETS.AuthCondition}.expression`), - str(`$${ResourceConstants.SNIPPETS.AuthCondition}.expression AND ($totalAuthExpression)`), - ), - ), - ), - ]); - } - - public appendItemIfLocallyAuthorized(): Expression { - return iff( - parens( - or([ - equals(ref(ResourceConstants.SNIPPETS.IsLocalDynamicGroupAuthorizedVariable), raw('true')), - equals(ref(ResourceConstants.SNIPPETS.IsLocalOwnerAuthorizedVariable), raw('true')), - ]), - ), - qref('$items.add($item)'), - ); - } - - public setUserGroups(customGroup?: string): Expression { - if (customGroup) { - return compoundExpression([ - set(ref('userGroups'), raw(`$util.defaultIfNull($ctx.identity.claims.get("${customGroup}"), [])`)), - iff( - raw('$util.isString($userGroups)'), - ifElse( - raw('$util.isList($util.parseJson($userGroups))'), - set(ref('userGroups'), raw('$util.parseJson($userGroups)')), - set(ref('userGroups'), raw('[$userGroups]')), - ), - ), - ]); - } - return set(ref('userGroups'), raw(`$util.defaultIfNull($ctx.identity.claims.get("${DEFAULT_GROUP_CLAIM}"), [])`)); - } - - public generateSubscriptionResolver(fieldName: string, subscriptionTypeName: string = 'Subscription') { - return new AppSync.Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: 'NONE', - FieldName: fieldName, - TypeName: subscriptionTypeName, - RequestMappingTemplate: print( - raw(`{ - "version": "${RESOLVER_VERSION_ID}", - "payload": {} -}`), - ), - ResponseMappingTemplate: print(raw(`$util.toJson(null)`)), - }); - } - - public operationCheckExpression(operation: string, field: FieldDefinitionNode) { - // check if the field has @connection - const connectionDirective = field.directives.find((dir) => dir.name.value === 'connection'); - const returnValue: Expression = connectionDirective ? toJson(ref(`context.result`)) : toJson(ref(`context.source.${field.name.value}`)); - return block('Checking for allowed operations which can return this field', [ - set(ref('operation'), raw('$util.defaultIfNull($context.source.operation, "null")')), - ifElse(raw(`$operation == "${operation}"`), ref('util.toJson(null)'), returnValue), - ]); - } - - public setOperationExpression(operation: string): string { - return print(block('Setting the operation', [qref(print(methodCall(ref('ctx.result.put'), str('operation'), str(operation))))])); - } - - public getAuthModeCheckWrappedExpression(expectedAuthModes: Set, expression: Expression): Expression { - if (!expectedAuthModes || expectedAuthModes.size === 0) { - return expression; - } - - const conditions = []; - - for (const expectedAuthMode of expectedAuthModes) { - conditions.push(equals(ref(ResourceConstants.SNIPPETS.AuthMode), str(`${expectedAuthMode}`))); - } - - return block('Check authMode and execute owner/group checks', [ - iff(conditions.length === 1 ? conditions[0] : or(conditions), expression), - ]); - } - - public getAuthModeDeterminationExpression(authProviders: Set, isUserPoolTheDefault: boolean): Expression { - if (!authProviders || authProviders.size === 0) { - return comment(`No authentication mode determination needed`); - } - - const expressions = []; - - for (const authProvider of authProviders) { - if (authProvider === 'userPools') { - const statements = [ - raw(`$util.isNullOrEmpty($${ResourceConstants.SNIPPETS.AuthMode})`), - not(raw(`$util.isNull($ctx.identity)`)), - not(raw(`$util.isNull($ctx.identity.sub)`)), - not(raw(`$util.isNull($ctx.identity.issuer)`)), - not(raw(`$util.isNull($ctx.identity.username)`)), - not(raw(`$util.isNull($ctx.identity.claims)`)), - not(raw(`$util.isNull($ctx.identity.sourceIp)`)), - ]; - - if (isUserPoolTheDefault === true) { - statements.push(not(raw(`$util.isNull($ctx.identity.defaultAuthStrategy)`))); - } - - const userPoolsExpression = iff(and(statements), set(ref(ResourceConstants.SNIPPETS.AuthMode), str(`userPools`))); - - expressions.push(userPoolsExpression); - } else if (authProvider === 'oidc') { - const oidcExpression = iff( - and([ - raw(`$util.isNullOrEmpty($${ResourceConstants.SNIPPETS.AuthMode})`), - not(raw(`$util.isNull($ctx.identity)`)), - not(raw(`$util.isNull($ctx.identity.sub)`)), - not(raw(`$util.isNull($ctx.identity.issuer)`)), - not(raw(`$util.isNull($ctx.identity.claims)`)), - raw(`$util.isNull($ctx.identity.username)`), - raw(`$util.isNull($ctx.identity.sourceIp)`), - ]), - set(ref(ResourceConstants.SNIPPETS.AuthMode), str(`oidc`)), - ); - - if (expressions.length > 0) { - expressions.push(newline()); - } - - expressions.push(oidcExpression); - } - } - - return block('Determine request authentication mode', expressions); - } - - public getStaticAuthorizationVariable(field: FieldDefinitionNode): string { - return field - ? `${field.name.value}_${ResourceConstants.SNIPPETS.IsStaticGroupAuthorizedVariable}` - : ResourceConstants.SNIPPETS.IsStaticGroupAuthorizedVariable; - } - - public makeIAMPolicyForRole(isAuthPolicy: Boolean, resources: Set): ManagedPolicy[] { - const policies = new Array(); - const authPiece = isAuthPolicy ? 'auth' : 'unauth'; - let policyResources: object[] = []; - let resourceSize = 0; - - // 6144 bytes is the maximum policy payload size, but there is structural overhead, hence the 6000 bytes - const MAX_BUILT_SIZE_BYTES = 6000; - // The overhead is the amount of static policy arn contents like region, accountid, etc. - // arn:aws:appsync:${AWS::Region}:${AWS::AccountId}:apis/${apiId}/types/${typeName}/fields/${fieldName} - // 16 15 13 5 27 6 X+1 7 Y - // 89 + 11 extra = 100 - const RESOURCE_OVERHEAD = 100; - - const createPolicy = (newPolicyResources) => - new IAM.ManagedPolicy({ - Roles: [ - // HACK double casting needed because it cannot except Ref - { Ref: `${authPiece}RoleName` } as unknown as Value, - ], - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Action: ['appsync:GraphQL'], - Resource: newPolicyResources, - }, - ], - }, - }); - - for (const resource of resources) { - // We always have 2 parts, no need to check - const resourceParts = resource.split('/'); - - if (resourceParts[1] !== 'null') { - policyResources.push( - Fn.Sub('arn:aws:appsync:${AWS::Region}:${AWS::AccountId}:apis/${apiId}/types/${typeName}/fields/${fieldName}', { - apiId: { - 'Fn::GetAtt': ['GraphQLAPI', 'ApiId'], - }, - typeName: resourceParts[0], - fieldName: resourceParts[1], - }), - ); - - resourceSize += RESOURCE_OVERHEAD + resourceParts[0].length + resourceParts[1].length; - } else { - policyResources.push( - Fn.Sub('arn:aws:appsync:${AWS::Region}:${AWS::AccountId}:apis/${apiId}/types/${typeName}/*', { - apiId: { - 'Fn::GetAtt': ['GraphQLAPI', 'ApiId'], - }, - typeName: resourceParts[0], - }), - ); - - resourceSize += RESOURCE_OVERHEAD + resourceParts[0].length; - } - - // - // Check policy size and if needed create a new one and clear the resources, reset - // accumulated size - // - - if (resourceSize > MAX_BUILT_SIZE_BYTES) { - const policy = createPolicy(policyResources.slice(0, policyResources.length - 1)); - - policies.push(policy); - - // Remove all but the last item - policyResources = policyResources.slice(-1); - resourceSize = 0; - } - } - - if (policyResources.length > 0) { - const policy = createPolicy(policyResources); - - policies.push(policy); - } - - return policies; - } - - /** - * ES EXPRESSIONS - */ - - public makeESItemsExpression(includeVersion: boolean) { - // generate es expresion to appsync - return compoundExpression([ - set(ref('es_items'), list([])), - forEach(ref('entry'), ref('context.result.hits.hits'), [ - iff(raw('!$foreach.hasNext'), set(ref('nextToken'), ref('entry.sort.get(0)'))), - ...this.getSourceMapper(includeVersion), - ]), - ]); - } - - private getSourceMapper = (includeVersion: boolean) => { - if (includeVersion) { - return [ - set(ref('row'), methodCall(ref('entry.get'), str('_source'))), - qref('$row.put("_version", $entry.get("_version"))'), - qref('$es_items.add($row)'), - ]; - } - return [qref('$es_items.add($entry.get("_source"))')]; - }; - - public makeESToGQLExpression() { - return compoundExpression([ - set( - ref('es_response'), - obj({ - items: ref('es_items'), - }), - ), - iff( - raw('$es_items.size() > 0'), - compoundExpression([qref('$es_response.put("nextToken", $nextToken)'), qref('$es_response.put("total", $es_items.size())')]), - ), - toJson(ref('es_response')), - ]); - } -} diff --git a/packages/graphql-auth-transformer/tsconfig.json b/packages/graphql-auth-transformer/tsconfig.json deleted file mode 100644 index 478cbfc9c6..0000000000 --- a/packages/graphql-auth-transformer/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "strict": false, // TODO enable - "rootDir": "src", - "outDir": "lib" - }, - "references": [ - { "path": "../amplify-graphql-directives" }, - { "path": "../graphql-connection-transformer" }, - { "path": "../graphql-dynamodb-transformer" }, - { "path": "../graphql-elasticsearch-transformer" }, - { "path": "../graphql-mapping-template" }, - { "path": "../graphql-transformer-common" }, - { "path": "../graphql-transformer-core" } - ] -} diff --git a/packages/graphql-connection-transformer/.npmignore b/packages/graphql-connection-transformer/.npmignore deleted file mode 100644 index 3ee5d55b0b..0000000000 --- a/packages/graphql-connection-transformer/.npmignore +++ /dev/null @@ -1,5 +0,0 @@ -**/__mocks__/** -**/__tests__/** -src -tsconfig.json -tsconfig.tsbuildinfo diff --git a/packages/graphql-connection-transformer/API.md b/packages/graphql-connection-transformer/API.md deleted file mode 100644 index 59b353110a..0000000000 --- a/packages/graphql-connection-transformer/API.md +++ /dev/null @@ -1,36 +0,0 @@ -## API Report File for "graphql-connection-transformer" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { DirectiveNode } from 'graphql'; -import { FieldDefinitionNode } from 'graphql'; -import { InterfaceTypeDefinitionNode } from 'graphql'; -import { KeySchema } from 'cloudform-types/types/dynamoDb/table'; -import { ObjectNode } from 'graphql-mapping-template'; -import { ObjectTypeDefinitionNode } from 'graphql'; -import Resolver from 'cloudform-types/types/appSync/resolver'; -import Table from 'cloudform-types/types/dynamoDb/table'; -import Template from 'cloudform-types/types/template'; -import { Transformer as Transformer_2 } from 'graphql-transformer-core'; -import { TransformerContext } from 'graphql-transformer-core'; - -// @public (undocumented) -export class ModelConnectionTransformer extends Transformer_2 { - constructor(); - // (undocumented) - before: (ctx: TransformerContext) => void; - // (undocumented) - connectionWithKey: (parent: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, field: FieldDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => void; - // (undocumented) - field: (parent: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, field: FieldDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => void; - // Warning: (ae-forgotten-export) The symbol "ResourceFactory" needs to be exported by the entry point index.d.ts - // - // (undocumented) - resources: ResourceFactory; -} - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/graphql-connection-transformer/CHANGELOG.md b/packages/graphql-connection-transformer/CHANGELOG.md deleted file mode 100644 index a8fa9590c9..0000000000 --- a/packages/graphql-connection-transformer/CHANGELOG.md +++ /dev/null @@ -1,1106 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [5.2.80](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.79...graphql-connection-transformer@5.2.80) (2024-07-15) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.79](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.78...graphql-connection-transformer@5.2.79) (2024-07-02) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.78](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.77...graphql-connection-transformer@5.2.78) (2024-06-25) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.77](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.76...graphql-connection-transformer@5.2.77) (2024-04-26) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.76](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.75...graphql-connection-transformer@5.2.76) (2024-04-11) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.75](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.74...graphql-connection-transformer@5.2.75) (2024-03-28) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.74](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.73...graphql-connection-transformer@5.2.74) (2024-02-28) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.73](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.72...graphql-connection-transformer@5.2.73) (2024-02-05) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.72](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.71...graphql-connection-transformer@5.2.72) (2024-01-22) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.71](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.70...graphql-connection-transformer@5.2.71) (2023-12-18) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.70](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.69...graphql-connection-transformer@5.2.70) (2023-12-06) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.69](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.68...graphql-connection-transformer@5.2.69) (2023-11-18) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.68](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.67...graphql-connection-transformer@5.2.68) (2023-11-16) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.67](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.66...graphql-connection-transformer@5.2.67) (2023-11-15) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.66](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.65...graphql-connection-transformer@5.2.66) (2023-10-21) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.65](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.64...graphql-connection-transformer@5.2.65) (2023-08-30) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.64](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.63...graphql-connection-transformer@5.2.64) (2023-08-28) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.63](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.62...graphql-connection-transformer@5.2.63) (2023-08-09) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.62](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.61...graphql-connection-transformer@5.2.62) (2023-07-21) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.61](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.60...graphql-connection-transformer@5.2.61) (2023-07-17) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.60](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.59...graphql-connection-transformer@5.2.60) (2023-07-07) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.59](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.58...graphql-connection-transformer@5.2.59) (2023-07-07) - -### Bug Fixes - -- trigger republish of dependencies that failed in https://app.circleci.com/pipelines/github/aws-amplify/amplify-category-api/7981/workflows/e7366f04-6f0a-4ee4-9cc2-1772089e8005/jobs/163571 ([f2c7151](https://github.com/aws-amplify/amplify-category-api/commit/f2c7151005e4a9fd29d91ac1af1f3e482a06a5cc)) - -## [5.2.58](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.57...graphql-connection-transformer@5.2.58) (2023-07-07) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.57](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.56...graphql-connection-transformer@5.2.57) (2023-06-29) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.56](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.55...graphql-connection-transformer@5.2.56) (2023-06-20) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.55](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.54...graphql-connection-transformer@5.2.55) (2023-06-05) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.54](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.53...graphql-connection-transformer@5.2.54) (2023-05-23) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.53](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.52...graphql-connection-transformer@5.2.53) (2023-05-17) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.52](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.51...graphql-connection-transformer@5.2.52) (2023-04-25) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.51](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.50...graphql-connection-transformer@5.2.51) (2023-03-30) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.50](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.49...graphql-connection-transformer@5.2.50) (2023-03-15) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.49](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.48...graphql-connection-transformer@5.2.49) (2023-03-01) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.48](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.47...graphql-connection-transformer@5.2.48) (2023-02-27) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.47](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.46...graphql-connection-transformer@5.2.47) (2023-01-26) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.46](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.45...graphql-connection-transformer@5.2.46) (2023-01-12) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.45](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.44...graphql-connection-transformer@5.2.45) (2023-01-12) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.44](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.43...graphql-connection-transformer@5.2.44) (2022-12-03) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.43](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.42...graphql-connection-transformer@5.2.43) (2022-09-14) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.42](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.40...graphql-connection-transformer@5.2.42) (2022-07-20) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.41](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.40...graphql-connection-transformer@5.2.41) (2022-07-14) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.40](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.39...graphql-connection-transformer@5.2.40) (2022-07-01) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.39](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.38...graphql-connection-transformer@5.2.39) (2022-06-23) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.38](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.37...graphql-connection-transformer@5.2.38) (2022-06-13) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.37](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.36...graphql-connection-transformer@5.2.37) (2022-06-10) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.36](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.35...graphql-connection-transformer@5.2.36) (2022-06-10) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.35](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.32...graphql-connection-transformer@5.2.35) (2022-06-07) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.34](https://github.com/aws-amplify/amplify-category-api/compare/graphql-connection-transformer@5.2.32...graphql-connection-transformer@5.2.34) (2022-05-31) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.33](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.32...graphql-connection-transformer@5.2.33) (2022-05-02) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.32](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.31...graphql-connection-transformer@5.2.32) (2022-04-29) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.31](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.30...graphql-connection-transformer@5.2.31) (2022-04-27) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.30](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.29...graphql-connection-transformer@5.2.30) (2022-04-11) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.29](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.28...graphql-connection-transformer@5.2.29) (2022-04-07) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.28](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.27...graphql-connection-transformer@5.2.28) (2022-03-23) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.27](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.26...graphql-connection-transformer@5.2.27) (2022-03-17) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.26](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.25...graphql-connection-transformer@5.2.26) (2022-03-14) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.24...graphql-connection-transformer@5.2.25) (2022-03-07) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.23...graphql-connection-transformer@5.2.24) (2022-02-25) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.22...graphql-connection-transformer@5.2.23) (2022-02-15) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.18...graphql-connection-transformer@5.2.22) (2022-02-10) - -## 7.6.19 (2022-02-08) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.17...graphql-connection-transformer@5.2.18) (2022-02-03) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.16...graphql-connection-transformer@5.2.17) (2022-01-31) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.15...graphql-connection-transformer@5.2.16) (2022-01-27) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.14...graphql-connection-transformer@5.2.15) (2022-01-23) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.13...graphql-connection-transformer@5.2.14) (2022-01-13) - -### Bug Fixes - -- clean up missing and unused GraphQL v1 dependencies ([#9496](https://github.com/aws-amplify/amplify-cli/issues/9496)) ([fe8201b](https://github.com/aws-amplify/amplify-cli/commit/fe8201be17f42db233fce0bb366ff4d0c8358ec0)) - -## [5.2.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.11...graphql-connection-transformer@5.2.13) (2022-01-10) - -## 7.6.7 (2022-01-10) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.10...graphql-connection-transformer@5.2.11) (2021-12-21) - -### Bug Fixes - -- generate list types will nullable elements ([#9310](https://github.com/aws-amplify/amplify-cli/issues/9310)) ([e972956](https://github.com/aws-amplify/amplify-cli/commit/e9729565fef2ac7df51f7fc7f345da536f385ac1)) - -## [5.2.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.9...graphql-connection-transformer@5.2.10) (2021-12-17) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.8...graphql-connection-transformer@5.2.9) (2021-12-03) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.7...graphql-connection-transformer@5.2.8) (2021-12-02) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.6...graphql-connection-transformer@5.2.7) (2021-12-01) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.5...graphql-connection-transformer@5.2.6) (2021-11-26) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.4...graphql-connection-transformer@5.2.5) (2021-11-23) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.3...graphql-connection-transformer@5.2.4) (2021-11-21) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.2...graphql-connection-transformer@5.2.3) (2021-11-20) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@5.2.1...graphql-connection-transformer@5.2.2) (2021-11-17) - -**Note:** Version bump only for package graphql-connection-transformer - -## [5.2.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.22.0...graphql-connection-transformer@5.2.1) (2021-11-15) - -**Note:** Version bump only for package graphql-connection-transformer - -# [5.0.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.25...graphql-connection-transformer@5.0.0) (2021-11-13) - -### Bug Fixes - -- **graphql-relational-transformer:** fix has many without fields ([#8700](https://github.com/aws-amplify/amplify-cli/issues/8700)) ([cc21d4d](https://github.com/aws-amplify/amplify-cli/commit/cc21d4dcf827a9ef27a89dffe828f3726a03ecea)) - -### Features - -- generate list types as non-null ([#8166](https://github.com/aws-amplify/amplify-cli/issues/8166)) ([93786c1](https://github.com/aws-amplify/amplify-cli/commit/93786c13ef04c72748ca32a1ef7878c0e6b5b129)) - -# [4.22.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.25...graphql-connection-transformer@4.22.0) (2021-11-11) - -### Bug Fixes - -- **graphql-relational-transformer:** fix has many without fields ([#8700](https://github.com/aws-amplify/amplify-cli/issues/8700)) ([cc21d4d](https://github.com/aws-amplify/amplify-cli/commit/cc21d4dcf827a9ef27a89dffe828f3726a03ecea)) - -### Features - -- generate list types as non-null ([#8166](https://github.com/aws-amplify/amplify-cli/issues/8166)) ([93786c1](https://github.com/aws-amplify/amplify-cli/commit/93786c13ef04c72748ca32a1ef7878c0e6b5b129)) - -## [4.21.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.24...graphql-connection-transformer@4.21.25) (2021-10-10) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.23...graphql-connection-transformer@4.21.24) (2021-10-06) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.22...graphql-connection-transformer@4.21.23) (2021-09-27) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.21...graphql-connection-transformer@4.21.22) (2021-09-18) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.21](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.20...graphql-connection-transformer@4.21.21) (2021-09-14) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.20](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.19...graphql-connection-transformer@4.21.20) (2021-09-09) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.19](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.18...graphql-connection-transformer@4.21.19) (2021-09-02) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.17...graphql-connection-transformer@4.21.18) (2021-08-24) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.16...graphql-connection-transformer@4.21.17) (2021-08-06) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.15...graphql-connection-transformer@4.21.16) (2021-07-30) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.14...graphql-connection-transformer@4.21.15) (2021-07-27) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.13...graphql-connection-transformer@4.21.14) (2021-07-16) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.12...graphql-connection-transformer@4.21.13) (2021-06-30) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.11...graphql-connection-transformer@4.21.12) (2021-06-24) - -### Bug Fixes - -- **graphql-transformer-common:** improve generated graphql pluralization ([#7258](https://github.com/aws-amplify/amplify-cli/issues/7258)) ([fc3ad0d](https://github.com/aws-amplify/amplify-cli/commit/fc3ad0dd5a12a7912c59ae12024f593b4cdf7f2d)), closes [#4224](https://github.com/aws-amplify/amplify-cli/issues/4224) - -## [4.21.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.10...graphql-connection-transformer@4.21.11) (2021-06-15) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.9...graphql-connection-transformer@4.21.10) (2021-05-29) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.8...graphql-connection-transformer@4.21.9) (2021-05-26) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.7...graphql-connection-transformer@4.21.8) (2021-05-18) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** make primary key non null on del ([#6337](https://github.com/aws-amplify/amplify-cli/issues/6337)) ([4a5c679](https://github.com/aws-amplify/amplify-cli/commit/4a5c6795680b6b88efb19b923ee234253ca30c35)), closes [#2564](https://github.com/aws-amplify/amplify-cli/issues/2564) - -## [4.21.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.6...graphql-connection-transformer@4.21.7) (2021-05-14) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.4...graphql-connection-transformer@4.21.6) (2021-05-03) - -## 4.50.1 (2021-05-03) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.4...graphql-connection-transformer@4.21.5) (2021-05-03) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.3...graphql-connection-transformer@4.21.4) (2021-04-27) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.2...graphql-connection-transformer@4.21.3) (2021-04-19) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.21.1...graphql-connection-transformer@4.21.2) (2021-04-14) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.21.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.20.7...graphql-connection-transformer@4.21.1) (2021-04-09) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.20.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.20.6...graphql-connection-transformer@4.20.7) (2021-03-23) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.20.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.20.5...graphql-connection-transformer@4.20.6) (2021-03-11) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.20.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.20.4...graphql-connection-transformer@4.20.5) (2021-03-05) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.20.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.20.3...graphql-connection-transformer@4.20.4) (2021-02-26) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.20.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.20.2...graphql-connection-transformer@4.20.3) (2021-02-24) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.20.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.20.1...graphql-connection-transformer@4.20.2) (2021-02-17) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.20.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.20.0...graphql-connection-transformer@4.20.1) (2021-02-11) - -**Note:** Version bump only for package graphql-connection-transformer - -# [4.20.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.19.4...graphql-connection-transformer@4.20.0) (2021-02-10) - -### Features - -- **graphql-connection-transformer:** allow null key-based connections ([#5153](https://github.com/aws-amplify/amplify-cli/issues/5153)) ([e9c8276](https://github.com/aws-amplify/amplify-cli/commit/e9c82768df42144291c70bc719db9f1ab546c39a)) - -## [4.19.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.19.3...graphql-connection-transformer@4.19.4) (2020-12-16) - -### Bug Fixes - -- **graphql-key-transformer:** prevent non-scalar key fields ([#5319](https://github.com/aws-amplify/amplify-cli/issues/5319)) ([4a5b305](https://github.com/aws-amplify/amplify-cli/commit/4a5b305dd695e61fcbc4ce0ca659b6f5a1c7e467)), closes [#5300](https://github.com/aws-amplify/amplify-cli/issues/5300) -- [#6108](https://github.com/aws-amplify/amplify-cli/issues/6108) - add proper AWSJSON mapping in generated filter input types ([#6112](https://github.com/aws-amplify/amplify-cli/issues/6112)) ([743e84a](https://github.com/aws-amplify/amplify-cli/commit/743e84a9d968aab4648a12d3a19aa5ea14c4d755)) - -### Reverts - -- Revert "Revert "Revert "fix: #6108 - add proper AWSJSON mapping in generated filter input types (#6112)" (#6158)" (#6160)" (#6183) ([a0ca94e](https://github.com/aws-amplify/amplify-cli/commit/a0ca94e5a1a848404ef3977743f19d26300a636a)), closes [#6108](https://github.com/aws-amplify/amplify-cli/issues/6108) [#6112](https://github.com/aws-amplify/amplify-cli/issues/6112) [#6158](https://github.com/aws-amplify/amplify-cli/issues/6158) [#6160](https://github.com/aws-amplify/amplify-cli/issues/6160) [#6183](https://github.com/aws-amplify/amplify-cli/issues/6183) -- Revert "fix(graphql-key-transformer): prevent non-scalar key fields (#5319)" (#6181) ([c61268d](https://github.com/aws-amplify/amplify-cli/commit/c61268d093571c906c13e7033552503b9fd83a98)), closes [#5319](https://github.com/aws-amplify/amplify-cli/issues/5319) [#6181](https://github.com/aws-amplify/amplify-cli/issues/6181) -- Revert "Revert "fix: #6108 - add proper AWSJSON mapping in generated filter input types (#6112)" (#6158)" (#6160) ([f425924](https://github.com/aws-amplify/amplify-cli/commit/f42592420dcb49640c680c5001b3026ae0129090)), closes [#6108](https://github.com/aws-amplify/amplify-cli/issues/6108) [#6112](https://github.com/aws-amplify/amplify-cli/issues/6112) [#6158](https://github.com/aws-amplify/amplify-cli/issues/6158) [#6160](https://github.com/aws-amplify/amplify-cli/issues/6160) -- Revert "fix: #6108 - add proper AWSJSON mapping in generated filter input types (#6112)" (#6158) ([9e57e4d](https://github.com/aws-amplify/amplify-cli/commit/9e57e4d8c887be8ee4119c87383c7379cec40c37)), closes [#6108](https://github.com/aws-amplify/amplify-cli/issues/6108) [#6112](https://github.com/aws-amplify/amplify-cli/issues/6112) [#6158](https://github.com/aws-amplify/amplify-cli/issues/6158) - -## [4.19.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.19.2...graphql-connection-transformer@4.19.3) (2020-12-07) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.19.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.19.1...graphql-connection-transformer@4.19.2) (2020-11-30) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.19.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.18...graphql-connection-transformer@4.19.1) (2020-11-22) - -**Note:** Version bump only for package graphql-connection-transformer - -# [4.19.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.5.5...graphql-connection-transformer@4.19.0) (2020-11-22) - -### Bug Fixes - -- **graphql-connection-transformer:** error if field not in relatedType ([#4481](https://github.com/aws-amplify/amplify-cli/issues/4481)) ([48e4a5e](https://github.com/aws-amplify/amplify-cli/commit/48e4a5ed8656f963d7cde49d465e4436b313e23e)), closes [#4236](https://github.com/aws-amplify/amplify-cli/issues/4236) -- add custom enum filter to connection filter ([#4269](https://github.com/aws-amplify/amplify-cli/issues/4269)) ([f559df0](https://github.com/aws-amplify/amplify-cli/commit/f559df077015c1c8d8462a92968093efdc5b9452)) -- **graphql-connection-transformer:** limit was not respected ([#4021](https://github.com/aws-amplify/amplify-cli/issues/4021)) ([480d0a0](https://github.com/aws-amplify/amplify-cli/commit/480d0a02a5744225d8375f447ab8dc642e285eaa)) -- [#3438](https://github.com/aws-amplify/amplify-cli/issues/3438), many-to-many with conflict resolution generated wrong schema ([#4171](https://github.com/aws-amplify/amplify-cli/issues/4171)) ([9e8606c](https://github.com/aws-amplify/amplify-cli/commit/9e8606c4a300b5690839ec0869f7384aff189b1f)) -- add AttributeTypeEnum for connections on models with no codegen ([#4102](https://github.com/aws-amplify/amplify-cli/issues/4102)) ([4e92402](https://github.com/aws-amplify/amplify-cli/commit/4e92402e0b0fae30501972f3ad16203fc19ba287)) -- **graphql-connection-transformer:** support non string type in sort key ([#3492](https://github.com/aws-amplify/amplify-cli/issues/3492)) ([bc4a1d9](https://github.com/aws-amplify/amplify-cli/commit/bc4a1d9bd707c62ea2c4ec685401f34dfeca0bd0)), closes [#3403](https://github.com/aws-amplify/amplify-cli/issues/3403) -- **graphql-connection-transformer:** valiate composite sortkey ([#3419](https://github.com/aws-amplify/amplify-cli/issues/3419)) ([e9d0e95](https://github.com/aws-amplify/amplify-cli/commit/e9d0e95616075d9f152191bc5eb0ee612f8f65c0)) -- [#2296](https://github.com/aws-amplify/amplify-cli/issues/2296) [#2304](https://github.com/aws-amplify/amplify-cli/issues/2304) [#2100](https://github.com/aws-amplify/amplify-cli/issues/2100) ([#2439](https://github.com/aws-amplify/amplify-cli/issues/2439)) ([82762d6](https://github.com/aws-amplify/amplify-cli/commit/82762d6187eb2102ebd134b181622188c5632d1d)) -- [#2347](https://github.com/aws-amplify/amplify-cli/issues/2347) - enum validation for key directive ([#2363](https://github.com/aws-amplify/amplify-cli/issues/2363)) ([1facade](https://github.com/aws-amplify/amplify-cli/commit/1facaded3095eaff5a015e76ca4d718b7bc3c938)) -- [#2389](https://github.com/aws-amplify/amplify-cli/issues/2389) ([#2538](https://github.com/aws-amplify/amplify-cli/issues/2538)) ([fb92a9d](https://github.com/aws-amplify/amplify-cli/commit/fb92a9d7c6a1f807e49b7f899531de90cc1f4ee3)) -- build break, chore: typescript, lerna update ([#2640](https://github.com/aws-amplify/amplify-cli/issues/2640)) ([29fae36](https://github.com/aws-amplify/amplify-cli/commit/29fae366f4cab054feefa58c7dc733002d19570c)) -- export Typescript definitions and fix resulting type errors ([#2452](https://github.com/aws-amplify/amplify-cli/issues/2452)) ([7de3845](https://github.com/aws-amplify/amplify-cli/commit/7de384594d3b9cbf22cdaa85107fc8df26c141ec)), closes [#2451](https://github.com/aws-amplify/amplify-cli/issues/2451) -- sanitize input in transformer resolver([#3316](https://github.com/aws-amplify/amplify-cli/issues/3316)) ([a3bc0a5](https://github.com/aws-amplify/amplify-cli/commit/a3bc0a5e5d3faa7946d16d0f6595ce8c2f3c11dc)) -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) -- **graphql-connection-transformer:** fix self connection bug ([#1944](https://github.com/aws-amplify/amplify-cli/issues/1944)) ([1a6affc](https://github.com/aws-amplify/amplify-cli/commit/1a6affc7cc5ba0d59c908b6f6a58852013d22343)), closes [#1799](https://github.com/aws-amplify/amplify-cli/issues/1799) - -### Features - -- **amplify-category-api:** change default graphql query limit to 100 ([#4124](https://github.com/aws-amplify/amplify-cli/issues/4124)) ([1a68c4d](https://github.com/aws-amplify/amplify-cli/commit/1a68c4d589e2101357dec4e980719fc547964e23)) -- **amplify-codegen-appsync-model-plugin:** modelgen connection support ([#2836](https://github.com/aws-amplify/amplify-cli/issues/2836)) ([353749c](https://github.com/aws-amplify/amplify-cli/commit/353749ce6643a07206a1f4c30d00beb775db169e)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) -- **graphql-connection-transformer:** limit ([#1953](https://github.com/aws-amplify/amplify-cli/issues/1953)) ([dcaf844](https://github.com/aws-amplify/amplify-cli/commit/dcaf84480974e7a697d1ea29782a4f5032a77942)) -- **graphql-dynamodb-transformer:** expose createdAt and updatedAt on model ([#4149](https://github.com/aws-amplify/amplify-cli/issues/4149)) ([8e0662e](https://github.com/aws-amplify/amplify-cli/commit/8e0662eac8c88da9393f32c33457a597acf591ed)), closes [#401](https://github.com/aws-amplify/amplify-cli/issues/401) -- **graphql-key-transformer:** add query automatically for named keys ([#4458](https://github.com/aws-amplify/amplify-cli/issues/4458)) ([375282d](https://github.com/aws-amplify/amplify-cli/commit/375282d648cf9d096d13c7b958a0dfb7bd6d60b0)) -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c1927da10f8c54f38a523021187361131c)) -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- updated version of [#2118](https://github.com/aws-amplify/amplify-cli/issues/2118) with addressed review comments ([#2230](https://github.com/aws-amplify/amplify-cli/issues/2230)) ([be3c499](https://github.com/aws-amplify/amplify-cli/commit/be3c499edcc6bec63b38e9241c5af7b83c930022)) - -### Reverts - -- add query automatically for named keys ([#4513](https://github.com/aws-amplify/amplify-cli/issues/4513)) ([50c1120](https://github.com/aws-amplify/amplify-cli/commit/50c112050645b8fd5011a1e6863d30f58e0c55cb)) - -## [4.18.21](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.18...graphql-connection-transformer@4.18.21) (2020-11-20) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.18.20](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.18...graphql-connection-transformer@4.18.20) (2020-11-20) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.18.19](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.18...graphql-connection-transformer@4.18.19) (2020-11-19) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.18.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.17...graphql-connection-transformer@4.18.18) (2020-11-08) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.18.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.16...graphql-connection-transformer@4.18.17) (2020-10-30) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.18.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.15...graphql-connection-transformer@4.18.16) (2020-10-27) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.18.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.14...graphql-connection-transformer@4.18.15) (2020-10-22) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.18.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.13...graphql-connection-transformer@4.18.14) (2020-10-17) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.18.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.12...graphql-connection-transformer@4.18.13) (2020-10-01) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.18.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.11...graphql-connection-transformer@4.18.12) (2020-09-16) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.18.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.10...graphql-connection-transformer@4.18.11) (2020-09-02) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.18.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.9...graphql-connection-transformer@4.18.10) (2020-08-31) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.18.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.8...graphql-connection-transformer@4.18.9) (2020-08-14) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.18.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.7...graphql-connection-transformer@4.18.8) (2020-08-11) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.18.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.5...graphql-connection-transformer@4.18.7) (2020-07-29) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.18.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.5...graphql-connection-transformer@4.18.6) (2020-07-23) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.18.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.4...graphql-connection-transformer@4.18.5) (2020-07-18) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.18.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.3...graphql-connection-transformer@4.18.4) (2020-07-15) - -### Bug Fixes - -- **graphql-connection-transformer:** error if field not in relatedType ([#4481](https://github.com/aws-amplify/amplify-cli/issues/4481)) ([0a6a7ea](https://github.com/aws-amplify/amplify-cli/commit/0a6a7eabbe726d7add52b8a8811c54f7257d176f)), closes [#4236](https://github.com/aws-amplify/amplify-cli/issues/4236) - -## [4.18.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.2...graphql-connection-transformer@4.18.3) (2020-06-25) - -### Reverts - -- Revert "fix: change scope of hashed files for AppSync (#4602)" ([73aaab1](https://github.com/aws-amplify/amplify-cli/commit/73aaab1a7b1f8b2de5fa22fa1ef9aeea7de35cb4)), closes [#4602](https://github.com/aws-amplify/amplify-cli/issues/4602) - -## [4.18.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.1...graphql-connection-transformer@4.18.2) (2020-06-18) - -### Bug Fixes - -- change scope of hashed files for AppSync ([#4602](https://github.com/aws-amplify/amplify-cli/issues/4602)) ([10fa9da](https://github.com/aws-amplify/amplify-cli/commit/10fa9da646f4de755e2dc92cd4bb2a6319425d72)), closes [#4458](https://github.com/aws-amplify/amplify-cli/issues/4458) - -## [4.18.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.18.0...graphql-connection-transformer@4.18.1) (2020-06-11) - -### Reverts - -- add query automatically for named keys ([#4513](https://github.com/aws-amplify/amplify-cli/issues/4513)) ([6d3123b](https://github.com/aws-amplify/amplify-cli/commit/6d3123bfe3ba412d3b1af076e550e6733c988c8f)) - -# [4.18.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.17.2...graphql-connection-transformer@4.18.0) (2020-06-10) - -### Features - -- **graphql-key-transformer:** add query automatically for named keys ([#4458](https://github.com/aws-amplify/amplify-cli/issues/4458)) ([3d194f8](https://github.com/aws-amplify/amplify-cli/commit/3d194f805dcbd6325ddf78155c4327dbca3e7f4a)) - -## [4.17.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.17.1...graphql-connection-transformer@4.17.2) (2020-06-02) - -### Bug Fixes - -- add custom enum filter to connection filter ([#4269](https://github.com/aws-amplify/amplify-cli/issues/4269)) ([a29d427](https://github.com/aws-amplify/amplify-cli/commit/a29d427dc23f82f04d4e7b79402dd9642591e759)) - -## [4.17.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.17.0...graphql-connection-transformer@4.17.1) (2020-05-26) - -### Bug Fixes - -- **graphql-connection-transformer:** limit was not respected ([#4021](https://github.com/aws-amplify/amplify-cli/issues/4021)) ([9800384](https://github.com/aws-amplify/amplify-cli/commit/9800384efff53a57973105508482cad945523727)) - -# [4.17.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.16.0...graphql-connection-transformer@4.17.0) (2020-05-15) - -### Features - -- **graphql-dynamodb-transformer:** expose createdAt and updatedAt on model ([#4149](https://github.com/aws-amplify/amplify-cli/issues/4149)) ([8e0662e](https://github.com/aws-amplify/amplify-cli/commit/8e0662eac8c88da9393f32c33457a597acf591ed)), closes [#401](https://github.com/aws-amplify/amplify-cli/issues/401) - -# [4.16.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.15.3...graphql-connection-transformer@4.16.0) (2020-05-08) - -### Bug Fixes - -- [#3438](https://github.com/aws-amplify/amplify-cli/issues/3438), many-to-many with conflict resolution generated wrong schema ([#4171](https://github.com/aws-amplify/amplify-cli/issues/4171)) ([9e8606c](https://github.com/aws-amplify/amplify-cli/commit/9e8606c4a300b5690839ec0869f7384aff189b1f)) -- add AttributeTypeEnum for connections on models with no codegen ([#4102](https://github.com/aws-amplify/amplify-cli/issues/4102)) ([4e92402](https://github.com/aws-amplify/amplify-cli/commit/4e92402e0b0fae30501972f3ad16203fc19ba287)) - -### Features - -- **amplify-category-api:** change default graphql query limit to 100 ([#4124](https://github.com/aws-amplify/amplify-cli/issues/4124)) ([1a68c4d](https://github.com/aws-amplify/amplify-cli/commit/1a68c4d589e2101357dec4e980719fc547964e23)) - -## [4.15.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.15.2...graphql-connection-transformer@4.15.3) (2020-04-23) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.15.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.15.1...graphql-connection-transformer@4.15.2) (2020-03-22) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.15.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.13.4...graphql-connection-transformer@4.15.1) (2020-03-07) - -### Bug Fixes - -- **graphql-connection-transformer:** support non string type in sort key ([#3492](https://github.com/aws-amplify/amplify-cli/issues/3492)) ([bc4a1d9](https://github.com/aws-amplify/amplify-cli/commit/bc4a1d9bd707c62ea2c4ec685401f34dfeca0bd0)), closes [#3403](https://github.com/aws-amplify/amplify-cli/issues/3403) -- **graphql-connection-transformer:** valiate composite sortkey ([#3419](https://github.com/aws-amplify/amplify-cli/issues/3419)) ([e9d0e95](https://github.com/aws-amplify/amplify-cli/commit/e9d0e95616075d9f152191bc5eb0ee612f8f65c0)) - -## [4.14.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.13.6-beta.0...graphql-connection-transformer@4.14.1) (2020-03-05) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.13.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.13.3...graphql-connection-transformer@4.13.4) (2020-02-18) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.13.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.13.2...graphql-connection-transformer@4.13.3) (2020-02-13) - -**Note:** Version bump only for package graphql-connection-transformer - -## [4.13.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.13.1...graphql-connection-transformer@4.13.2) (2020-02-07) - -### Bug Fixes - -- sanitize input in transformer resolver([#3316](https://github.com/aws-amplify/amplify-cli/issues/3316)) ([a3bc0a5](https://github.com/aws-amplify/amplify-cli/commit/a3bc0a5e5d3faa7946d16d0f6595ce8c2f3c11dc)) - -## [4.13.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@4.13.0...graphql-connection-transformer@4.13.1) (2020-01-24) - -**Note:** Version bump only for package graphql-connection-transformer - -# [4.13.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.29.0...graphql-connection-transformer@4.13.0) (2020-01-23) - -### Bug Fixes - -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **amplify-codegen-appsync-model-plugin:** modelgen connection support ([#2836](https://github.com/aws-amplify/amplify-cli/issues/2836)) ([353749c](https://github.com/aws-amplify/amplify-cli/commit/353749ce6643a07206a1f4c30d00beb775db169e)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.12.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.29.0...graphql-connection-transformer@4.12.0) (2020-01-09) - -### Bug Fixes - -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **amplify-codegen-appsync-model-plugin:** modelgen connection support ([#2836](https://github.com/aws-amplify/amplify-cli/issues/2836)) ([353749c](https://github.com/aws-amplify/amplify-cli/commit/353749ce6643a07206a1f4c30d00beb775db169e)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.11.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.29.0...graphql-connection-transformer@4.11.0) (2019-12-31) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **amplify-codegen-appsync-model-plugin:** modelgen connection support ([#2836](https://github.com/aws-amplify/amplify-cli/issues/2836)) ([353749c](https://github.com/aws-amplify/amplify-cli/commit/353749ce6643a07206a1f4c30d00beb775db169e)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.10.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.29.0...graphql-connection-transformer@4.10.0) (2019-12-28) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **amplify-codegen-appsync-model-plugin:** modelgen connection support ([#2836](https://github.com/aws-amplify/amplify-cli/issues/2836)) ([353749c](https://github.com/aws-amplify/amplify-cli/commit/353749ce6643a07206a1f4c30d00beb775db169e)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.9.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.29.0...graphql-connection-transformer@4.9.0) (2019-12-26) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **amplify-codegen-appsync-model-plugin:** modelgen connection support ([#2836](https://github.com/aws-amplify/amplify-cli/issues/2836)) ([353749c](https://github.com/aws-amplify/amplify-cli/commit/353749ce6643a07206a1f4c30d00beb775db169e)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.8.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.29.0...graphql-connection-transformer@4.8.0) (2019-12-25) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **amplify-codegen-appsync-model-plugin:** modelgen connection support ([#2836](https://github.com/aws-amplify/amplify-cli/issues/2836)) ([353749c](https://github.com/aws-amplify/amplify-cli/commit/353749ce6643a07206a1f4c30d00beb775db169e)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.7.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.29.0...graphql-connection-transformer@4.7.0) (2019-12-20) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **amplify-codegen-appsync-model-plugin:** modelgen connection support ([#2836](https://github.com/aws-amplify/amplify-cli/issues/2836)) ([353749c](https://github.com/aws-amplify/amplify-cli/commit/353749ce6643a07206a1f4c30d00beb775db169e)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.6.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.29.0...graphql-connection-transformer@4.6.0) (2019-12-10) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **amplify-codegen-appsync-model-plugin:** modelgen connection support ([#2836](https://github.com/aws-amplify/amplify-cli/issues/2836)) ([353749c](https://github.com/aws-amplify/amplify-cli/commit/353749ce6643a07206a1f4c30d00beb775db169e)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.4.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.29.0...graphql-connection-transformer@4.4.0) (2019-12-03) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **amplify-codegen-appsync-model-plugin:** modelgen connection support ([#2836](https://github.com/aws-amplify/amplify-cli/issues/2836)) ([353749c](https://github.com/aws-amplify/amplify-cli/commit/353749ce6643a07206a1f4c30d00beb775db169e)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.3.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.29.0...graphql-connection-transformer@4.3.0) (2019-12-01) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **amplify-codegen-appsync-model-plugin:** modelgen connection support ([#2836](https://github.com/aws-amplify/amplify-cli/issues/2836)) ([353749c](https://github.com/aws-amplify/amplify-cli/commit/353749ce6643a07206a1f4c30d00beb775db169e)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.2.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.29.0...graphql-connection-transformer@4.2.0) (2019-11-27) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **amplify-codegen-appsync-model-plugin:** modelgen connection support ([#2836](https://github.com/aws-amplify/amplify-cli/issues/2836)) ([353749c](https://github.com/aws-amplify/amplify-cli/commit/353749ce6643a07206a1f4c30d00beb775db169e)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.1.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.29.0...graphql-connection-transformer@4.1.0) (2019-11-27) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **amplify-codegen-appsync-model-plugin:** modelgen connection support ([#2836](https://github.com/aws-amplify/amplify-cli/issues/2836)) ([353749c](https://github.com/aws-amplify/amplify-cli/commit/353749ce6643a07206a1f4c30d00beb775db169e)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [3.11.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.5.5...graphql-connection-transformer@3.11.0) (2019-08-30) - -### Bug Fixes - -- **graphql-connection-transformer:** fix self connection bug ([#1944](https://github.com/aws-amplify/amplify-cli/issues/1944)) ([1a6affc](https://github.com/aws-amplify/amplify-cli/commit/1a6affc)), closes [#1799](https://github.com/aws-amplify/amplify-cli/issues/1799) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.10.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.5.5...graphql-connection-transformer@3.10.0) (2019-08-28) - -### Bug Fixes - -- **graphql-connection-transformer:** fix self connection bug ([#1944](https://github.com/aws-amplify/amplify-cli/issues/1944)) ([1a6affc](https://github.com/aws-amplify/amplify-cli/commit/1a6affc)), closes [#1799](https://github.com/aws-amplify/amplify-cli/issues/1799) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.9.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.5.5...graphql-connection-transformer@3.9.0) (2019-08-13) - -### Bug Fixes - -- **graphql-connection-transformer:** fix self connection bug ([#1944](https://github.com/aws-amplify/amplify-cli/issues/1944)) ([1a6affc](https://github.com/aws-amplify/amplify-cli/commit/1a6affc)), closes [#1799](https://github.com/aws-amplify/amplify-cli/issues/1799) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.8.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.5.5...graphql-connection-transformer@3.8.0) (2019-08-07) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.7.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.5.5...graphql-connection-transformer@3.7.0) (2019-08-02) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.6.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.5.5...graphql-connection-transformer@3.6.0) (2019-07-31) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -## [3.5.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.5.4...graphql-connection-transformer@3.5.5) (2019-07-24) - -**Note:** Version bump only for package graphql-connection-transformer - -## [3.5.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.5.2...graphql-connection-transformer@3.5.4) (2019-06-30) - -**Note:** Version bump only for package graphql-connection-transformer - -## [3.5.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.5.1...graphql-connection-transformer@3.5.2) (2019-06-26) - -**Note:** Version bump only for package graphql-connection-transformer - -## [3.5.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.5.0...graphql-connection-transformer@3.5.1) (2019-06-12) - -**Note:** Version bump only for package graphql-connection-transformer - -# [3.5.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.4.6...graphql-connection-transformer@3.5.0) (2019-05-29) - -### Features - -- feature/[@key](https://github.com/key) ([#1463](https://github.com/aws-amplify/amplify-cli/issues/1463)) ([00ed819](https://github.com/aws-amplify/amplify-cli/commit/00ed819)) - -## [3.4.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.4.5...graphql-connection-transformer@3.4.6) (2019-05-21) - -**Note:** Version bump only for package graphql-connection-transformer - -## [3.4.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.4.4...graphql-connection-transformer@3.4.5) (2019-05-17) - -**Note:** Version bump only for package graphql-connection-transformer - -## [3.4.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.4.2...graphql-connection-transformer@3.4.4) (2019-05-07) - -**Note:** Version bump only for package graphql-connection-transformer - -## [3.4.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.4.2...graphql-connection-transformer@3.4.3) (2019-05-06) - -**Note:** Version bump only for package graphql-connection-transformer - -## [3.4.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.4.1...graphql-connection-transformer@3.4.2) (2019-04-16) - -**Note:** Version bump only for package graphql-connection-transformer - -## [3.4.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.3.1...graphql-connection-transformer@3.4.1) (2019-04-09) - -**Note:** Version bump only for package graphql-connection-transformer - -## [3.3.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.0.9...graphql-connection-transformer@3.3.1) (2019-04-03) - -**Note:** Version bump only for package graphql-connection-transformer - -## [3.0.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.0.8...graphql-connection-transformer@3.0.9) (2019-03-22) - -**Note:** Version bump only for package graphql-connection-transformer - -## [3.0.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.0.7...graphql-connection-transformer@3.0.8) (2019-03-05) - -**Note:** Version bump only for package graphql-connection-transformer - -## [3.0.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.0.6...graphql-connection-transformer@3.0.7) (2019-02-20) - -**Note:** Version bump only for package graphql-connection-transformer - -## [3.0.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.0.5...graphql-connection-transformer@3.0.6) (2019-02-12) - -### Bug Fixes - -- cloudform/type versions ([ec6f99f](https://github.com/aws-amplify/amplify-cli/commit/ec6f99f)) - -## [3.0.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.0.3-beta.0...graphql-connection-transformer@3.0.5) (2019-02-11) - -**Note:** Version bump only for package graphql-connection-transformer - -## [3.0.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.0.3-beta.0...graphql-connection-transformer@3.0.3) (2019-02-11) - -**Note:** Version bump only for package graphql-connection-transformer - -## [3.0.3-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@3.0.2...graphql-connection-transformer@3.0.3-beta.0) (2019-02-11) - -**Note:** Version bump only for package graphql-connection-transformer - - - -# [2.0.0-multienv.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.34-multienv.1...graphql-connection-transformer@2.0.0-multienv.2) (2018-12-31) - -### Bug Fixes - -- update grahql transformer package versions for multienv ([8b4b2bd](https://github.com/aws-amplify/amplify-cli/commit/8b4b2bd)) - - - -## [1.0.34-multienv.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.34-multienv.0...graphql-connection-transformer@1.0.34-multienv.1) (2018-12-19) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.34-multienv.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.33...graphql-connection-transformer@1.0.34-multienv.0) (2018-11-16) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.33](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.33-beta.0...graphql-connection-transformer@1.0.33) (2018-11-09) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.33-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.12...graphql-connection-transformer@1.0.33-beta.0) (2018-11-09) - -### Bug Fixes - -- **graphql-connection-transformer:** Remove unused types ([87c3e0a](https://github.com/aws-amplify/amplify-cli/commit/87c3e0a)) - - - -## [1.0.32](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.32-beta.0...graphql-connection-transformer@1.0.32) (2018-11-05) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.32-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.12...graphql-connection-transformer@1.0.32-beta.0) (2018-11-05) - -### Bug Fixes - -- **graphql-connection-transformer:** Remove unused types ([87c3e0a](https://github.com/aws-amplify/amplify-cli/commit/87c3e0a)) - - - -## [1.0.31](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.12...graphql-connection-transformer@1.0.31) (2018-11-02) - -### Bug Fixes - -- **graphql-connection-transformer:** Remove unused types ([87c3e0a](https://github.com/aws-amplify/amplify-cli/commit/87c3e0a)) - - - -## [1.0.30](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.30-beta.0...graphql-connection-transformer@1.0.30) (2018-11-02) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.30-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.12...graphql-connection-transformer@1.0.30-beta.0) (2018-11-02) - -### Bug Fixes - -- **graphql-connection-transformer:** Remove unused types ([87c3e0a](https://github.com/aws-amplify/amplify-cli/commit/87c3e0a)) - - - -## [1.0.29](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.29-beta.0...graphql-connection-transformer@1.0.29) (2018-10-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.29-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.12...graphql-connection-transformer@1.0.29-beta.0) (2018-10-23) - -### Bug Fixes - -- **graphql-connection-transformer:** Remove unused types ([87c3e0a](https://github.com/aws-amplify/amplify-cli/commit/87c3e0a)) - - - -## [1.0.28](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.28-beta.0...graphql-connection-transformer@1.0.28) (2018-10-18) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.28-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.12...graphql-connection-transformer@1.0.28-beta.0) (2018-10-12) - -### Bug Fixes - -- **graphql-connection-transformer:** Remove unused types ([87c3e0a](https://github.com/aws-amplify/amplify-cli/commit/87c3e0a)) - - - -## [1.0.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.11...graphql-connection-transformer@1.0.12) (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.10...graphql-connection-transformer@1.0.11) (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.9...graphql-connection-transformer@1.0.10) (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.8...graphql-connection-transformer@1.0.9) (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.7...graphql-connection-transformer@1.0.8) (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.6...graphql-connection-transformer@1.0.7) (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.5...graphql-connection-transformer@1.0.6) (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.4...graphql-connection-transformer@1.0.5) (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## 1.0.4 (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## 1.0.3 (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## 1.0.2 (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## 1.0.1 (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer diff --git a/packages/graphql-connection-transformer/package.json b/packages/graphql-connection-transformer/package.json deleted file mode 100644 index b3b229882d..0000000000 --- a/packages/graphql-connection-transformer/package.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "name": "graphql-connection-transformer", - "version": "5.2.80", - "description": "An AppSync model transform for connecting objects.", - "repository": { - "type": "git", - "url": "https://github.com/aws-amplify/amplify-category-api.git", - "directory": "packages/graphql-connection-transformer" - }, - "author": "Amazon Web Services", - "license": "Apache-2.0", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "keywords": [ - "graphql", - "appsync", - "aws" - ], - "scripts": { - "test": "jest", - "build": "tsc", - "clean": "rimraf ./lib", - "extract-api": "ts-node ../../scripts/extract-api.ts" - }, - "dependencies": { - "cloudform-types": "^4.2.0", - "graphql": "^15.5.0", - "graphql-dynamodb-transformer": "7.2.80", - "graphql-key-transformer": "3.2.80", - "graphql-mapping-template": "4.20.16", - "graphql-transformer-common": "4.31.1", - "graphql-transformer-core": "8.2.13" - }, - "jest": { - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, - "testURL": "http://localhost/", - "testRegex": "(src/__tests__/.*.test.(t|j)s)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], - "collectCoverage": true, - "coverageProvider": "v8", - "coverageThreshold": { - "global": { - "branches": 88, - "functions": 90, - "lines": 90 - } - }, - "coverageReporters": [ - "clover", - "text" - ], - "collectCoverageFrom": [ - "src/**/*.ts" - ], - "coveragePathIgnorePatterns": [ - "/__tests__/" - ] - } -} diff --git a/packages/graphql-connection-transformer/src/ModelConnectionTransformer.ts b/packages/graphql-connection-transformer/src/ModelConnectionTransformer.ts deleted file mode 100644 index 0ce9e26d09..0000000000 --- a/packages/graphql-connection-transformer/src/ModelConnectionTransformer.ts +++ /dev/null @@ -1,791 +0,0 @@ -import { Transformer, TransformerContext, InvalidDirectiveError, getDirectiveArguments } from 'graphql-transformer-core'; -import { ConnectionDirectiveV1 } from '@aws-amplify/graphql-directives'; -import { - DirectiveNode, - ObjectTypeDefinitionNode, - Kind, - FieldDefinitionNode, - InterfaceTypeDefinitionNode, - InputObjectTypeDefinitionNode, - EnumTypeDefinitionNode, - parse, -} from 'graphql'; -import { - makeModelConnectionType, - makeModelConnectionField, - makeScalarFilterInputs, - makeModelXFilterInputObject, - makeModelSortDirectionEnumObject, - SortKeyFieldInfoTypeName, - CONDITIONS_MINIMUM_VERSION, - makeAttributeTypeEnum, - makeEnumFilterInputObjects, -} from 'graphql-dynamodb-transformer'; -import { - getBaseType, - isListType, - getDirectiveArgument, - blankObject, - isScalar, - isScalarOrEnum, - STANDARD_SCALARS, - toCamelCase, - isNonNullType, - attributeTypeFromScalar, - makeScalarKeyConditionForType, - makeNamedType, - ResolverResourceIDs, - ModelResourceIDs, -} from 'graphql-transformer-common'; -import Table, { KeySchema, GlobalSecondaryIndex, LocalSecondaryIndex } from 'cloudform-types/types/dynamoDb/table'; -import { updateInputWithConnectionField } from './definitions'; -import { ResourceFactory } from './resources'; - -const CONNECTION_STACK_NAME = 'ConnectionStack'; - -interface RelationArguments { - keyName?: string; - fields: string[]; - limit?: number; -} - -function makeConnectionAttributeName(type: string, field?: string) { - // The same logic is used in amplify-codegen-appsync-model-plugin package to generate association field - // Make sure the logic gets update in that package - return field ? toCamelCase([type, field, 'id']) : toCamelCase([type, 'id']); -} - -function validateKeyField(field: FieldDefinitionNode): void { - if (!field) { - return; - } - const baseType = getBaseType(field.type); - const isAList = isListType(field.type); - // The only valid key fields are single String and ID fields. - if ((baseType === 'ID' || baseType === 'String') && !isAList) { - return; - } - throw new InvalidDirectiveError(`If you define a field and specify it as a 'keyField', it must be of type 'ID' or 'String'.`); -} - -/** - * Ensure that the field passed in is compatible to be a key field - * (Not a list and of type ID or String) - * @param field: the field to be checked. - */ -function validateKeyFieldConnectionWithKey(field: FieldDefinitionNode, ctx: TransformerContext): void { - const isAList = isListType(field.type); - const isAScalarOrEnum = isScalarOrEnum(field.type, ctx.getTypeDefinitionsOfKind(Kind.ENUM_TYPE_DEFINITION) as EnumTypeDefinitionNode[]); - - // The only valid key fields are single non-null fields. - if (!isAList && isAScalarOrEnum) { - return; - } - throw new InvalidDirectiveError(`All fields provided to an @connection must be scalar or enum fields.`); -} - -/** - * Returns the type of the field with the field name specified by finding it from the array of fields - * and returning its type. - * @param fields Array of FieldDefinitionNodes to search within. - * @param fieldName Name of the field whose type is to be fetched. - */ -function getFieldType(relatedType: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, fieldName: string) { - const foundField = relatedType.fields.find((f) => f.name.value === fieldName); - if (!foundField) { - throw new InvalidDirectiveError(`${fieldName} is not defined in ${relatedType.name.value}.`); - } - return foundField.type; -} - -/** - * Checks that the fields being used to query match the expected key types for the index being used. - * @param parent: All fields of the parent object. - * @param relatedTypeFields: All fields of the related object. - * @param inputFieldNames: The fields passed in to the @connection directive. - * @param keySchema: The key schema for the index being used. - */ -function checkFieldsAgainstIndex( - parent: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, - relatedType: ObjectTypeDefinitionNode, - inputFieldNames: string[], - keySchema: KeySchema[], - field: Readonly, -): void { - const hashAttributeName = keySchema[0].AttributeName; - const tablePKType = getFieldType(relatedType, String(hashAttributeName)); - const queryPKType = getFieldType(parent, inputFieldNames[0]); - const numFields = inputFieldNames.length; - - if (getBaseType(tablePKType) !== getBaseType(queryPKType)) { - throw new InvalidDirectiveError(`${inputFieldNames[0]} field is not of type ${getBaseType(tablePKType)}`); - } - if (numFields > keySchema.length && keySchema.length !== 2) { - throw new InvalidDirectiveError('Too many fields passed in to @connection directive.'); - } - // when sort key is passed, ensure that the length of composite sort key matches the length of the fields passed - if (numFields > 1) { - const querySortFields = inputFieldNames.slice(1); - const tableSortFields = String(keySchema[1].AttributeName).split(ModelResourceIDs.ModelCompositeKeySeparator()); - if (querySortFields.length !== tableSortFields.length) { - throw new InvalidDirectiveError(`Invalid @connection directive ${field.name.value}. fields does not accept partial sort key`); - } - } - if (numFields === 2) { - const sortAttributeName = String(keySchema[1].AttributeName).split(ModelResourceIDs.ModelCompositeKeySeparator())[0]; - const tableSKType = getFieldType(relatedType, String(sortAttributeName)); - const querySKType = getFieldType(parent, inputFieldNames[1]); - - if (getBaseType(tableSKType) !== getBaseType(querySKType)) { - throw new InvalidDirectiveError(`${inputFieldNames[1]} field is not of type ${getBaseType(tableSKType)}`); - } - } else if (numFields > 2) { - const tableSortFields = String(keySchema[1].AttributeName).split(ModelResourceIDs.ModelCompositeKeySeparator()); - const tableSortKeyTypes = tableSortFields.map((name) => getFieldType(relatedType, name)); - const querySortFields = inputFieldNames.slice(1); - const querySortKeyTypes = querySortFields.map((name) => getFieldType(parent, name)); - - // Check that types of each attribute match types of the fields that make up the composite sort key for the - // table or index being queried. - querySortKeyTypes.forEach((fieldType, index) => { - if (getBaseType(fieldType) !== getBaseType(tableSortKeyTypes[index])) { - throw new InvalidDirectiveError( - `${querySortFields[index]} field is not of type ${getBaseType(tableSortKeyTypes[index])} arguments`, - ); - } - }); - } -} - -/** - * The @connection transform. - * - * This transform configures the GSIs and resolvers needed to implement - * relationships at the GraphQL level. - */ -export class ModelConnectionTransformer extends Transformer { - resources: ResourceFactory; - - constructor() { - super('ModelConnectionTransformer', parse(ConnectionDirectiveV1.definition)); - this.resources = new ResourceFactory(); - } - - public before = (ctx: TransformerContext): void => { - const template = this.resources.initTemplate(); - ctx.mergeResources(template.Resources); - ctx.mergeParameters(template.Parameters); - ctx.mergeOutputs(template.Outputs); - }; - - /** - * Create a 1-1, 1-M, or M-1 connection between two model types. - * Throws an error if the related type is not an object type annotated with @model. - */ - public field = ( - parent: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, - field: FieldDefinitionNode, - directive: DirectiveNode, - ctx: TransformerContext, - ): void => { - const parentTypeName = parent.name.value; - const fieldName = field.name.value; - - ctx.mapResourceToStack(CONNECTION_STACK_NAME, ResolverResourceIDs.ResolverResourceID(parentTypeName, fieldName)); - - const parentModelDirective = parent.directives.find((dir: DirectiveNode) => dir.name.value === 'model'); - if (!parentModelDirective) { - throw new InvalidDirectiveError(`@connection must be on an @model object type field.`); - } - - const relatedTypeName = getBaseType(field.type); - const relatedType = ctx.inputDocument.definitions.find( - (d) => d.kind === Kind.OBJECT_TYPE_DEFINITION && d.name.value === relatedTypeName, - ) as ObjectTypeDefinitionNode | undefined; - if (!relatedType) { - throw new InvalidDirectiveError(`Could not find an object type named ${relatedTypeName}.`); - } - const modelDirective = relatedType.directives.find((dir: DirectiveNode) => dir.name.value === 'model'); - if (!modelDirective) { - throw new InvalidDirectiveError(`Object type ${relatedTypeName} must be annotated with @model.`); - } - - // Checks if "fields" argument is provided which indicates use of the new parameterization - // hence dive straight to new logic and return. - if (getDirectiveArgument(directive, 'fields')) { - this.connectionWithKey(parent, field, directive, ctx); - return; - } - - let connectionName = getDirectiveArgument(directive, 'name'); - let associatedSortFieldName = null; - let sortType = null; - // Find the associated connection field if one exists. - const associatedConnectionField = relatedType.fields.find((f: FieldDefinitionNode) => { - // Make sure we don't associate with the same field in a self connection - if (f === field) { - return false; - } - const relatedDirective = f.directives.find((dir: DirectiveNode) => dir.name.value === 'connection'); - if (relatedDirective) { - const relatedDirectiveName = getDirectiveArgument(relatedDirective, 'name'); - if (connectionName && relatedDirectiveName && relatedDirectiveName === connectionName) { - associatedSortFieldName = getDirectiveArgument(relatedDirective, 'sortField'); - return true; - } - } - return false; - }); - - if (connectionName && !associatedConnectionField) { - throw new InvalidDirectiveError( - `Found one half of connection "${connectionName}" at ${parentTypeName}.${fieldName} but no related field on type ${relatedTypeName}`, - ); - } - - connectionName = connectionName || `${parentTypeName}.${fieldName}`; - const leftConnectionIsList = isListType(field.type); - const leftConnectionIsNonNull = isNonNullType(field.type); - const rightConnectionIsList = associatedConnectionField ? isListType(associatedConnectionField.type) : undefined; - const rightConnectionIsNonNull = associatedConnectionField ? isNonNullType(associatedConnectionField.type) : undefined; - const limit = getDirectiveArgument(directive, 'limit'); - - let connectionAttributeName = getDirectiveArgument(directive, 'keyField'); - const associatedSortField = - associatedSortFieldName && parent.fields.find((f: FieldDefinitionNode) => f.name.value === associatedSortFieldName); - - if (associatedSortField) { - if (isListType(associatedSortField.type)) { - throw new InvalidDirectiveError(`sortField "${associatedSortFieldName}" is a list. It should be a scalar.`); - } - sortType = getBaseType(associatedSortField.type); - if (!isScalar(associatedSortField.type) || sortType === STANDARD_SCALARS.Boolean) { - throw new InvalidDirectiveError( - `sortField "${associatedSortFieldName}" is of type "${sortType}". ` + - `It should be a scalar that maps to a DynamoDB "String", "Number", or "Binary"`, - ); - } - } - - // This grabs the definition of the sort field when it lives on the foreign model. - // We use this to configure key condition arguments for the resolver on the many side of the @connection. - const foreignAssociatedSortField = - associatedSortFieldName && relatedType.fields.find((f: FieldDefinitionNode) => f.name.value === associatedSortFieldName); - const sortKeyInfo = foreignAssociatedSortField - ? { - fieldName: foreignAssociatedSortField.name.value, - attributeType: attributeTypeFromScalar(foreignAssociatedSortField.type), - typeName: getBaseType(foreignAssociatedSortField.type), - } - : undefined; - - // Relationship Cardinalities: - // 1. [] to [] - // 2. [] to {} - // 3. {} to [] - // 4. [] to ? - // 5. {} to ? - if (leftConnectionIsList && rightConnectionIsList) { - // 1. TODO. - // Use an intermediary table or other strategy like embedded string sets for many to many. - throw new InvalidDirectiveError(`Invalid Connection (${connectionName}): Many to Many connections are not yet supported.`); - } else if (leftConnectionIsList && rightConnectionIsList === false) { - // 2. [] to {} when the association exists. Note: false and undefined are not equal. - // Store a foreign key on the related table and wire up a Query resolver. - // This is the inverse of 3. - const primaryKeyField = this.getPrimaryKeyField(ctx, parent); - const idFieldName = primaryKeyField ? primaryKeyField.name.value : 'id'; - - if (!connectionAttributeName) { - connectionAttributeName = makeConnectionAttributeName(relatedTypeName, associatedConnectionField.name.value); - } - // Validate the provided key field is legit. - const existingKeyField = relatedType.fields.find((f) => f.name.value === connectionAttributeName); - validateKeyField(existingKeyField); - - const queryResolver = this.resources.makeQueryConnectionResolver( - parentTypeName, - fieldName, - relatedTypeName, - connectionAttributeName, - connectionName, - idFieldName, - // If there is a sort field for this connection query then use - sortKeyInfo, - limit, - ); - ctx.setResource(ResolverResourceIDs.ResolverResourceID(parentTypeName, fieldName), queryResolver); - - this.extendTypeWithConnection(ctx, parent, field, relatedType, sortKeyInfo); - } else if (!leftConnectionIsList && rightConnectionIsList) { - // 3. {} to [] when the association exists. - // Store foreign key on this table and wire up a GetItem resolver. - // This is the inverse of 2. - - // if the sortField is not defined as a field, throw an error - // Cannot assume the required type of the field - if (associatedSortFieldName && !associatedSortField) { - throw new InvalidDirectiveError( - `sortField "${associatedSortFieldName}" not found on type "${parent.name.value}", other half of connection "${connectionName}".`, - ); - } - - const primaryKeyField = this.getPrimaryKeyField(ctx, relatedType); - const idFieldName = primaryKeyField ? primaryKeyField.name.value : 'id'; - - if (!connectionAttributeName) { - connectionAttributeName = makeConnectionAttributeName(parentTypeName, fieldName); - } - // Validate the provided key field is legit. - const existingKeyField = parent.fields.find((f) => f.name.value === connectionAttributeName); - validateKeyField(existingKeyField); - - const tableLogicalId = ModelResourceIDs.ModelTableResourceID(parentTypeName); - const table = ctx.getResource(tableLogicalId) as Table; - const sortField = associatedSortField ? { name: associatedSortFieldName, type: sortType } : null; - const updated = this.resources.updateTableForConnection(table, connectionName, connectionAttributeName, sortField); - ctx.setResource(tableLogicalId, updated); - - const getResolver = this.resources.makeGetItemConnectionResolver( - parentTypeName, - fieldName, - relatedTypeName, - connectionAttributeName, - idFieldName, - ); - ctx.setResource(ResolverResourceIDs.ResolverResourceID(parentTypeName, fieldName), getResolver); - - // Update the create & update input objects for this - const createInputName = ModelResourceIDs.ModelCreateInputObjectName(parentTypeName); - const createInput = ctx.getType(createInputName) as InputObjectTypeDefinitionNode; - if (createInput) { - const updated = updateInputWithConnectionField(createInput, connectionAttributeName, leftConnectionIsNonNull); - ctx.putType(updated); - } - const updateInputName = ModelResourceIDs.ModelUpdateInputObjectName(parentTypeName); - const updateInput = ctx.getType(updateInputName) as InputObjectTypeDefinitionNode; - if (updateInput) { - const updated = updateInputWithConnectionField(updateInput, connectionAttributeName); - ctx.putType(updated); - } - } else if (leftConnectionIsList) { - // 4. [] to ? - // Store foreign key on the related table and wire up a Query resolver. - // This has no inverse and has limited knowlege of the connection. - const primaryKeyField = this.getPrimaryKeyField(ctx, parent); - const idFieldName = primaryKeyField ? primaryKeyField.name.value : 'id'; - - if (!connectionAttributeName) { - connectionAttributeName = makeConnectionAttributeName(parentTypeName, fieldName); - } - - // Validate the provided key field is legit. - const existingKeyField = relatedType.fields.find((f) => f.name.value === connectionAttributeName); - validateKeyField(existingKeyField); - - const tableLogicalId = ModelResourceIDs.ModelTableResourceID(relatedTypeName); - const table = ctx.getResource(tableLogicalId) as Table; - const updated = this.resources.updateTableForConnection(table, connectionName, connectionAttributeName); - ctx.setResource(tableLogicalId, updated); - - const queryResolver = this.resources.makeQueryConnectionResolver( - parentTypeName, - fieldName, - relatedTypeName, - connectionAttributeName, - connectionName, - idFieldName, - sortKeyInfo, - limit, - ); - ctx.setResource(ResolverResourceIDs.ResolverResourceID(parentTypeName, fieldName), queryResolver); - - this.extendTypeWithConnection(ctx, parent, field, relatedType, sortKeyInfo); - - // Update the create & update input objects for the related type - const createInputName = ModelResourceIDs.ModelCreateInputObjectName(relatedTypeName); - const createInput = ctx.getType(createInputName) as InputObjectTypeDefinitionNode; - if (createInput) { - const updated = updateInputWithConnectionField(createInput, connectionAttributeName); - ctx.putType(updated); - } - const updateInputName = ModelResourceIDs.ModelUpdateInputObjectName(relatedTypeName); - const updateInput = ctx.getType(updateInputName) as InputObjectTypeDefinitionNode; - if (updateInput) { - const updated = updateInputWithConnectionField(updateInput, connectionAttributeName); - ctx.putType(updated); - } - } else { - // 5. {} to ? - // Store foreign key on this table and wire up a GetItem resolver. - // This has no inverse and has limited knowlege of the connection. - const primaryKeyField = this.getPrimaryKeyField(ctx, relatedType); - const idFieldName = primaryKeyField ? primaryKeyField.name.value : 'id'; - - if (!connectionAttributeName) { - connectionAttributeName = makeConnectionAttributeName(parentTypeName, fieldName); - } - - // Issue #2100 - in a 1:1 mapping that's based on sortField, we need to validate both sides - // and getItemResolver has to be aware of the soft field. - let sortFieldInfo; - const sortFieldName = getDirectiveArgument(directive, 'sortField'); - if (sortFieldName) { - // Related type has to have a primary key directive and has to have a soft key - // defined - const relatedSortField = this.getSortField(relatedType); - - if (!relatedSortField) { - throw new InvalidDirectiveError( - `sortField "${sortFieldName}" requires a primary @key on type "${relatedTypeName}" with a sort key that was not found.`, - ); - } - - const sortField = parent.fields.find((f) => f.name.value === sortFieldName); - - if (!sortField) { - throw new InvalidDirectiveError(`sortField with name "${sortFieldName} cannot be found on type: ${parent.name.value}`); - } - - const relatedSortFieldType = getBaseType(relatedSortField.type); - const sortFieldType = getBaseType(sortField.type); - - if (relatedSortFieldType !== sortFieldType) { - throw new InvalidDirectiveError( - `sortField "${relatedSortField.name.value}" on type "${relatedTypeName}" is not matching the ` + - `type of field "${sortFieldName}" on type "${parentTypeName}"`, - ); - } - - let sortFieldIsStringLike = true; - - // We cannot use $util.defaultIfNullOrBlank on non-string types - if ( - sortFieldType === STANDARD_SCALARS.Int || - sortFieldType === STANDARD_SCALARS.Float || - sortFieldType === STANDARD_SCALARS.Bolean - ) { - sortFieldIsStringLike = false; - } - - sortFieldInfo = { - primarySortFieldName: relatedSortField.name.value, - sortFieldName, - sortFieldIsStringLike, - }; - } - - // Validate the provided key field is legit. - const existingKeyField = parent.fields.find((f) => f.name.value === connectionAttributeName); - validateKeyField(existingKeyField); - - const getResolver = this.resources.makeGetItemConnectionResolver( - parentTypeName, - fieldName, - relatedTypeName, - connectionAttributeName, - idFieldName, - sortFieldInfo, - ); - ctx.setResource(ResolverResourceIDs.ResolverResourceID(parentTypeName, fieldName), getResolver); - - // Update the create & update input objects for this type - const createInputName = ModelResourceIDs.ModelCreateInputObjectName(parentTypeName); - const createInput = ctx.getType(createInputName) as InputObjectTypeDefinitionNode; - if (createInput) { - const updated = updateInputWithConnectionField(createInput, connectionAttributeName, leftConnectionIsNonNull); - ctx.putType(updated); - } - const updateInputName = ModelResourceIDs.ModelUpdateInputObjectName(parentTypeName); - const updateInput = ctx.getType(updateInputName) as InputObjectTypeDefinitionNode; - if (updateInput) { - const updated = updateInputWithConnectionField(updateInput, connectionAttributeName); - ctx.putType(updated); - } - } - }; - - /** - * The @connection parameterization with "fields" can be used to connect objects by running a query on a table. - * The directive is given an index to query and a list of fields to query by such that it - * returns a list objects (or in certain cases a single object) that are connected to the - * object it is called on. - * This directive is designed to leverage indices configured using @key to create relationships. - * - * Directive Definition: - * @connection(keyName: String, fields: [String!]!) on FIELD_DEFINITION - * param @keyName The name of the index configured using @key that should be queried to get - * connected objects - * param @fields The names of the fields on the current object to query by. - */ - public connectionWithKey = ( - parent: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, - field: FieldDefinitionNode, - directive: DirectiveNode, - ctx: TransformerContext, - ): void => { - const parentTypeName = parent.name.value; - const fieldName = field.name.value; - const args: RelationArguments = getDirectiveArguments(directive); - - // Ensure that there is at least one field provided. - if (args.fields.length === 0) { - throw new InvalidDirectiveError('No fields passed in to @connection directive.'); - } - - // Check that related type exists and that the connected object is annotated with @model. - const relatedTypeName = getBaseType(field.type); - const relatedType = ctx.inputDocument.definitions.find( - (d) => d.kind === Kind.OBJECT_TYPE_DEFINITION && d.name.value === relatedTypeName, - ) as ObjectTypeDefinitionNode | undefined; - - // Get Child object's table. - const tableLogicalID = ModelResourceIDs.ModelTableResourceID(relatedType.name.value); - const tableResource = ctx.getResource(tableLogicalID) as Table; - - // Check that each field provided exists in the parent model and that it is a valid key type (single non-null). - let inputFields: FieldDefinitionNode[] = []; - args.fields.forEach((item) => { - const fieldsArrayLength = inputFields.length; - inputFields.push(parent.fields.find((f) => f.name.value === item)); - if (!inputFields[fieldsArrayLength]) { - throw new InvalidDirectiveError(`${item} is not a field in ${parentTypeName}`); - } - - validateKeyFieldConnectionWithKey(inputFields[fieldsArrayLength], ctx); - }); - - let index: GlobalSecondaryIndex = undefined; - // If no index is provided use the default index for the related model type and - // check that the query fields match the PK/SK of the table. Else confirm that index exists. - if (!args.keyName) { - checkFieldsAgainstIndex(parent, relatedType, args.fields, tableResource.Properties.KeySchema, field); - } else { - index = - (tableResource.Properties.GlobalSecondaryIndexes - ? (tableResource.Properties.GlobalSecondaryIndexes).find((GSI) => GSI.IndexName === args.keyName) - : null) || - (tableResource.Properties.LocalSecondaryIndexes - ? (tableResource.Properties.LocalSecondaryIndexes).find((LSI) => LSI.IndexName === args.keyName) - : null); - if (!index) { - throw new InvalidDirectiveError(`Key ${args.keyName} does not exist for model ${relatedTypeName}`); - } - - // check the arity - - // Confirm that types of query fields match types of PK/SK of the index being queried. - checkFieldsAgainstIndex(parent, relatedType, args.fields, index.KeySchema, field); - } - - // If the related type is not a list, the index has to be the default index and the fields provided must match the PK/SK of the index. - if (!isListType(field.type)) { - if (args.keyName) { - // tslint:disable-next-line: max-line-length - throw new InvalidDirectiveError( - `Connection is to a single object but the keyName ${args.keyName} was provided which does not reference the default table.`, - ); - } - - // Start with GetItem resolver for case where the connection is to a single object. - const getResolver = this.resources.makeGetItemConnectionWithKeyResolver( - parentTypeName, - fieldName, - relatedTypeName, - args.fields, - tableResource.Properties.KeySchema, - ); - - ctx.setResource(ResolverResourceIDs.ResolverResourceID(parentTypeName, fieldName), getResolver); - } else { - const keySchema: KeySchema[] = index ? index.KeySchema : tableResource.Properties.KeySchema; - - const queryResolver = this.resources.makeQueryConnectionWithKeyResolver( - parentTypeName, - fieldName, - relatedType, - args.fields, - keySchema, - index ? String(index.IndexName) : undefined, - args.limit, - ); - - ctx.setResource(ResolverResourceIDs.ResolverResourceID(parentTypeName, fieldName), queryResolver); - - let sortKeyInfo: { fieldName: string; typeName: SortKeyFieldInfoTypeName; model: string; keyName: string } = undefined; - if (args.fields.length > 1) { - sortKeyInfo = undefined; - } else { - const compositeSortKeyType: SortKeyFieldInfoTypeName = 'Composite'; - const compositeSortKeyName = keySchema[1] ? this.resources.makeCompositeSortKeyName(String(keySchema[1].AttributeName)) : undefined; - const sortKeyField = keySchema[1] ? relatedType.fields.find((f) => f.name.value === keySchema[1].AttributeName) : undefined; - - // If a sort key field is found then add a simple sort key, else add a composite sort key. - if (sortKeyField) { - sortKeyInfo = keySchema[1] - ? { - fieldName: String(keySchema[1].AttributeName), - typeName: getBaseType(sortKeyField.type), - model: relatedTypeName, - keyName: index ? String(index.IndexName) : 'Primary', - } - : undefined; - } else { - sortKeyInfo = keySchema[1] - ? { - fieldName: compositeSortKeyName, - typeName: compositeSortKeyType, - model: relatedTypeName, - keyName: index ? String(index.IndexName) : 'Primary', - } - : undefined; - } - } - - this.extendTypeWithConnection(ctx, parent, field, relatedType, sortKeyInfo); - } - }; - - private typeExist(type: string, ctx: TransformerContext): boolean { - return Boolean(type in ctx.nodeMap); - } - - private generateModelXConnectionType(ctx: TransformerContext, typeDef: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode): void { - const tableXConnectionName = ModelResourceIDs.ModelConnectionTypeName(typeDef.name.value); - if (this.typeExist(tableXConnectionName, ctx)) { - return; - } - - // Create the ModelXConnection - const connectionType = blankObject(tableXConnectionName); - ctx.addObject(connectionType); - - ctx.addObjectExtension(makeModelConnectionType(typeDef.name.value)); - } - - private generateFilterAndKeyConditionInputs( - ctx: TransformerContext, - field: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, - sortKeyInfo?: { fieldName: string; typeName: SortKeyFieldInfoTypeName }, - ): void { - const scalarFilters = makeScalarFilterInputs(this.supportsConditions(ctx)); - for (const filter of scalarFilters) { - if (!this.typeExist(filter.name.value, ctx)) { - ctx.addInput(filter); - } - } - - // Create the Enum filters - const enumFilters = makeEnumFilterInputObjects(field, ctx, this.supportsConditions(ctx)); - for (const filter of enumFilters) { - if (!this.typeExist(filter.name.value, ctx)) { - ctx.addInput(filter); - } - } - - // Create the ModelXFilterInput - const tableXQueryFilterInput = makeModelXFilterInputObject(field, ctx, this.supportsConditions(ctx)); - if (!this.typeExist(tableXQueryFilterInput.name.value, ctx)) { - ctx.addInput(tableXQueryFilterInput); - } - - if (this.supportsConditions(ctx)) { - const attributeTypeEnum = makeAttributeTypeEnum(); - if (!this.typeExist(attributeTypeEnum.name.value, ctx)) { - ctx.addType(attributeTypeEnum); - } - } - - // Create sort key condition inputs for valid sort key types - // We only create the KeyConditionInput if it is being used. - // Don't create a key condition input for composite sort keys since it already done by @key. - if (sortKeyInfo && sortKeyInfo.typeName !== 'Composite') { - const sortKeyConditionInput = makeScalarKeyConditionForType(makeNamedType(sortKeyInfo.typeName)); - if (!this.typeExist(sortKeyConditionInput.name.value, ctx)) { - ctx.addInput(sortKeyConditionInput); - } - } - } - - private supportsConditions(context: TransformerContext) { - return context.getTransformerVersion() >= CONDITIONS_MINIMUM_VERSION; - } - - private extendTypeWithConnection( - ctx: TransformerContext, - parent: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, - field: FieldDefinitionNode, - returnType: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, - sortKeyInfo?: { fieldName: string; typeName: SortKeyFieldInfoTypeName; model?: string; keyName?: string }, - ) { - this.generateModelXConnectionType(ctx, returnType); - - // Extensions are not allowed to redeclare fields so we must replace - // it in place. - const type = ctx.getType(parent.name.value) as ObjectTypeDefinitionNode; - if (type && (type.kind === Kind.OBJECT_TYPE_DEFINITION || type.kind === Kind.INTERFACE_TYPE_DEFINITION)) { - // Find the field and replace it in place. - const newFields = type.fields.map((f: FieldDefinitionNode) => { - if (f.name.value === field.name.value) { - const updated = makeModelConnectionField(field.name.value, returnType.name.value, sortKeyInfo, [...f.directives]); - return updated; - } - return f; - }); - const updatedType = { - ...type, - fields: newFields, - }; - ctx.putType(updatedType); - - if (!this.typeExist('ModelSortDirection', ctx)) { - const modelSortDirection = makeModelSortDirectionEnumObject(); - ctx.addEnum(modelSortDirection); - } - - this.generateFilterAndKeyConditionInputs(ctx, returnType, sortKeyInfo); - } else { - throw new InvalidDirectiveError(`Could not find a object or interface type named ${parent.name.value}.`); - } - } - - private getPrimaryKeyField(ctx: TransformerContext, type: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode): FieldDefinitionNode { - let field: FieldDefinitionNode; - - for (const keyDirective of type.directives.filter((d) => d.name.value === 'key')) { - if (getDirectiveArgument(keyDirective, 'name') === undefined) { - const fieldsArg = getDirectiveArgument(keyDirective, 'fields'); - - if (fieldsArg && fieldsArg.length && fieldsArg.length >= 1 && fieldsArg.length <= 2) { - field = type.fields.find((f) => f.name.value === fieldsArg[0]); - } - - // Exit the loop even if field was not set above, @key will throw validation - // error anyway - break; - } - } - - return field; - } - - private getSortField(type: ObjectTypeDefinitionNode) { - let field: FieldDefinitionNode; - - for (const keyDirective of type.directives.filter((d) => d.name.value === 'key')) { - if (getDirectiveArgument(keyDirective, 'name') === undefined) { - const fieldsArg = getDirectiveArgument(keyDirective, 'fields'); - - if (fieldsArg && fieldsArg.length && fieldsArg.length === 2) { - field = type.fields.find((f) => f.name.value === fieldsArg[1]); - } - - // Exit the loop even if field was not set above, @key will throw validation - // error anyway - break; - } - } - - return field; - } -} diff --git a/packages/graphql-connection-transformer/src/__tests__/ModelConnectionTransformer.test.ts b/packages/graphql-connection-transformer/src/__tests__/ModelConnectionTransformer.test.ts deleted file mode 100644 index 998f935b5b..0000000000 --- a/packages/graphql-connection-transformer/src/__tests__/ModelConnectionTransformer.test.ts +++ /dev/null @@ -1,775 +0,0 @@ -import { - ObjectTypeDefinitionNode, - parse, - FieldDefinitionNode, - DocumentNode, - DefinitionNode, - Kind, - InputObjectTypeDefinitionNode, - InputValueDefinitionNode, -} from 'graphql'; -import { GraphQLTransform, TRANSFORM_CURRENT_VERSION } from 'graphql-transformer-core'; -import { ResolverResourceIDs, ModelResourceIDs, ResourceConstants } from 'graphql-transformer-common'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelConnectionTransformer } from '../ModelConnectionTransformer'; - -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -test('ModelConnectionTransformer simple one to many happy case', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection - } - type Comment @model { - id: ID! - content: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Post', 'comments')]).toBeTruthy(); - const schemaDoc = parse(out.schema); - - // Post.comments field - const postType = getObjectType(schemaDoc, 'Post'); - expectFields(postType, ['comments']); - const commentField = postType.fields.find((f) => f.name.value === 'comments'); - expect(commentField.arguments.length).toEqual(4); - expectArguments(commentField, ['filter', 'limit', 'nextToken', 'sortDirection']); - expect(commentField.type.kind).toEqual(Kind.NAMED_TYPE); - expect((commentField.type as any).name.value).toEqual('ModelCommentConnection'); - - // Check the Comment.commentPostId - // Check the Comment.commentPostId inputs - const commentCreateInput = getInputType(schemaDoc, ModelResourceIDs.ModelCreateInputObjectName('Comment')); - const connectionId = commentCreateInput.fields.find((f) => f.name.value === 'postCommentsId'); - expect(connectionId).toBeTruthy(); - - const commentUpdateInput = getInputType(schemaDoc, ModelResourceIDs.ModelUpdateInputObjectName('Comment')); - const connectionUpdateId = commentUpdateInput.fields.find((f) => f.name.value === 'postCommentsId'); - expect(connectionUpdateId).toBeTruthy(); -}); - -test('ModelConnectionTransformer simple one to many happy case with custom keyField and implicit connection name', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection(keyField: "postId") - } - type Comment @model { - id: ID! - content: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Post', 'comments')]).toBeTruthy(); - const schemaDoc = parse(out.schema); - - // Post.comments field - const postType = getObjectType(schemaDoc, 'Post'); - expectFields(postType, ['comments']); - const commentField = postType.fields.find((f) => f.name.value === 'comments'); - expect(commentField.arguments.length).toEqual(4); - expectArguments(commentField, ['filter', 'limit', 'nextToken', 'sortDirection']); - expect(commentField.type.kind).toEqual(Kind.NAMED_TYPE); - expect((commentField.type as any).name.value).toEqual('ModelCommentConnection'); - - // Check the Comment.commentPostId - // Check the Comment.commentPostId inputs - const commentCreateInput = getInputType(schemaDoc, ModelResourceIDs.ModelCreateInputObjectName('Comment')); - const connectionId = commentCreateInput.fields.find((f) => f.name.value === 'postId'); - expect(connectionId).toBeTruthy(); - - const commentUpdateInput = getInputType(schemaDoc, ModelResourceIDs.ModelUpdateInputObjectName('Comment')); - const connectionUpdateId = commentUpdateInput.fields.find((f) => f.name.value === 'postId'); - expect(connectionUpdateId).toBeTruthy(); -}); - -test('that ModelConnection Transformer throws error when the field in connection is not found in the related Type', () => { - const invalidSchema = ` - type Post @model { - name: String! - teamID: ID! - team: Team @connection(fields: ["teamID"]) - } - - type Team @model { - name: [String!]! - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - try { - transformer.transform(invalidSchema); - expect(true).toEqual(false); - } catch (e) { - console.log(e); - expect(e).toBeTruthy(); - expect(e.name).toEqual('InvalidDirectiveError'); - } -}); - -test('ModelConnectionTransformer simple one to many happy case with custom keyField and explicit connection name', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - createdAt: String - updatedAt: String - comments: [Comment] @connection(name: "PostComments", keyField: "postId") - } - type Comment @model { - id: ID! - content: String! - post: Post! @connection(name: "PostComments", keyField: "postId") - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Post', 'comments')]).toBeTruthy(); - const schemaDoc = parse(out.schema); - - // Post.comments field - const postType = getObjectType(schemaDoc, 'Post'); - expectFields(postType, ['comments']); - const commentField = postType.fields.find((f) => f.name.value === 'comments'); - expect(commentField.arguments.length).toEqual(4); - expectArguments(commentField, ['filter', 'limit', 'nextToken', 'sortDirection']); - expect(commentField.type.kind).toEqual(Kind.NAMED_TYPE); - expect((commentField.type as any).name.value).toEqual('ModelCommentConnection'); - - // Check the Comment.commentPostId - // Check the Comment.commentPostId inputs - const commentCreateInput = getInputType(schemaDoc, ModelResourceIDs.ModelCreateInputObjectName('Comment')); - const connectionId = commentCreateInput.fields.find((f) => f.name.value === 'postId'); - expect(connectionId).toBeTruthy(); - expect(connectionId.type.kind).toEqual(Kind.NON_NULL_TYPE); - - const commentUpdateInput = getInputType(schemaDoc, ModelResourceIDs.ModelUpdateInputObjectName('Comment')); - const connectionUpdateId = commentUpdateInput.fields.find((f) => f.name.value === 'postId'); - expect(connectionUpdateId).toBeTruthy(); - expect(connectionUpdateId.type.kind).toEqual(Kind.NAMED_TYPE); -}); - -test('ModelConnectionTransformer complex one to many happy case', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection(name: "PostComments") - } - type Comment @model { - id: ID! - content: String - post: Post @connection(name: "PostComments") - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Post', 'comments')]).toBeTruthy(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'post')]).toBeTruthy(); - const schemaDoc = parse(out.schema); - const postType = getObjectType(schemaDoc, 'Post'); - const commentType = getObjectType(schemaDoc, 'Comment'); - - // Check Post.comments field - expectFields(postType, ['comments']); - const commentField = postType.fields.find((f) => f.name.value === 'comments'); - expect(commentField.arguments.length).toEqual(4); - expectArguments(commentField, ['filter', 'limit', 'nextToken', 'sortDirection']); - expect(commentField.type.kind).toEqual(Kind.NAMED_TYPE); - expect((commentField.type as any).name.value).toEqual('ModelCommentConnection'); - - // Check the Comment.commentPostId inputs - const commentCreateInput = getInputType(schemaDoc, ModelResourceIDs.ModelCreateInputObjectName('Comment')); - const connectionId = commentCreateInput.fields.find((f) => f.name.value === 'commentPostId'); - expect(connectionId).toBeTruthy(); - - const commentUpdateInput = getInputType(schemaDoc, ModelResourceIDs.ModelUpdateInputObjectName('Comment')); - const connectionUpdateId = commentUpdateInput.fields.find((f) => f.name.value === 'commentPostId'); - expect(connectionUpdateId).toBeTruthy(); - - // Check Comment.post field - const postField = commentType.fields.find((f) => f.name.value === 'post'); - expect(postField.arguments.length).toEqual(0); - expect(postField.type.kind).toEqual(Kind.NAMED_TYPE); - expect((postField.type as any).name.value).toEqual('Post'); -}); - -test('ModelConnectionTransformer many to many should fail', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection(name: "ManyToMany") - } - type Comment @model { - id: ID! - content: String - posts: [Post] @connection(name: "ManyToMany") - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - try { - transformer.transform(validSchema); - expect(true).toEqual(false); - } catch (e) { - // Should throw bc we don't let support many to many - expect(e).toBeTruthy(); - expect(e.name).toEqual('InvalidDirectiveError'); - } -}); - -test('ModelConnectionTransformer many to many should fail due to missing other "name"', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection(name: "ManyToMany") - } - type Comment @model { - id: ID! - content: String - - # This is meant to be the other half of "ManyToMany" but I forgot. - posts: [Post] @connection - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - try { - transformer.transform(validSchema); - expect(true).toEqual(false); - } catch (e) { - // Should throw bc we check both halves when name is given - expect(e).toBeTruthy(); - expect(e.name).toEqual('InvalidDirectiveError'); - } -}); - -test('ModelConnectionTransformer many to many should fail due to missing other connection', () => { - const validSchema = ` - type Post @model { - id: ID! - things: [Thing!] @connection - } - - type Thing @model(queries: null, mutations: null) { - id: ID! - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Post', 'things')]).toBeTruthy(); - const schemaDoc = parse(out.schema); - const postType = getObjectType(schemaDoc, 'Post'); - const postConnection = getObjectType(schemaDoc, 'ModelPostConnection'); - const thingConnection = getObjectType(schemaDoc, 'ModelThingConnection'); - const thingFilterInput = getInputType(schemaDoc, 'ModelThingFilterInput'); - expect(thingFilterInput).toBeDefined(); - expect(postType).toBeDefined(); - expect(thingConnection).toBeDefined(); - expect(postConnection).toBeDefined(); -}); - -test('ModelConnectionTransformer with non null @connections', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - createdAt: String - updatedAt: String - comments: [Comment] @connection(name: "PostComments", keyField: "postId") - - # A non null on the one in a 1-M does enforce a non-null - # on the CreatePostInput - singleComment: Comment! @connection - - # A non null on the many in a 1-M does not enforce a non-null - # in the CommentCreateInput because it is not explicitly implied. - manyComments: [Comment]! @connection - } - type Comment @model { - id: ID! - content: String! - - # A non-null on the one in 1-M again enforces a non null. - post: Post! @connection(name: "PostComments", keyField: "postId") - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Post', 'comments')]).toBeTruthy(); - const schemaDoc = parse(out.schema); - - // Post.comments field - const postType = getObjectType(schemaDoc, 'Post'); - expectFields(postType, ['comments']); - const commentField = postType.fields.find((f) => f.name.value === 'comments'); - expect(commentField.arguments.length).toEqual(4); - expectArguments(commentField, ['filter', 'limit', 'nextToken', 'sortDirection']); - expect(commentField.type.kind).toEqual(Kind.NAMED_TYPE); - expect((commentField.type as any).name.value).toEqual('ModelCommentConnection'); - - // Check the Comment.commentPostId - // Check the Comment.commentPostId inputs - const commentCreateInput = getInputType(schemaDoc, ModelResourceIDs.ModelCreateInputObjectName('Comment')); - const connectionId = commentCreateInput.fields.find((f) => f.name.value === 'postId'); - expect(connectionId).toBeTruthy(); - expect(connectionId.type.kind).toEqual(Kind.NON_NULL_TYPE); - - const manyCommentId = commentCreateInput.fields.find((f) => f.name.value === 'postManyCommentsId'); - expect(manyCommentId).toBeTruthy(); - expect(manyCommentId.type.kind).toEqual(Kind.NAMED_TYPE); - - const commentUpdateInput = getInputType(schemaDoc, ModelResourceIDs.ModelUpdateInputObjectName('Comment')); - const connectionUpdateId = commentUpdateInput.fields.find((f) => f.name.value === 'postId'); - expect(connectionUpdateId).toBeTruthy(); - expect(connectionUpdateId.type.kind).toEqual(Kind.NAMED_TYPE); - - // Check the post create type - const postCreateInput = getInputType(schemaDoc, ModelResourceIDs.ModelCreateInputObjectName('Post')); - const postConnectionId = postCreateInput.fields.find((f) => f.name.value === 'postSingleCommentId'); - expect(postConnectionId).toBeTruthy(); - expect(postConnectionId.type.kind).toEqual(Kind.NON_NULL_TYPE); -}); - -test('ModelConnectionTransformer with sortField fails if not specified in associated type', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection(name: "PostComments", sortField: "createdAt") - } - type Comment @model { - id: ID! - content: String - post: Post @connection(name: "PostComments") - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - expect(() => { - transformer.transform(validSchema); - }).toThrowError(); -}); - -test('ModelConnectionTransformer with sortField creates a connection resolver with a sort key condition.', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection(name: "PostComments", sortField: "createdAt") - } - type Comment @model { - id: ID! - content: String - post: Post @connection(name: "PostComments", sortField: "createdAt") - createdAt: AWSDateTime - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Post', 'comments')]).toBeTruthy(); - const schemaDoc = parse(out.schema); - - // Post.comments field - const postType = getObjectType(schemaDoc, 'Post'); - expectFields(postType, ['comments']); - const commentField = postType.fields.find((f) => f.name.value === 'comments'); - expect(commentField.arguments.length).toEqual(5); - expectArguments(commentField, ['createdAt', 'filter', 'limit', 'nextToken', 'sortDirection']); -}); - -test('ModelConnectionTransformer throws with invalid key fields', () => { - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - const invalidSchema = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection(keyField: "postId") - } - type Comment @model { - id: ID! - content: String - - # Key fields must be String or ID. - postId: [String] - } - `; - expect(() => transformer.transform(invalidSchema)).toThrow(); - - const invalidSchema2 = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection(name: "PostComments", keyField: "postId") - } - type Comment @model { - id: ID! - content: String - - # Key fields must be String or ID. - postId: [String] - - post: Post @connection(name: "PostComments", keyField: "postId") - } - `; - expect(() => transformer.transform(invalidSchema2)).toThrow(); - - const invalidSchema3 = ` - type Post @model { - id: ID! - title: String! - } - type Comment @model { - id: ID! - content: String - - # Key fields must be String or ID. - postId: [String] - - post: Post @connection(keyField: "postId") - } - `; - expect(() => transformer.transform(invalidSchema3)).toThrow(); -}); - -test('ModelConnectionTransformer does not throw with valid key fields', () => { - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - const validSchema = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection(keyField: "postId") - } - type Comment @model { - id: ID! - content: String - - # Key fields must be String or ID. - postId: String - } - `; - expect(() => transformer.transform(validSchema)).toBeTruthy(); - - const validSchema2 = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection(name: "PostComments", keyField: "postId") - } - type Comment @model { - id: ID! - content: String - - # Key fields must be String or ID. - postId: ID - - post: Post @connection(name: "PostComments", keyField: "postId") - } - `; - expect(() => transformer.transform(validSchema2)).toBeTruthy(); - - const validSchema3 = ` - type Post @model { - id: ID! - title: String! - } - type Comment @model { - id: ID! - content: String - - # Key fields must be String or ID. - postId: String - - post: Post @connection(keyField: "postId") - } - `; - expect(() => transformer.transform(validSchema3)).toBeTruthy(); -}); - -test('ModelConnectionTransformer sortField with missing @key should fail', () => { - const validSchema = ` - type Model1 @model(subscriptions: null) - { - id: ID! - sort: Int! - name: String! - } - type Model2 @model(subscriptions: null) - { - id: ID! - connection: Model1 @connection(sortField: "modelOneSort") - modelOneSort: Int! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - try { - transformer.transform(validSchema); - expect(true).toEqual(false); - } catch (e) { - expect(e).toBeTruthy(); - expect(e.name).toEqual('InvalidDirectiveError'); - } -}); - -test('ModelConnectionTransformer overrides the default limit', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection(limit: 50) - } - type Comment @model { - id: ID! - content: String - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Post', 'comments')]).toBeTruthy(); - - // Post.comments field - expect(out.resolvers['Post.comments.req.vtl']).toContain('#set( $limit = $util.defaultIfNull($context.args.limit, 50) )'); -}); - -test('ModelConnectionTransformer uses the default limit', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection - } - type Comment @model { - id: ID! - content: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Post', 'comments')]).toBeTruthy(); - - // Post.comments field - expect(out.resolvers['Post.comments.req.vtl']).toContain( - `#set( $limit = $util.defaultIfNull($context.args.limit, ${ResourceConstants.DEFAULT_PAGE_LIMIT}) )`, - ); -}); - -test('ModelConnectionTransformer with keyField overrides the default limit', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection(limit: 50, fields: ["id"]) - } - type Comment @model { - id: ID! - content: String - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Post', 'comments')]).toBeTruthy(); - - // Post.comments field - expect(out.resolvers['Post.comments.req.vtl']).toContain('#set( $limit = $util.defaultIfNull($context.args.limit, 50) )'); -}); - -test('ModelConnectionTransformer with keyField uses the default limit', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - comments: [Comment] @connection(fields: ["id"]) - } - type Comment @model { - id: ID! - content: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Post', 'comments')]).toBeTruthy(); - - // Post.comments field - expect(out.resolvers['Post.comments.req.vtl']).toContain( - `#set( $limit = $util.defaultIfNull($context.args.limit, ${ResourceConstants.DEFAULT_PAGE_LIMIT}) )`, - ); -}); - -test('Connection on models with no codegen includes AttributeTypeEnum', () => { - const validSchema = ` - type Post @model(queries: null, mutations: null, subscriptions: null) { - id: ID! - title: String! - comments: [Comment] @connection - } - type Comment @model(queries: null, mutations: null, subscriptions: null) { - id: ID! - content: String - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - transformConfig: { - Version: TRANSFORM_CURRENT_VERSION, - }, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - expect(out.schema).toMatchSnapshot(); -}); - -test('Connection on models with no codegen includes custom enum filters', () => { - const validSchema = ` - type Cart @model(queries: null, mutations: null, subscriptions: null) { - id: ID!, - cartItems: [CartItem] @connection(name: "CartCartItem") - } - - type CartItem @model(queries: null, mutations: null, subscriptions: null) { - id: ID! - productType: PRODUCT_TYPE! - cart: Cart @connection(name: "CartCartItem") - } - - enum PRODUCT_TYPE { - UNIT - PACKAGE - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - transformConfig: { - Version: TRANSFORM_CURRENT_VERSION, - }, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.schema).toMatchSnapshot(); -}); - -function expectFields(type: ObjectTypeDefinitionNode, fields: string[]) { - for (const fieldName of fields) { - const foundField = type.fields.find((f: FieldDefinitionNode) => f.name.value === fieldName); - expect(foundField).toBeDefined(); - } -} - -function expectArguments(field: FieldDefinitionNode, args: string[]) { - for (const argName of args) { - const foundArg = field.arguments.find((a: InputValueDefinitionNode) => a.name.value === argName); - expect(foundArg).toBeDefined(); - } -} - -function doNotExpectFields(type: ObjectTypeDefinitionNode, fields: string[]) { - for (const fieldName of fields) { - expect(type.fields.find((f: FieldDefinitionNode) => f.name.value === fieldName)).toBeUndefined(); - } -} - -function getObjectType(doc: DocumentNode, type: string): ObjectTypeDefinitionNode | undefined { - return doc.definitions.find((def: DefinitionNode) => def.kind === Kind.OBJECT_TYPE_DEFINITION && def.name.value === type) as - | ObjectTypeDefinitionNode - | undefined; -} - -function getInputType(doc: DocumentNode, type: string): InputObjectTypeDefinitionNode | undefined { - return doc.definitions.find((def: DefinitionNode) => def.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION && def.name.value === type) as - | InputObjectTypeDefinitionNode - | undefined; -} - -function verifyInputCount(doc: DocumentNode, type: string, count: number): boolean { - return doc.definitions.filter((def) => def.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION && def.name.value === type).length === count; -} diff --git a/packages/graphql-connection-transformer/src/__tests__/NewConnectionTransformer.test.ts b/packages/graphql-connection-transformer/src/__tests__/NewConnectionTransformer.test.ts deleted file mode 100644 index 92fb5ba275..0000000000 --- a/packages/graphql-connection-transformer/src/__tests__/NewConnectionTransformer.test.ts +++ /dev/null @@ -1,695 +0,0 @@ -import { - ObjectTypeDefinitionNode, - parse, - FieldDefinitionNode, - DocumentNode, - DefinitionNode, - Kind, - InputObjectTypeDefinitionNode, - InputValueDefinitionNode, -} from 'graphql'; -import { GraphQLTransform, ConflictHandlerType, TRANSFORM_CURRENT_VERSION } from 'graphql-transformer-core'; -import { ResolverResourceIDs } from 'graphql-transformer-common'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { KeyTransformer } from 'graphql-key-transformer'; -import { ModelConnectionTransformer } from '../ModelConnectionTransformer'; - -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -test('ModelConnectionTransformer should fail if connection was called on an object that is not a Model type.', () => { - const validSchema = ` - type Test { - id: ID! - email: String! - testObj: Test1 @connection(fields: ["email"]) - } - - type Test1 @model { - id: ID! - name: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(validSchema)).toThrowError(`@connection must be on an @model object type field.`); -}); - -test('ModelConnectionTransformer should fail if connection was with an object that is not a Model type.', () => { - const validSchema = ` - type Test @model { - id: ID! - email: String! - testObj: Test1 @connection(fields: ["email"]) - } - - type Test1 { - id: ID! - name: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(validSchema)).toThrowError(`Object type Test1 must be annotated with @model.`); -}); - -test('ModelConnectionTransformer should fail if the field type where the directive is called is incorrect.', () => { - const validSchema = ` - type Test @model { - id: ID! - email: String! - testObj: Test2 @connection(fields: ["email"]) - } - - type Test1 @model { - id: ID! - name: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(validSchema)).toThrowError('Unknown type "Test2". Did you mean "Test" or "Test1"?'); -}); - -test('ModelConnectionTransformer should fail if an empty list of fields is passed in.', () => { - const validSchema = ` - type Test @model { - id: ID! - email: String - testObj: Test1 @connection(fields: []) - } - - type Test1 @model { - id: ID! - name: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(validSchema)).toThrowError('No fields passed in to @connection directive.'); -}); - -test('ModelConnectionTransformer should fail if any of the fields passed in are not in the Parent model.', () => { - const validSchema = ` - type Test @model { - id: ID! - email: String - testObj: [Test1] @connection(fields: ["id", "name"]) - } - - type Test1 - @model - @key(fields: ["id", "name"]) - { - id: ID! - friendID: ID! - name: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(validSchema)).toThrowError('name is not a field in Test'); -}); - -test('ModelConnectionTransformer should fail if the query is not run on the default table when connection is trying to connect a single object.', () => { - const validSchema = ` - type Test @model { - id: ID! - email: String - testObj: Test1 @connection(keyName: "notDefault", fields: ["id"]) - } - - type Test1 - @model - @key(name: "notDefault", fields: ["friendID"]) - { - id: ID! - friendID: ID! - name: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(validSchema)).toThrowError( - 'Connection is to a single object but the keyName notDefault was provided which does not reference the default table.', - ); -}); - -test('ModelConnectionTransformer should fail if keyName provided does not exist.', () => { - const validSchema = ` - type Test @model { - id: ID! - email: String - testObj: [Test1] @connection(keyName: "notDefault", fields: ["id"]) - } - - type Test1 @model { - id: ID! - friendID: ID! - name: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(validSchema)).toThrowError('Key notDefault does not exist for model Test1'); -}); - -test('ModelConnectionTransformer should fail if first field does not match PK of table. (When using default table)', () => { - const validSchema = ` - type Test @model { - id: ID! - email: String! - testObj: Test1 @connection(fields: ["email"]) - } - - type Test1 @model { - id: ID! - friendID: ID! - name: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(validSchema)).toThrowError('email field is not of type ID'); -}); - -test('ModelConnectionTransformer should fail if sort key type passed in does not match default table sort key type.', () => { - const validSchema = ` - type Test @model { - id: ID! - email: String! - testObj: [Test1] @connection(fields: ["id", "email"]) - } - - type Test1 - @model - @key(fields: ["id", "friendID"]) - { - id: ID! - friendID: ID! - name: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(validSchema)).toThrowError('email field is not of type ID'); -}); - -test('ModelConnectionTransformer should fail if partial sort key is passed in connection.', () => { - const validSchema = ` - type Test @model { - id: ID! - email: String! - testObj: [Test1] @connection(keyName: "testIndex", fields: ["id", "email"]) - } - - type Test1 - @model - @key(name: "testIndex", fields: ["id", "friendID", "name"]) - { - id: ID! - friendID: ID! - name: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(validSchema)).toThrowError( - 'Invalid @connection directive testObj. fields does not accept partial sort key', - ); -}); - -test('ModelConnectionTransformer should accept connection without sort key', () => { - const validSchema = ` - type Test @model { - id: ID! - email: String! - testObj: [Test1] @connection(keyName: "testIndex", fields: ["id"]) - } - - type Test1 - @model - @key(name: "testIndex", fields: ["id", "friendID", "name"]) - { - id: ID! - friendID: ID! - name: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(validSchema)).not.toThrowError(); -}); - -test('ModelConnectionTransformer should fail if sort key type passed in does not match custom index sort key type.', () => { - const validSchema = ` - type Test @model { - id: ID! - email: String! - testObj: [Test1] @connection(keyName: "testIndex", fields: ["id", "email"]) - } - - type Test1 - @model - @key(name: "testIndex", fields: ["id", "friendID"]) - { - id: ID! - friendID: ID! - name: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(validSchema)).toThrowError('email field is not of type ID'); -}); - -test('ModelConnectionTransformer should fail if partition key type passed in does not match custom index partition key type.', () => { - const validSchema = ` - type Test @model { - id: ID! - email: String! - testObj: [Test1] @connection(keyName: "testIndex", fields: ["email", "id"]) - } - - type Test1 - @model - @key(name: "testIndex", fields: ["id", "friendID"]) - { - id: ID! - friendID: ID! - name: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(validSchema)).toThrowError('email field is not of type ID'); -}); - -test('ModelConnectionTransformer for One-to-One getItem case.', () => { - const validSchema = ` - type Test @model { - id: ID! - email: String! - otherHalf: Test1 @connection(fields: ["id", "email"]) - } - - type Test1 - @model - @key(fields: ["id", "email"]) - { - id: ID! - friendID: ID! - email: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Test', 'otherHalf')]).toBeTruthy(); - const schemaDoc = parse(out.schema); - - const testObjType = getObjectType(schemaDoc, 'Test'); - expectFields(testObjType, ['otherHalf']); - const relatedField = testObjType.fields.find((f) => f.name.value === 'otherHalf'); - expect(relatedField.type.kind).toEqual(Kind.NAMED_TYPE); -}); - -test('ModelConnectionTransformer for One-to-Many query case.', () => { - const validSchema = ` - type Test @model { - id: ID! - email: String! - otherParts: [Test1] @connection(fields: ["id", "email"]) - } - - type Test1 - @model - @key(fields: ["id", "email"]) - { - id: ID! - friendID: ID! - email: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Test', 'otherParts')]).toBeTruthy(); - const schemaDoc = parse(out.schema); - - const testObjType = getObjectType(schemaDoc, 'Test'); - expectFields(testObjType, ['otherParts']); - const relatedField = testObjType.fields.find((f) => f.name.value === 'otherParts'); - - expect(relatedField.arguments.length).toEqual(4); - expectArguments(relatedField, ['filter', 'limit', 'nextToken', 'sortDirection']); - expect(relatedField.type.kind).toEqual(Kind.NAMED_TYPE); - - expect((relatedField.type as any).name.value).toEqual('ModelTest1Connection'); -}); - -test('ModelConnectionTransformer for bidirectional One-to-Many query case.', () => { - const validSchema = ` - type Post - @model - @key(name: "byOwner", fields: ["owner", "id"]) - { - id: ID! - title: String! - author: User @connection(fields: ["owner"]) - owner: ID! - } - type User @model { - id: ID! - posts: [Post] @connection(keyName: "byOwner", fields: ["id"]) - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Post', 'author')]).toBeTruthy(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('User', 'posts')]).toBeTruthy(); - const schemaDoc = parse(out.schema); - - const userType = getObjectType(schemaDoc, 'User'); - expectFields(userType, ['posts']); - const postsField = userType.fields.find((f) => f.name.value === 'posts'); - - expect(postsField.arguments.length).toEqual(5); - expectArguments(postsField, ['id', 'filter', 'limit', 'nextToken', 'sortDirection']); - expect(postsField.type.kind).toEqual(Kind.NAMED_TYPE); - - expect((postsField.type as any).name.value).toEqual('ModelPostConnection'); - - const postType = getObjectType(schemaDoc, 'Post'); - expectFields(postType, ['author']); - const userField = postType.fields.find((f) => f.name.value === 'author'); - expect(userField.type.kind).toEqual(Kind.NAMED_TYPE); -}); - -test('ModelConnectionTransformer for One-to-Many query with a composite sort key.', () => { - const validSchema = ` - type Test @model { - id: ID! - email: String! - name: String! - otherParts: [Test1] @connection(fields: ["id", "email", "name"]) - } - - type Test1 - @model - @key(fields: ["id", "email", "name"]) - { - id: ID! - friendID: ID! - email: String! - name: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Test', 'otherParts')]).toBeTruthy(); - const schemaDoc = parse(out.schema); - - const testObjType = getObjectType(schemaDoc, 'Test'); - expectFields(testObjType, ['otherParts']); - const relatedField = testObjType.fields.find((f) => f.name.value === 'otherParts'); - - expect(relatedField.arguments.length).toEqual(4); - expectArguments(relatedField, ['filter', 'limit', 'nextToken', 'sortDirection']); - expect(relatedField.type.kind).toEqual(Kind.NAMED_TYPE); - - expect((relatedField.type as any).name.value).toEqual('ModelTest1Connection'); -}); -test('ModelConnectionTransformer for One-to-Many query with a composite sort key passed in as an argument.', () => { - const validSchema = ` - type Test @model { - id: ID! - email: String! - name: String! - otherParts: [Test1] @connection(fields: ["id"]) - } - - type Test1 - @model - @key(fields: ["id", "email", "name"]) - { - id: ID! - friendID: ID! - email: String! - name: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Test', 'otherParts')]).toBeTruthy(); - const schemaDoc = parse(out.schema); - - const testObjType = getObjectType(schemaDoc, 'Test'); - expectFields(testObjType, ['otherParts']); - const relatedField = testObjType.fields.find((f) => f.name.value === 'otherParts'); - - expect(relatedField.arguments.length).toEqual(5); - expectArguments(relatedField, ['emailName', 'filter', 'limit', 'nextToken', 'sortDirection']); - expect(relatedField.type.kind).toEqual(Kind.NAMED_TYPE); - - expect((relatedField.type as any).name.value).toEqual('ModelTest1Connection'); -}); - -test('ModelConnectionTransformer for One-to-One getItem with composite sort key.', () => { - const validSchema = ` - type Test @model { - id: ID! - email: String! - name: String! - otherHalf: Test1 @connection(fields: ["id", "email", "name"]) - } - - type Test1 - @model - @key(fields: ["id", "email", "name"]) - { - id: ID! - friendID: ID! - email: String! - name: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer(), new ModelConnectionTransformer()], - featureFlags, - }); - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.stacks.ConnectionStack.Resources[ResolverResourceIDs.ResolverResourceID('Test', 'otherHalf')]).toBeTruthy(); - const schemaDoc = parse(out.schema); - - const testObjType = getObjectType(schemaDoc, 'Test'); - expectFields(testObjType, ['otherHalf']); - const relatedField = testObjType.fields.find((f) => f.name.value === 'otherHalf'); - expect(relatedField.type.kind).toEqual(Kind.NAMED_TYPE); -}); - -test('Many-to-many without conflict resolution generates correct schema', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - editors: [PostEditor] @connection(keyName: "byPost", fields: ["id"]) - } - - # Create a join model and disable queries as you don't need them - # and can query through Post.editors and User.posts - type PostEditor - @model(queries: null) - @key(name: "byPost", fields: ["postID", "editorID"]) - @key(name: "byEditor", fields: ["editorID", "postID"]) { - id: ID! - postID: ID! - editorID: ID! - post: Post! @connection(fields: ["postID"]) - editor: User! @connection(fields: ["editorID"]) - } - - type User @model { - id: ID! - username: String! - posts: [PostEditor] @connection(keyName: "byEditor", fields: ["id"]) - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer(), new ModelConnectionTransformer()], - featureFlags, - transformConfig: { - Version: TRANSFORM_CURRENT_VERSION, - }, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - expect(out.schema).toMatchSnapshot(); -}); - -test('Many-to-many with conflict resolution generates correct schema', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - editors: [PostEditor] @connection(keyName: "byPost", fields: ["id"]) - } - - # Create a join model and disable queries as you don't need them - # and can query through Post.editors and User.posts - type PostEditor - @model(queries: null) - @key(name: "byPost", fields: ["postID", "editorID"]) - @key(name: "byEditor", fields: ["editorID", "postID"]) { - id: ID! - postID: ID! - editorID: ID! - post: Post! @connection(fields: ["postID"]) - editor: User! @connection(fields: ["editorID"]) - } - - type User @model { - id: ID! - username: String! - posts: [PostEditor] @connection(keyName: "byEditor", fields: ["id"]) - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer(), new ModelConnectionTransformer()], - featureFlags, - transformConfig: { - Version: TRANSFORM_CURRENT_VERSION, - ResolverConfig: { - project: { - ConflictHandler: ConflictHandlerType.AUTOMERGE, - ConflictDetection: 'VERSION', - }, - }, - }, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - expect(out.schema).toMatchSnapshot(); -}); - -function getInputType(doc: DocumentNode, type: string): InputObjectTypeDefinitionNode | undefined { - return doc.definitions.find((def: DefinitionNode) => def.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION && def.name.value === type) as - | InputObjectTypeDefinitionNode - | undefined; -} - -// Taken from ModelConnectionTransformer.test.ts -function getObjectType(doc: DocumentNode, type: string): ObjectTypeDefinitionNode | undefined { - return doc.definitions.find((def: DefinitionNode) => def.kind === Kind.OBJECT_TYPE_DEFINITION && def.name.value === type) as - | ObjectTypeDefinitionNode - | undefined; -} - -function expectFields(type: ObjectTypeDefinitionNode, fields: string[]) { - for (const fieldName of fields) { - const foundField = type.fields.find((f: FieldDefinitionNode) => f.name.value === fieldName); - expect(foundField).toBeDefined(); - } -} - -function expectArguments(field: FieldDefinitionNode, args: string[]) { - for (const argName of args) { - const foundArg = field.arguments.find((a: InputValueDefinitionNode) => a.name.value === argName); - expect(foundArg).toBeDefined(); - } -} diff --git a/packages/graphql-connection-transformer/src/__tests__/__snapshots__/ModelConnectionTransformer.test.ts.snap b/packages/graphql-connection-transformer/src/__tests__/__snapshots__/ModelConnectionTransformer.test.ts.snap deleted file mode 100644 index f7633cd623..0000000000 --- a/packages/graphql-connection-transformer/src/__tests__/__snapshots__/ModelConnectionTransformer.test.ts.snap +++ /dev/null @@ -1,255 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Connection on models with no codegen includes AttributeTypeEnum 1`] = ` -"type Post { - id: ID! - title: String! - comments(filter: ModelCommentFilterInput, sortDirection: ModelSortDirection, limit: Int, nextToken: String): ModelCommentConnection - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} - -type Comment { - id: ID! - content: String - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} - -type ModelCommentConnection { - items: [Comment]! - nextToken: String -} - -enum ModelSortDirection { - ASC - DESC -} - -input ModelStringInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String - attributeExists: Boolean - attributeType: ModelAttributeTypes - size: ModelSizeInput -} - -input ModelIDInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID - attributeExists: Boolean - attributeType: ModelAttributeTypes - size: ModelSizeInput -} - -input ModelIntInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelFloatInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelBooleanInput { - ne: Boolean - eq: Boolean - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelSizeInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelCommentFilterInput { - id: ModelIDInput - content: ModelStringInput - and: [ModelCommentFilterInput] - or: [ModelCommentFilterInput] - not: ModelCommentFilterInput -} - -enum ModelAttributeTypes { - binary - binarySet - bool - list - map - number - numberSet - string - stringSet - _null -} -" -`; - -exports[`Connection on models with no codegen includes custom enum filters 1`] = ` -"type Cart { - id: ID! - cartItems(filter: ModelCartItemFilterInput, sortDirection: ModelSortDirection, limit: Int, nextToken: String): ModelCartItemConnection - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} - -type CartItem { - id: ID! - productType: PRODUCT_TYPE! - cart: Cart - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} - -enum PRODUCT_TYPE { - UNIT - PACKAGE -} - -type ModelCartItemConnection { - items: [CartItem]! - nextToken: String -} - -enum ModelSortDirection { - ASC - DESC -} - -input ModelStringInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String - attributeExists: Boolean - attributeType: ModelAttributeTypes - size: ModelSizeInput -} - -input ModelIDInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID - attributeExists: Boolean - attributeType: ModelAttributeTypes - size: ModelSizeInput -} - -input ModelIntInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelFloatInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelBooleanInput { - ne: Boolean - eq: Boolean - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelSizeInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelPRODUCT_TYPEInput { - eq: PRODUCT_TYPE - ne: PRODUCT_TYPE -} - -input ModelCartItemFilterInput { - id: ModelIDInput - productType: ModelPRODUCT_TYPEInput - and: [ModelCartItemFilterInput] - or: [ModelCartItemFilterInput] - not: ModelCartItemFilterInput -} - -enum ModelAttributeTypes { - binary - binarySet - bool - list - map - number - numberSet - string - stringSet - _null -} -" -`; diff --git a/packages/graphql-connection-transformer/src/__tests__/__snapshots__/NewConnectionTransformer.test.ts.snap b/packages/graphql-connection-transformer/src/__tests__/__snapshots__/NewConnectionTransformer.test.ts.snap deleted file mode 100644 index 88cb7149f7..0000000000 --- a/packages/graphql-connection-transformer/src/__tests__/__snapshots__/NewConnectionTransformer.test.ts.snap +++ /dev/null @@ -1,559 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Many-to-many with conflict resolution generates correct schema 1`] = ` -"type Post { - id: ID! - title: String! - editors(editorID: ModelIDKeyConditionInput, filter: ModelPostEditorFilterInput, sortDirection: ModelSortDirection, limit: Int, nextToken: String): ModelPostEditorConnection - _version: Int! - _deleted: Boolean - _lastChangedAt: AWSTimestamp! - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} - -type PostEditor { - id: ID! - postID: ID! - editorID: ID! - post: Post! - editor: User! - _version: Int! - _deleted: Boolean - _lastChangedAt: AWSTimestamp! - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} - -type User { - id: ID! - username: String! - posts(postID: ModelIDKeyConditionInput, filter: ModelPostEditorFilterInput, sortDirection: ModelSortDirection, limit: Int, nextToken: String): ModelPostEditorConnection - _version: Int! - _deleted: Boolean - _lastChangedAt: AWSTimestamp! - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} - -enum ModelSortDirection { - ASC - DESC -} - -type ModelPostConnection { - items: [Post]! - nextToken: String - startedAt: AWSTimestamp -} - -input ModelStringInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String - attributeExists: Boolean - attributeType: ModelAttributeTypes - size: ModelSizeInput -} - -input ModelIDInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID - attributeExists: Boolean - attributeType: ModelAttributeTypes - size: ModelSizeInput -} - -input ModelIntInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelFloatInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelBooleanInput { - ne: Boolean - eq: Boolean - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelSizeInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelPostFilterInput { - id: ModelIDInput - title: ModelStringInput - and: [ModelPostFilterInput] - or: [ModelPostFilterInput] - not: ModelPostFilterInput -} - -enum ModelAttributeTypes { - binary - binarySet - bool - list - map - number - numberSet - string - stringSet - _null -} - -type Query { - syncPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String, lastSync: AWSTimestamp): ModelPostConnection - getPost(id: ID!): Post - listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection - syncPostEditors(filter: ModelPostEditorFilterInput, limit: Int, nextToken: String, lastSync: AWSTimestamp): ModelPostEditorConnection - syncUsers(filter: ModelUserFilterInput, limit: Int, nextToken: String, lastSync: AWSTimestamp): ModelUserConnection - getUser(id: ID!): User - listUsers(filter: ModelUserFilterInput, limit: Int, nextToken: String): ModelUserConnection -} - -input CreatePostInput { - id: ID - title: String! - _version: Int -} - -input UpdatePostInput { - id: ID! - title: String - _version: Int -} - -input DeletePostInput { - id: ID! - _version: Int -} - -type Mutation { - createPost(input: CreatePostInput!, condition: ModelPostConditionInput): Post - updatePost(input: UpdatePostInput!, condition: ModelPostConditionInput): Post - deletePost(input: DeletePostInput!, condition: ModelPostConditionInput): Post - createPostEditor(input: CreatePostEditorInput!, condition: ModelPostEditorConditionInput): PostEditor - updatePostEditor(input: UpdatePostEditorInput!, condition: ModelPostEditorConditionInput): PostEditor - deletePostEditor(input: DeletePostEditorInput!, condition: ModelPostEditorConditionInput): PostEditor - createUser(input: CreateUserInput!, condition: ModelUserConditionInput): User - updateUser(input: UpdateUserInput!, condition: ModelUserConditionInput): User - deleteUser(input: DeleteUserInput!, condition: ModelUserConditionInput): User -} - -input ModelPostConditionInput { - title: ModelStringInput - and: [ModelPostConditionInput] - or: [ModelPostConditionInput] - not: ModelPostConditionInput -} - -type Subscription { - onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) - onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) - onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) - onCreatePostEditor: PostEditor @aws_subscribe(mutations: [\\"createPostEditor\\"]) - onUpdatePostEditor: PostEditor @aws_subscribe(mutations: [\\"updatePostEditor\\"]) - onDeletePostEditor: PostEditor @aws_subscribe(mutations: [\\"deletePostEditor\\"]) - onCreateUser: User @aws_subscribe(mutations: [\\"createUser\\"]) - onUpdateUser: User @aws_subscribe(mutations: [\\"updateUser\\"]) - onDeleteUser: User @aws_subscribe(mutations: [\\"deleteUser\\"]) -} - -type ModelPostEditorConnection { - items: [PostEditor]! - nextToken: String - startedAt: AWSTimestamp -} - -input ModelPostEditorFilterInput { - id: ModelIDInput - postID: ModelIDInput - editorID: ModelIDInput - and: [ModelPostEditorFilterInput] - or: [ModelPostEditorFilterInput] - not: ModelPostEditorFilterInput -} - -input CreatePostEditorInput { - id: ID - postID: ID! - editorID: ID! - _version: Int -} - -input UpdatePostEditorInput { - id: ID! - postID: ID - editorID: ID - _version: Int -} - -input DeletePostEditorInput { - id: ID! - _version: Int -} - -input ModelPostEditorConditionInput { - postID: ModelIDInput - editorID: ModelIDInput - and: [ModelPostEditorConditionInput] - or: [ModelPostEditorConditionInput] - not: ModelPostEditorConditionInput -} - -type ModelUserConnection { - items: [User]! - nextToken: String - startedAt: AWSTimestamp -} - -input ModelUserFilterInput { - id: ModelIDInput - username: ModelStringInput - and: [ModelUserFilterInput] - or: [ModelUserFilterInput] - not: ModelUserFilterInput -} - -input CreateUserInput { - id: ID - username: String! - _version: Int -} - -input UpdateUserInput { - id: ID! - username: String - _version: Int -} - -input DeleteUserInput { - id: ID! - _version: Int -} - -input ModelUserConditionInput { - username: ModelStringInput - and: [ModelUserConditionInput] - or: [ModelUserConditionInput] - not: ModelUserConditionInput -} - -input ModelIDKeyConditionInput { - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - between: [ID] - beginsWith: ID -} -" -`; - -exports[`Many-to-many without conflict resolution generates correct schema 1`] = ` -"type Post { - id: ID! - title: String! - editors(editorID: ModelIDKeyConditionInput, filter: ModelPostEditorFilterInput, sortDirection: ModelSortDirection, limit: Int, nextToken: String): ModelPostEditorConnection - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} - -type PostEditor { - id: ID! - postID: ID! - editorID: ID! - post: Post! - editor: User! - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} - -type User { - id: ID! - username: String! - posts(postID: ModelIDKeyConditionInput, filter: ModelPostEditorFilterInput, sortDirection: ModelSortDirection, limit: Int, nextToken: String): ModelPostEditorConnection - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} - -enum ModelSortDirection { - ASC - DESC -} - -type ModelPostConnection { - items: [Post]! - nextToken: String -} - -input ModelStringInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String - attributeExists: Boolean - attributeType: ModelAttributeTypes - size: ModelSizeInput -} - -input ModelIDInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID - attributeExists: Boolean - attributeType: ModelAttributeTypes - size: ModelSizeInput -} - -input ModelIntInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelFloatInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelBooleanInput { - ne: Boolean - eq: Boolean - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelSizeInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelPostFilterInput { - id: ModelIDInput - title: ModelStringInput - and: [ModelPostFilterInput] - or: [ModelPostFilterInput] - not: ModelPostFilterInput -} - -enum ModelAttributeTypes { - binary - binarySet - bool - list - map - number - numberSet - string - stringSet - _null -} - -type Query { - getPost(id: ID!): Post - listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection - getUser(id: ID!): User - listUsers(filter: ModelUserFilterInput, limit: Int, nextToken: String): ModelUserConnection -} - -input CreatePostInput { - id: ID - title: String! -} - -input UpdatePostInput { - id: ID! - title: String -} - -input DeletePostInput { - id: ID! -} - -type Mutation { - createPost(input: CreatePostInput!, condition: ModelPostConditionInput): Post - updatePost(input: UpdatePostInput!, condition: ModelPostConditionInput): Post - deletePost(input: DeletePostInput!, condition: ModelPostConditionInput): Post - createPostEditor(input: CreatePostEditorInput!, condition: ModelPostEditorConditionInput): PostEditor - updatePostEditor(input: UpdatePostEditorInput!, condition: ModelPostEditorConditionInput): PostEditor - deletePostEditor(input: DeletePostEditorInput!, condition: ModelPostEditorConditionInput): PostEditor - createUser(input: CreateUserInput!, condition: ModelUserConditionInput): User - updateUser(input: UpdateUserInput!, condition: ModelUserConditionInput): User - deleteUser(input: DeleteUserInput!, condition: ModelUserConditionInput): User -} - -input ModelPostConditionInput { - title: ModelStringInput - and: [ModelPostConditionInput] - or: [ModelPostConditionInput] - not: ModelPostConditionInput -} - -type Subscription { - onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) - onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) - onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) - onCreatePostEditor: PostEditor @aws_subscribe(mutations: [\\"createPostEditor\\"]) - onUpdatePostEditor: PostEditor @aws_subscribe(mutations: [\\"updatePostEditor\\"]) - onDeletePostEditor: PostEditor @aws_subscribe(mutations: [\\"deletePostEditor\\"]) - onCreateUser: User @aws_subscribe(mutations: [\\"createUser\\"]) - onUpdateUser: User @aws_subscribe(mutations: [\\"updateUser\\"]) - onDeleteUser: User @aws_subscribe(mutations: [\\"deleteUser\\"]) -} - -input CreatePostEditorInput { - id: ID - postID: ID! - editorID: ID! -} - -input UpdatePostEditorInput { - id: ID! - postID: ID - editorID: ID -} - -input DeletePostEditorInput { - id: ID! -} - -input ModelPostEditorConditionInput { - postID: ModelIDInput - editorID: ModelIDInput - and: [ModelPostEditorConditionInput] - or: [ModelPostEditorConditionInput] - not: ModelPostEditorConditionInput -} - -type ModelUserConnection { - items: [User]! - nextToken: String -} - -input ModelUserFilterInput { - id: ModelIDInput - username: ModelStringInput - and: [ModelUserFilterInput] - or: [ModelUserFilterInput] - not: ModelUserFilterInput -} - -input CreateUserInput { - id: ID - username: String! -} - -input UpdateUserInput { - id: ID! - username: String -} - -input DeleteUserInput { - id: ID! -} - -input ModelUserConditionInput { - username: ModelStringInput - and: [ModelUserConditionInput] - or: [ModelUserConditionInput] - not: ModelUserConditionInput -} - -input ModelIDKeyConditionInput { - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - between: [ID] - beginsWith: ID -} - -type ModelPostEditorConnection { - items: [PostEditor]! - nextToken: String -} - -input ModelPostEditorFilterInput { - id: ModelIDInput - postID: ModelIDInput - editorID: ModelIDInput - and: [ModelPostEditorFilterInput] - or: [ModelPostEditorFilterInput] - not: ModelPostEditorFilterInput -} -" -`; diff --git a/packages/graphql-connection-transformer/src/definitions.ts b/packages/graphql-connection-transformer/src/definitions.ts deleted file mode 100644 index 02cc248110..0000000000 --- a/packages/graphql-connection-transformer/src/definitions.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { InputObjectTypeDefinitionNode } from 'graphql'; -import { makeInputValueDefinition, makeNonNullType, makeNamedType } from 'graphql-transformer-common'; - -export function updateInputWithConnectionField( - input: InputObjectTypeDefinitionNode, - connectionFieldName: string, - nonNull: boolean = false, -): InputObjectTypeDefinitionNode { - const keyFieldExists = Boolean(input.fields.find((f) => f.name.value === connectionFieldName)); - // If the key field already exists then do not change the input. - // The @connection field will validate that the key field is valid. - if (keyFieldExists) { - return input; - } - const updatedFields = [ - ...input.fields, - makeInputValueDefinition(connectionFieldName, nonNull ? makeNonNullType(makeNamedType('ID')) : makeNamedType('ID')), - ]; - return { - ...input, - fields: updatedFields, - }; -} diff --git a/packages/graphql-connection-transformer/src/index.ts b/packages/graphql-connection-transformer/src/index.ts deleted file mode 100644 index 7c3b95745e..0000000000 --- a/packages/graphql-connection-transformer/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './ModelConnectionTransformer'; -// No-op change to trigger re-publish diff --git a/packages/graphql-connection-transformer/src/resources.ts b/packages/graphql-connection-transformer/src/resources.ts deleted file mode 100644 index dca16606f3..0000000000 --- a/packages/graphql-connection-transformer/src/resources.ts +++ /dev/null @@ -1,453 +0,0 @@ -import Table, { GlobalSecondaryIndex, KeySchema, Projection, AttributeDefinition } from 'cloudform-types/types/dynamoDb/table'; -import Resolver from 'cloudform-types/types/appSync/resolver'; -import Template from 'cloudform-types/types/template'; -import { Fn, Refs } from 'cloudform-types'; -import { ObjectTypeDefinitionNode, InterfaceTypeDefinitionNode } from 'graphql'; -import { - DynamoDBMappingTemplate, - str, - print, - ref, - obj, - set, - nul, - ObjectNode, - ifElse, - compoundExpression, - bool, - equals, - iff, - raw, - Expression, - or, - list, -} from 'graphql-mapping-template'; -import { - ResourceConstants, - ModelResourceIDs, - DEFAULT_SCALARS, - NONE_VALUE, - NONE_INT_VALUE, - applyKeyConditionExpression, - attributeTypeFromScalar, - toCamelCase, - applyCompositeKeyConditionExpression, -} from 'graphql-transformer-common'; -import { InvalidDirectiveError } from 'graphql-transformer-core'; - -export class ResourceFactory { - public makeParams() { - return {}; - } - - /** - * Creates the barebones template for an application - */ - public initTemplate(): Template { - return { - Parameters: this.makeParams(), - Resources: {}, - Outputs: {}, - }; - } - - /** - * Add a GSI for the connection if one does not already exist. - * @param table The table to add the GSI to. - */ - public updateTableForConnection( - table: Table, - connectionName: string, - connectionAttributeName: string, - sortField: { name: string; type: string } = null, - ): Table { - const gsis = table.Properties.GlobalSecondaryIndexes || ([] as GlobalSecondaryIndex[]); - if (gsis.length >= 20) { - throw new InvalidDirectiveError( - `Cannot create connection ${connectionName}. Table ${table.Properties.TableName} out of GSI capacity.`, - ); - } - const connectionGSIName = `gsi-${connectionName}`; - - // If the GSI does not exist yet then add it. - const existingGSI = gsis.find((gsi) => gsi.IndexName === connectionGSIName); - if (!existingGSI) { - const keySchema = [new KeySchema({ AttributeName: connectionAttributeName, KeyType: 'HASH' })]; - if (sortField) { - keySchema.push(new KeySchema({ AttributeName: sortField.name, KeyType: 'RANGE' })); - } - gsis.push( - new GlobalSecondaryIndex({ - IndexName: connectionGSIName, - KeySchema: keySchema, - Projection: new Projection({ - ProjectionType: 'ALL', - }), - ProvisionedThroughput: Fn.If(ResourceConstants.CONDITIONS.ShouldUsePayPerRequestBilling, Refs.NoValue, { - ReadCapacityUnits: Fn.Ref(ResourceConstants.PARAMETERS.DynamoDBModelTableReadIOPS), - WriteCapacityUnits: Fn.Ref(ResourceConstants.PARAMETERS.DynamoDBModelTableWriteIOPS), - }) as any, - }), - ); - } - - // If the attribute definition does not exist yet, add it. - const attributeDefinitions = table.Properties.AttributeDefinitions as AttributeDefinition[]; - const existingAttribute = attributeDefinitions.find((attr) => attr.AttributeName === connectionAttributeName); - if (!existingAttribute) { - attributeDefinitions.push( - new AttributeDefinition({ - AttributeName: connectionAttributeName, - AttributeType: 'S', - }), - ); - } - - // If the attribute definition does not exist yet, add it. - if (sortField) { - const existingSortAttribute = attributeDefinitions.find((attr) => attr.AttributeName === sortField.name); - if (!existingSortAttribute) { - const scalarType = DEFAULT_SCALARS[sortField.type]; - const attributeType = scalarType === 'String' ? 'S' : 'N'; - attributeDefinitions.push(new AttributeDefinition({ AttributeName: sortField.name, AttributeType: attributeType })); - } - } - - table.Properties.GlobalSecondaryIndexes = gsis; - table.Properties.AttributeDefinitions = attributeDefinitions; - return table; - } - - /** - * Create a get item resolver for singular connections. - * @param type The parent type name. - * @param field The connection field name. - * @param relatedType The name of the related type to fetch from. - * @param connectionAttribute The name of the underlying attribute containing the id. - * @param idFieldName The name of the field within the type that serve as the id. - * @param sortFieldInfo The info about the sort field if specified. - */ - public makeGetItemConnectionResolver( - type: string, - field: string, - relatedType: string, - connectionAttribute: string, - idFieldName: string, - sortFieldInfo?: { primarySortFieldName: string; sortFieldName: string; sortFieldIsStringLike: boolean }, - ): Resolver { - let keyObj: ObjectNode = obj({ - [`${idFieldName}`]: ref( - `util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.${connectionAttribute}, "${NONE_VALUE}"))`, - ), - }); - - if (sortFieldInfo) { - if (sortFieldInfo.sortFieldIsStringLike) { - keyObj.attributes.push([ - sortFieldInfo.primarySortFieldName, - ref(`util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.${sortFieldInfo.sortFieldName}, "${NONE_VALUE}"))`), - ]); - } else { - // Use Int minvalue as default - keyObj.attributes.push([ - sortFieldInfo.primarySortFieldName, - ref(`util.dynamodb.toDynamoDBJson($util.defaultIfNull($ctx.source.${sortFieldInfo.sortFieldName}, ${NONE_INT_VALUE}))`), - ]); - } - } - - return new Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(ModelResourceIDs.ModelTableDataSourceID(relatedType), 'Name'), - FieldName: field, - TypeName: type, - RequestMappingTemplate: print( - ifElse( - or([ - raw(`$util.isNull($ctx.source.${connectionAttribute})`), - ...(sortFieldInfo ? [raw(`$util.isNull($ctx.source.${connectionAttribute})`)] : []), - ]), - raw('#return'), - DynamoDBMappingTemplate.getItem({ - key: keyObj, - }), - ), - ), - ResponseMappingTemplate: print(DynamoDBMappingTemplate.dynamoDBResponse(false)), - }).dependsOn(ResourceConstants.RESOURCES.GraphQLSchemaLogicalID); - } - - /** - * Create a resolver that queries an item in DynamoDB. - * @param type - */ - public makeQueryConnectionResolver( - type: string, - field: string, - relatedType: string, - connectionAttribute: string, - connectionName: string, - idFieldName: string, - sortKeyInfo?: { fieldName: string; attributeType: 'S' | 'B' | 'N' }, - limit?: number, - ) { - const pageLimit = limit || ResourceConstants.DEFAULT_PAGE_LIMIT; - const setup: Expression[] = [ - set(ref('limit'), ref(`util.defaultIfNull($context.args.limit, ${pageLimit})`)), - set( - ref('query'), - obj({ - expression: str('#connectionAttribute = :connectionAttribute'), - expressionNames: obj({ - '#connectionAttribute': str(connectionAttribute), - }), - expressionValues: obj({ - ':connectionAttribute': obj({ - S: str(`$context.source.${idFieldName}`), - }), - }), - }), - ), - ]; - if (sortKeyInfo) { - setup.push(applyKeyConditionExpression(sortKeyInfo.fieldName, sortKeyInfo.attributeType, 'query')); - } - return new Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(ModelResourceIDs.ModelTableDataSourceID(relatedType), 'Name'), - FieldName: field, - TypeName: type, - RequestMappingTemplate: print( - ifElse( - raw(`$util.isNull($context.source.${idFieldName})`), - compoundExpression([set(ref('result'), obj({ items: list([]) })), raw('#return($result)')]), - compoundExpression([ - ...setup, - DynamoDBMappingTemplate.query({ - query: raw('$util.toJson($query)'), - scanIndexForward: ifElse( - ref('context.args.sortDirection'), - ifElse(equals(ref('context.args.sortDirection'), str('ASC')), bool(true), bool(false)), - bool(true), - ), - filter: ifElse(ref('context.args.filter'), ref('util.transform.toDynamoDBFilterExpression($ctx.args.filter)'), nul()), - limit: ref('limit'), - nextToken: ifElse(ref('context.args.nextToken'), ref('util.toJson($context.args.nextToken)'), nul()), - index: str(`gsi-${connectionName}`), - }), - ]), - ), - ), - ResponseMappingTemplate: print( - DynamoDBMappingTemplate.dynamoDBResponse( - false, - compoundExpression([iff(raw('!$result'), set(ref('result'), ref('ctx.result'))), raw('$util.toJson($result)')]), - ), - ), - }).dependsOn(ResourceConstants.RESOURCES.GraphQLSchemaLogicalID); - } - - // Resources for new way to parameterize @connection - - /** - * Create a get item resolver for singular connections. - * @param type The parent type name. - * @param field The connection field name. - * @param relatedType The name of the related type to fetch from. - * @param connectionAttributes The names of the underlying attributes containing the fields to query by. - * @param keySchema Key schema of the index or table being queried. - */ - public makeGetItemConnectionWithKeyResolver( - type: string, - field: string, - relatedType: string, - connectionAttributes: string[], - keySchema: KeySchema[], - ): Resolver { - const partitionKeyName = keySchema[0].AttributeName as string; - - let keyObj: ObjectNode = obj({ - [partitionKeyName]: ref( - `util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.${connectionAttributes[0]}, "${NONE_VALUE}"))`, - ), - }); - - // Add a composite sort key or simple sort key if there is one. - if (connectionAttributes.length > 2) { - const rangeKeyFields = connectionAttributes.slice(1); - const sortKeyName = keySchema[1].AttributeName as string; - const condensedSortKeyValue = this.condenseRangeKey(rangeKeyFields.map((keyField) => `\${ctx.source.${keyField}}`)); - - keyObj.attributes.push([ - sortKeyName, - ref(`util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank("${condensedSortKeyValue}", "${NONE_VALUE}"))`), - ]); - } else if (connectionAttributes[1]) { - const sortKeyName = keySchema[1].AttributeName as string; - keyObj.attributes.push([ - sortKeyName, - ref(`util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.${connectionAttributes[1]}, "${NONE_VALUE}"))`), - ]); - } - - return new Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(ModelResourceIDs.ModelTableDataSourceID(relatedType), 'Name'), - FieldName: field, - TypeName: type, - RequestMappingTemplate: print( - ifElse( - or(connectionAttributes.map((ca) => raw(`$util.isNull($ctx.source.${ca})`))), - raw('#return'), - compoundExpression([ - DynamoDBMappingTemplate.getItem({ - key: keyObj, - }), - ]), - ), - ), - ResponseMappingTemplate: print(DynamoDBMappingTemplate.dynamoDBResponse(false)), - }).dependsOn(ResourceConstants.RESOURCES.GraphQLSchemaLogicalID); - } - - /** - * Create a resolver that queries an item in DynamoDB. - * @param type The parent type name. - * @param field The connection field name. - * @param relatedType The related type to fetch from. - * @param connectionAttributes The names of the underlying attributes containing the fields to query by. - * @param keySchema The keySchema for the table or index being queried. - * @param indexName The index to run the query on. - */ - public makeQueryConnectionWithKeyResolver( - type: string, - field: string, - relatedType: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, - connectionAttributes: string[], - keySchema: KeySchema[], - indexName: string, - limit?: number, - ) { - const pageLimit = limit || ResourceConstants.DEFAULT_PAGE_LIMIT; - const setup: Expression[] = [ - set(ref('limit'), ref(`util.defaultIfNull($context.args.limit, ${pageLimit})`)), - set(ref('query'), this.makeExpression(keySchema, connectionAttributes)), - ]; - - // If the key schema has a sort key but one is not provided for the query, let a sort key be - // passed in via $ctx.args. - if (keySchema[1] && !connectionAttributes[1]) { - const sortKeyField = relatedType.fields.find((f) => f.name.value === keySchema[1].AttributeName); - - if (sortKeyField) { - setup.push(applyKeyConditionExpression(String(keySchema[1].AttributeName), attributeTypeFromScalar(sortKeyField.type), 'query')); - } else { - setup.push( - applyCompositeKeyConditionExpression( - this.getSortKeyNames(String(keySchema[1].AttributeName)), - 'query', - this.makeCompositeSortKeyName(String(keySchema[1].AttributeName)), - String(keySchema[1].AttributeName), - ), - ); - } - } - - let queryArguments = { - query: raw('$util.toJson($query)'), - scanIndexForward: ifElse( - ref('context.args.sortDirection'), - ifElse(equals(ref('context.args.sortDirection'), str('ASC')), bool(true), bool(false)), - bool(true), - ), - filter: ifElse(ref('context.args.filter'), ref('util.transform.toDynamoDBFilterExpression($ctx.args.filter)'), nul()), - limit: ref('limit'), - nextToken: ifElse(ref('context.args.nextToken'), ref('util.toJson($context.args.nextToken)'), nul()), - index: indexName ? str(indexName) : undefined, - }; - - if (!indexName) { - const indexArg = 'index'; - delete queryArguments[indexArg]; - } - - const queryObj = DynamoDBMappingTemplate.query(queryArguments); - - return new Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(ModelResourceIDs.ModelTableDataSourceID(relatedType.name.value), 'Name'), - FieldName: field, - TypeName: type, - RequestMappingTemplate: print( - ifElse( - raw(`$util.isNull($ctx.source.${connectionAttributes[0]})`), - compoundExpression([set(ref('result'), obj({ items: list([]) })), raw('#return($result)')]), - compoundExpression([...setup, queryObj]), - ), - ), - ResponseMappingTemplate: print( - DynamoDBMappingTemplate.dynamoDBResponse( - false, - compoundExpression([iff(raw('!$result'), set(ref('result'), ref('ctx.result'))), raw('$util.toJson($result)')]), - ), - ), - }).dependsOn(ResourceConstants.RESOURCES.GraphQLSchemaLogicalID); - } - - /** - * Makes the query expression based on whether there is a sort key to be used for the query - * or not. - * @param keySchema The key schema for the table or index being queried. - * @param connectionAttributes The names of the underlying attributes containing the fields to query by. - */ - public makeExpression(keySchema: KeySchema[], connectionAttributes: string[]): ObjectNode { - if (keySchema[1] && connectionAttributes[1]) { - let condensedSortKeyValue: string = undefined; - if (connectionAttributes.length > 2) { - const rangeKeyFields = connectionAttributes.slice(1); - condensedSortKeyValue = this.condenseRangeKey(rangeKeyFields.map((keyField) => `\${context.source.${keyField}}`)); - } - - return obj({ - expression: str('#partitionKey = :partitionKey AND #sortKey = :sortKey'), - expressionNames: obj({ - '#partitionKey': str(String(keySchema[0].AttributeName)), - '#sortKey': str(String(keySchema[1].AttributeName)), - }), - expressionValues: obj({ - ':partitionKey': obj({ - S: str(`$context.source.${connectionAttributes[0]}`), - }), - ':sortKey': obj({ - S: str(condensedSortKeyValue || `$context.source.${connectionAttributes[1]}`), - }), - }), - }); - } - - return obj({ - expression: str('#partitionKey = :partitionKey'), - expressionNames: obj({ - '#partitionKey': str(String(keySchema[0].AttributeName)), - }), - expressionValues: obj({ - ':partitionKey': obj({ - S: str(`$context.source.${connectionAttributes[0]}`), - }), - }), - }); - } - - private condenseRangeKey(fields: string[]) { - return fields.join(ModelResourceIDs.ModelCompositeKeySeparator()); - } - - public makeCompositeSortKeyName(sortKeyName: string) { - const attributeNames = sortKeyName.split(ModelResourceIDs.ModelCompositeKeySeparator()); - return toCamelCase(attributeNames); - } - - private getSortKeyNames(compositeSK: string) { - return compositeSK.split(ModelResourceIDs.ModelCompositeKeySeparator()); - } -} diff --git a/packages/graphql-connection-transformer/tsconfig.json b/packages/graphql-connection-transformer/tsconfig.json deleted file mode 100644 index 3793fefb97..0000000000 --- a/packages/graphql-connection-transformer/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "strict": false, // TODO enable - "rootDir": "src", - "outDir": "lib" - }, - "references": [ - { "path": "../amplify-graphql-directives" }, - { "path": "../graphql-dynamodb-transformer" }, - { "path": "../graphql-key-transformer" }, - { "path": "../graphql-mapping-template" }, - { "path": "../graphql-transformer-common" }, - { "path": "../graphql-transformer-core" } - ] -} diff --git a/packages/graphql-dynamodb-transformer/.npmignore b/packages/graphql-dynamodb-transformer/.npmignore deleted file mode 100644 index 3ee5d55b0b..0000000000 --- a/packages/graphql-dynamodb-transformer/.npmignore +++ /dev/null @@ -1,5 +0,0 @@ -**/__mocks__/** -**/__tests__/** -src -tsconfig.json -tsconfig.tsbuildinfo diff --git a/packages/graphql-dynamodb-transformer/API.md b/packages/graphql-dynamodb-transformer/API.md deleted file mode 100644 index ff6a11383f..0000000000 --- a/packages/graphql-dynamodb-transformer/API.md +++ /dev/null @@ -1,191 +0,0 @@ -## API Report File for "graphql-dynamodb-transformer" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { default as default_2 } from 'cloudform-types/types/appSync/graphQlApi'; -import { default as default_3 } from 'cloudform-types/types/appSync/graphQlSchema'; -import { default as default_4 } from 'cloudform-types/types/dynamoDb/table'; -import { default as default_5 } from 'cloudform-types/types/iam/role'; -import { default as default_6 } from 'cloudform-types/types/appSync/dataSource'; -import { default as default_7 } from 'cloudform-types/types/appSync/resolver'; -import { DeletionPolicy } from 'cloudform-types'; -import { DirectiveNode } from 'graphql'; -import { DocumentNode } from 'graphql'; -import { EnumTypeDefinitionNode } from 'graphql'; -import { FieldDefinitionNode } from 'graphql'; -import { InputObjectTypeDefinitionNode } from 'graphql'; -import { InputValueDefinitionNode } from 'graphql'; -import { InterfaceTypeDefinitionNode } from 'graphql'; -import { NumberParameter } from 'cloudform-types'; -import { ObjectTypeDefinitionNode } from 'graphql'; -import { ObjectTypeExtensionNode } from 'graphql'; -import Output from 'cloudform-types/types/output'; -import { StringParameter } from 'cloudform-types'; -import { SyncConfig } from 'graphql-transformer-core'; -import Template from 'cloudform-types/types/template'; -import { Transformer as Transformer_2 } from 'graphql-transformer-core'; -import { TransformerContext } from 'graphql-transformer-core'; - -// @public (undocumented) -export const CONDITIONS_MINIMUM_VERSION = 5; - -// @public (undocumented) -export const directiveDefinition: DocumentNode; - -// @public (undocumented) -export class DynamoDBModelTransformer extends Transformer_2 { - constructor(opts?: DynamoDBModelTransformerOptions); - // (undocumented) - after: (ctx: TransformerContext) => void; - // (undocumented) - before: (ctx: TransformerContext) => void; - // (undocumented) - object: (def: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => void; - // (undocumented) - opts: DynamoDBModelTransformerOptions; - // Warning: (ae-forgotten-export) The symbol "ResourceFactory" needs to be exported by the entry point index.d.ts - // - // (undocumented) - resources: ResourceFactory; -} - -// @public (undocumented) -export interface DynamoDBModelTransformerOptions { - // (undocumented) - EnableDeletionProtection?: boolean; - // (undocumented) - SyncConfig?: SyncConfig; -} - -// @public (undocumented) -export function getCreatedAtFieldName(directive: DirectiveNode): string | undefined; - -// @public (undocumented) -export function getFieldsOptionalNonNullableField(fields: InputValueDefinitionNode[], obj: ObjectTypeDefinitionNode): string[]; - -// @public (undocumented) -export function getNonModelObjectArray(obj: ObjectTypeDefinitionNode, ctx: TransformerContext, pMap: Map): ObjectTypeDefinitionNode[]; - -// @public (undocumented) -export function getTimestampFieldName(directive: DirectiveNode, fieldName: string, defaultFiledValue: string): string | undefined; - -// @public (undocumented) -export function getUpdatedAtFieldName(directive: DirectiveNode): string | undefined; - -// @public (undocumented) -export function makeAttributeTypeEnum(): EnumTypeDefinitionNode; - -// @public (undocumented) -export function makeCreateInputObject(obj: ObjectTypeDefinitionNode, directive: DirectiveNode, nonModelTypes: ObjectTypeDefinitionNode[], ctx: TransformerContext, isSync?: boolean): InputObjectTypeDefinitionNode; - -// @public (undocumented) -export function makeDeleteInputObject(obj: ObjectTypeDefinitionNode, isSync?: boolean): InputObjectTypeDefinitionNode; - -// @public (undocumented) -export function makeEnumFilterInputObjects(obj: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, ctx: TransformerContext, supportsConditions: Boolean): InputObjectTypeDefinitionNode[]; - -// @public (undocumented) -export function makeModelConnectionField(fieldName: string, returnTypeName: string, sortKeyInfo?: SortKeyFieldInfo, directives?: DirectiveNode[]): FieldDefinitionNode; - -// @public (undocumented) -export function makeModelConnectionType(typeName: string, isSync?: Boolean): ObjectTypeExtensionNode; - -// @public (undocumented) -export function makeModelScalarFilterInputObject(type: string, supportsConditions: Boolean): InputObjectTypeDefinitionNode; - -// @public (undocumented) -export function makeModelSortDirectionEnumObject(): EnumTypeDefinitionNode; - -// @public (undocumented) -export function makeModelXConditionInputObject(obj: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, ctx: TransformerContext, supportsConditions: Boolean): InputObjectTypeDefinitionNode; - -// @public (undocumented) -export function makeModelXFilterInputObject(obj: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, ctx: TransformerContext, supportsConditions: Boolean): InputObjectTypeDefinitionNode; - -// @public (undocumented) -export function makeNonModelInputObject(obj: ObjectTypeDefinitionNode, nonModelTypes: ObjectTypeDefinitionNode[], ctx: TransformerContext): InputObjectTypeDefinitionNode; - -// @public (undocumented) -export function makeScalarFilterInputs(supportsConditions: Boolean): InputObjectTypeDefinitionNode[]; - -// @public (undocumented) -export function makeSubscriptionField(fieldName: string, returnTypeName: string, mutations: string[]): FieldDefinitionNode; - -// @public (undocumented) -export function makeUpdateInputObject(obj: ObjectTypeDefinitionNode, nonModelTypes: ObjectTypeDefinitionNode[], ctx: TransformerContext, isSync?: boolean): InputObjectTypeDefinitionNode; - -// @public (undocumented) -export interface ModelDirectiveArgs { - // (undocumented) - mutations?: MutationNameMap; - // (undocumented) - queries?: QueryNameMap; - // (undocumented) - subscriptions?: SubscriptionNameMap; - // (undocumented) - timestamps?: ModelDirectiveTimestampConfiguration; -} - -// @public (undocumented) -export interface ModelDirectiveTimestampConfiguration { - // (undocumented) - createdAt?: string; - // (undocumented) - updatedAt?: string; -} - -// @public (undocumented) -export type ModelSubscriptionLevel = 'off' | 'public' | 'on'; - -// @public (undocumented) -export interface MutationNameMap { - // (undocumented) - create?: string; - // (undocumented) - delete?: string; - // (undocumented) - update?: string; -} - -// @public (undocumented) -export interface QueryNameMap { - // (undocumented) - get?: string; - // (undocumented) - list?: string; - // (undocumented) - query?: string; -} - -// @public (undocumented) -export interface SortKeyFieldInfo { - // (undocumented) - fieldName: string; - // (undocumented) - keyName?: string; - // (undocumented) - model?: string; - // (undocumented) - typeName: SortKeyFieldInfoTypeName; -} - -// @public (undocumented) -export type SortKeyFieldInfoTypeName = 'Composite' | string; - -// @public (undocumented) -export interface SubscriptionNameMap { - // (undocumented) - level?: ModelSubscriptionLevel; - // (undocumented) - onCreate?: string[]; - // (undocumented) - onDelete?: string[]; - // (undocumented) - onUpdate?: string[]; -} - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/graphql-dynamodb-transformer/CHANGELOG.md b/packages/graphql-dynamodb-transformer/CHANGELOG.md deleted file mode 100644 index c471927401..0000000000 --- a/packages/graphql-dynamodb-transformer/CHANGELOG.md +++ /dev/null @@ -1,1180 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [7.2.80](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.79...graphql-dynamodb-transformer@7.2.80) (2024-07-15) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.79](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.78...graphql-dynamodb-transformer@7.2.79) (2024-07-02) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.78](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.77...graphql-dynamodb-transformer@7.2.78) (2024-06-25) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.77](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.76...graphql-dynamodb-transformer@7.2.77) (2024-04-26) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.76](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.75...graphql-dynamodb-transformer@7.2.76) (2024-04-11) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.75](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.74...graphql-dynamodb-transformer@7.2.75) (2024-03-28) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.74](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.73...graphql-dynamodb-transformer@7.2.74) (2024-02-28) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.73](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.72...graphql-dynamodb-transformer@7.2.73) (2024-02-05) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.72](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.71...graphql-dynamodb-transformer@7.2.72) (2024-01-22) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.71](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.70...graphql-dynamodb-transformer@7.2.71) (2023-12-18) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.70](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.69...graphql-dynamodb-transformer@7.2.70) (2023-12-06) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.69](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.68...graphql-dynamodb-transformer@7.2.69) (2023-11-18) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.68](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.67...graphql-dynamodb-transformer@7.2.68) (2023-11-16) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.67](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.66...graphql-dynamodb-transformer@7.2.67) (2023-11-15) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.66](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.65...graphql-dynamodb-transformer@7.2.66) (2023-10-21) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.65](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.64...graphql-dynamodb-transformer@7.2.65) (2023-08-30) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.64](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.63...graphql-dynamodb-transformer@7.2.64) (2023-08-28) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.63](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.62...graphql-dynamodb-transformer@7.2.63) (2023-08-09) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.62](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.61...graphql-dynamodb-transformer@7.2.62) (2023-07-21) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.61](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.60...graphql-dynamodb-transformer@7.2.61) (2023-07-17) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.60](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.59...graphql-dynamodb-transformer@7.2.60) (2023-07-07) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.59](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.58...graphql-dynamodb-transformer@7.2.59) (2023-07-07) - -### Bug Fixes - -- trigger republish of dependencies that failed in https://app.circleci.com/pipelines/github/aws-amplify/amplify-category-api/7981/workflows/e7366f04-6f0a-4ee4-9cc2-1772089e8005/jobs/163571 ([f2c7151](https://github.com/aws-amplify/amplify-category-api/commit/f2c7151005e4a9fd29d91ac1af1f3e482a06a5cc)) - -## [7.2.58](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.57...graphql-dynamodb-transformer@7.2.58) (2023-07-07) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.57](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.56...graphql-dynamodb-transformer@7.2.57) (2023-06-29) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.56](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.55...graphql-dynamodb-transformer@7.2.56) (2023-06-20) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.55](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.54...graphql-dynamodb-transformer@7.2.55) (2023-06-05) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.54](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.53...graphql-dynamodb-transformer@7.2.54) (2023-05-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.53](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.52...graphql-dynamodb-transformer@7.2.53) (2023-05-17) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.52](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.51...graphql-dynamodb-transformer@7.2.52) (2023-04-25) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.51](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.50...graphql-dynamodb-transformer@7.2.51) (2023-03-30) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.50](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.49...graphql-dynamodb-transformer@7.2.50) (2023-03-15) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.49](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.48...graphql-dynamodb-transformer@7.2.49) (2023-03-01) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.48](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.47...graphql-dynamodb-transformer@7.2.48) (2023-02-27) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.47](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.46...graphql-dynamodb-transformer@7.2.47) (2023-01-26) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.46](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.45...graphql-dynamodb-transformer@7.2.46) (2023-01-12) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.45](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.44...graphql-dynamodb-transformer@7.2.45) (2023-01-12) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.44](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.43...graphql-dynamodb-transformer@7.2.44) (2022-12-03) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.43](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.42...graphql-dynamodb-transformer@7.2.43) (2022-09-14) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.42](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.40...graphql-dynamodb-transformer@7.2.42) (2022-07-20) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.41](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.40...graphql-dynamodb-transformer@7.2.41) (2022-07-14) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.40](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.39...graphql-dynamodb-transformer@7.2.40) (2022-07-01) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.39](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.38...graphql-dynamodb-transformer@7.2.39) (2022-06-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.38](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.37...graphql-dynamodb-transformer@7.2.38) (2022-06-13) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.37](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.36...graphql-dynamodb-transformer@7.2.37) (2022-06-10) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.36](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.35...graphql-dynamodb-transformer@7.2.36) (2022-06-10) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.35](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.32...graphql-dynamodb-transformer@7.2.35) (2022-06-07) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.34](https://github.com/aws-amplify/amplify-category-api/compare/graphql-dynamodb-transformer@7.2.32...graphql-dynamodb-transformer@7.2.34) (2022-05-31) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.33](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.32...graphql-dynamodb-transformer@7.2.33) (2022-05-02) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.32](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.31...graphql-dynamodb-transformer@7.2.32) (2022-04-29) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.31](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.30...graphql-dynamodb-transformer@7.2.31) (2022-04-27) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.30](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.29...graphql-dynamodb-transformer@7.2.30) (2022-04-11) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.29](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.28...graphql-dynamodb-transformer@7.2.29) (2022-04-07) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.28](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.27...graphql-dynamodb-transformer@7.2.28) (2022-03-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.27](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.26...graphql-dynamodb-transformer@7.2.27) (2022-03-17) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.26](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.25...graphql-dynamodb-transformer@7.2.26) (2022-03-14) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.24...graphql-dynamodb-transformer@7.2.25) (2022-03-07) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.23...graphql-dynamodb-transformer@7.2.24) (2022-02-25) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.22...graphql-dynamodb-transformer@7.2.23) (2022-02-15) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.18...graphql-dynamodb-transformer@7.2.22) (2022-02-10) - -## 7.6.19 (2022-02-08) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.17...graphql-dynamodb-transformer@7.2.18) (2022-02-03) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.16...graphql-dynamodb-transformer@7.2.17) (2022-01-31) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.15...graphql-dynamodb-transformer@7.2.16) (2022-01-27) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.14...graphql-dynamodb-transformer@7.2.15) (2022-01-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.13...graphql-dynamodb-transformer@7.2.14) (2022-01-13) - -### Bug Fixes - -- clean up missing and unused GraphQL v1 dependencies ([#9496](https://github.com/aws-amplify/amplify-cli/issues/9496)) ([fe8201b](https://github.com/aws-amplify/amplify-cli/commit/fe8201be17f42db233fce0bb366ff4d0c8358ec0)) - -## [7.2.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.11...graphql-dynamodb-transformer@7.2.13) (2022-01-10) - -## 7.6.7 (2022-01-10) - -### Bug Fixes - -- **graphql-model-transformer:** add id field to update input objects ([#9276](https://github.com/aws-amplify/amplify-cli/issues/9276)) ([45cd973](https://github.com/aws-amplify/amplify-cli/commit/45cd9736b5fc09d78a3f445f62fc2a971c11fec7)) -- make update input id field required ([#9452](https://github.com/aws-amplify/amplify-cli/issues/9452)) ([345fe28](https://github.com/aws-amplify/amplify-cli/commit/345fe28a60bbf1de32496430e38e25463a77e96c)) - -## [7.2.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.10...graphql-dynamodb-transformer@7.2.11) (2021-12-21) - -### Bug Fixes - -- generate list types will nullable elements ([#9310](https://github.com/aws-amplify/amplify-cli/issues/9310)) ([e972956](https://github.com/aws-amplify/amplify-cli/commit/e9729565fef2ac7df51f7fc7f345da536f385ac1)) - -## [7.2.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.9...graphql-dynamodb-transformer@7.2.10) (2021-12-17) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.8...graphql-dynamodb-transformer@7.2.9) (2021-12-03) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.7...graphql-dynamodb-transformer@7.2.8) (2021-12-02) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.6...graphql-dynamodb-transformer@7.2.7) (2021-12-01) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.5...graphql-dynamodb-transformer@7.2.6) (2021-11-26) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.4...graphql-dynamodb-transformer@7.2.5) (2021-11-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.3...graphql-dynamodb-transformer@7.2.4) (2021-11-21) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.2...graphql-dynamodb-transformer@7.2.3) (2021-11-20) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@7.2.1...graphql-dynamodb-transformer@7.2.2) (2021-11-17) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [7.2.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.23.0...graphql-dynamodb-transformer@7.2.1) (2021-11-15) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -# [7.0.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.25...graphql-dynamodb-transformer@7.0.0) (2021-11-13) - -### Features - -- generate list types as non-null ([#8166](https://github.com/aws-amplify/amplify-cli/issues/8166)) ([93786c1](https://github.com/aws-amplify/amplify-cli/commit/93786c13ef04c72748ca32a1ef7878c0e6b5b129)) - -# [6.23.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.25...graphql-dynamodb-transformer@6.23.0) (2021-11-11) - -### Features - -- generate list types as non-null ([#8166](https://github.com/aws-amplify/amplify-cli/issues/8166)) ([93786c1](https://github.com/aws-amplify/amplify-cli/commit/93786c13ef04c72748ca32a1ef7878c0e6b5b129)) - -## [6.22.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.24...graphql-dynamodb-transformer@6.22.25) (2021-10-10) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.23...graphql-dynamodb-transformer@6.22.24) (2021-10-06) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.22...graphql-dynamodb-transformer@6.22.23) (2021-09-27) - -### Bug Fixes - -- **graphql-model-transformer:** iam role name does not exceed 64 characters ([#8244](https://github.com/aws-amplify/amplify-cli/issues/8244)) ([812a671](https://github.com/aws-amplify/amplify-cli/commit/812a67163d6dd33160bf7ace9afd538c83a7af1a)) - -## [6.22.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.21...graphql-dynamodb-transformer@6.22.22) (2021-09-18) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.21](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.20...graphql-dynamodb-transformer@6.22.21) (2021-09-14) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.20](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.19...graphql-dynamodb-transformer@6.22.20) (2021-09-09) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.19](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.18...graphql-dynamodb-transformer@6.22.19) (2021-09-02) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.17...graphql-dynamodb-transformer@6.22.18) (2021-08-24) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.16...graphql-dynamodb-transformer@6.22.17) (2021-08-06) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.15...graphql-dynamodb-transformer@6.22.16) (2021-07-30) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.14...graphql-dynamodb-transformer@6.22.15) (2021-07-27) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.13...graphql-dynamodb-transformer@6.22.14) (2021-07-16) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.12...graphql-dynamodb-transformer@6.22.13) (2021-06-30) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.11...graphql-dynamodb-transformer@6.22.12) (2021-06-24) - -### Bug Fixes - -- correct 'tranformer' typo ([#7408](https://github.com/aws-amplify/amplify-cli/issues/7408)) ([9420f1b](https://github.com/aws-amplify/amplify-cli/commit/9420f1b29137fd7621d7d902a147e596776357df)) -- **graphql-transformer-common:** improve generated graphql pluralization ([#7258](https://github.com/aws-amplify/amplify-cli/issues/7258)) ([fc3ad0d](https://github.com/aws-amplify/amplify-cli/commit/fc3ad0dd5a12a7912c59ae12024f593b4cdf7f2d)), closes [#4224](https://github.com/aws-amplify/amplify-cli/issues/4224) -- validates optional non nullable fields to be not null ([#7170](https://github.com/aws-amplify/amplify-cli/issues/7170)) ([1ca842c](https://github.com/aws-amplify/amplify-cli/commit/1ca842c703bfc34e65bfffff85908ea8b2ccb521)) - -## [6.22.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.10...graphql-dynamodb-transformer@6.22.11) (2021-06-15) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.9...graphql-dynamodb-transformer@6.22.10) (2021-05-29) - -## 4.51.4 (2021-05-28) - -### Bug Fixes - -- **graphql-model-transformer:** use modelobject key for mutation resolver creation ([#7419](https://github.com/aws-amplify/amplify-cli/issues/7419)) ([37bc551](https://github.com/aws-amplify/amplify-cli/commit/37bc551030d47de993f8227ee3af0ba6cd738ab2)), closes [#i7417](https://github.com/aws-amplify/amplify-cli/issues/i7417) - -## [6.22.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.8...graphql-dynamodb-transformer@6.22.9) (2021-05-26) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.7...graphql-dynamodb-transformer@6.22.8) (2021-05-18) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** make primary key non null on del ([#6337](https://github.com/aws-amplify/amplify-cli/issues/6337)) ([4a5c679](https://github.com/aws-amplify/amplify-cli/commit/4a5c6795680b6b88efb19b923ee234253ca30c35)), closes [#2564](https://github.com/aws-amplify/amplify-cli/issues/2564) - -## [6.22.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.6...graphql-dynamodb-transformer@6.22.7) (2021-05-14) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.4...graphql-dynamodb-transformer@6.22.6) (2021-05-03) - -## 4.50.1 (2021-05-03) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.4...graphql-dynamodb-transformer@6.22.5) (2021-05-03) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.3...graphql-dynamodb-transformer@6.22.4) (2021-04-27) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.2...graphql-dynamodb-transformer@6.22.3) (2021-04-19) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.22.1...graphql-dynamodb-transformer@6.22.2) (2021-04-14) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.22.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.21.12...graphql-dynamodb-transformer@6.22.1) (2021-04-09) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.21.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.21.11...graphql-dynamodb-transformer@6.21.12) (2021-03-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.21.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.21.10...graphql-dynamodb-transformer@6.21.11) (2021-03-11) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.21.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.21.9...graphql-dynamodb-transformer@6.21.10) (2021-03-05) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.21.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.21.8...graphql-dynamodb-transformer@6.21.9) (2021-02-26) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.21.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.21.7...graphql-dynamodb-transformer@6.21.8) (2021-02-24) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.21.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.21.6...graphql-dynamodb-transformer@6.21.7) (2021-02-17) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.21.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.21.5...graphql-dynamodb-transformer@6.21.6) (2021-02-11) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.21.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.21.4...graphql-dynamodb-transformer@6.21.5) (2021-02-10) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.21.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.21.3...graphql-dynamodb-transformer@6.21.4) (2020-12-16) - -### Bug Fixes - -- **graphql-key-transformer:** prevent non-scalar key fields ([#5319](https://github.com/aws-amplify/amplify-cli/issues/5319)) ([4a5b305](https://github.com/aws-amplify/amplify-cli/commit/4a5b305dd695e61fcbc4ce0ca659b6f5a1c7e467)), closes [#5300](https://github.com/aws-amplify/amplify-cli/issues/5300) -- [#6108](https://github.com/aws-amplify/amplify-cli/issues/6108) - add proper AWSJSON mapping in generated filter input types ([#6112](https://github.com/aws-amplify/amplify-cli/issues/6112)) ([743e84a](https://github.com/aws-amplify/amplify-cli/commit/743e84a9d968aab4648a12d3a19aa5ea14c4d755)) - -### Reverts - -- Revert "Revert "Revert "fix: #6108 - add proper AWSJSON mapping in generated filter input types (#6112)" (#6158)" (#6160)" (#6183) ([a0ca94e](https://github.com/aws-amplify/amplify-cli/commit/a0ca94e5a1a848404ef3977743f19d26300a636a)), closes [#6108](https://github.com/aws-amplify/amplify-cli/issues/6108) [#6112](https://github.com/aws-amplify/amplify-cli/issues/6112) [#6158](https://github.com/aws-amplify/amplify-cli/issues/6158) [#6160](https://github.com/aws-amplify/amplify-cli/issues/6160) [#6183](https://github.com/aws-amplify/amplify-cli/issues/6183) -- Revert "fix(graphql-key-transformer): prevent non-scalar key fields (#5319)" (#6181) ([c61268d](https://github.com/aws-amplify/amplify-cli/commit/c61268d093571c906c13e7033552503b9fd83a98)), closes [#5319](https://github.com/aws-amplify/amplify-cli/issues/5319) [#6181](https://github.com/aws-amplify/amplify-cli/issues/6181) -- Revert "Revert "fix: #6108 - add proper AWSJSON mapping in generated filter input types (#6112)" (#6158)" (#6160) ([f425924](https://github.com/aws-amplify/amplify-cli/commit/f42592420dcb49640c680c5001b3026ae0129090)), closes [#6108](https://github.com/aws-amplify/amplify-cli/issues/6108) [#6112](https://github.com/aws-amplify/amplify-cli/issues/6112) [#6158](https://github.com/aws-amplify/amplify-cli/issues/6158) [#6160](https://github.com/aws-amplify/amplify-cli/issues/6160) -- Revert "fix: #6108 - add proper AWSJSON mapping in generated filter input types (#6112)" (#6158) ([9e57e4d](https://github.com/aws-amplify/amplify-cli/commit/9e57e4d8c887be8ee4119c87383c7379cec40c37)), closes [#6108](https://github.com/aws-amplify/amplify-cli/issues/6108) [#6112](https://github.com/aws-amplify/amplify-cli/issues/6112) [#6158](https://github.com/aws-amplify/amplify-cli/issues/6158) - -## [6.21.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.21.2...graphql-dynamodb-transformer@6.21.3) (2020-12-07) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.21.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.21.1...graphql-dynamodb-transformer@6.21.2) (2020-11-30) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.21.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.20.0...graphql-dynamodb-transformer@6.21.1) (2020-11-22) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -# [6.21.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.8.5...graphql-dynamodb-transformer@6.21.0) (2020-11-22) - -### Bug Fixes - -- [#4944](https://github.com/aws-amplify/amplify-cli/issues/4944), [#5332](https://github.com/aws-amplify/amplify-cli/issues/5332) ([#5431](https://github.com/aws-amplify/amplify-cli/issues/5431)) ([6104bde](https://github.com/aws-amplify/amplify-cli/commit/6104bde76533614cd41bd0d97aaad06660275add)) -- **graphql-dynamodb-transformer:** support model without id ([#4570](https://github.com/aws-amplify/amplify-cli/issues/4570)) ([7cb0648](https://github.com/aws-amplify/amplify-cli/commit/7cb064874d95527882eb58b1a18fa99dd2377ca7)) -- [#3438](https://github.com/aws-amplify/amplify-cli/issues/3438), many-to-many with conflict resolution generated wrong schema ([#4171](https://github.com/aws-amplify/amplify-cli/issues/4171)) ([9e8606c](https://github.com/aws-amplify/amplify-cli/commit/9e8606c4a300b5690839ec0869f7384aff189b1f)) -- add custom enum filter to connection filter ([#4269](https://github.com/aws-amplify/amplify-cli/issues/4269)) ([f559df0](https://github.com/aws-amplify/amplify-cli/commit/f559df077015c1c8d8462a92968093efdc5b9452)) -- **graphql-dynamodb-transformer:** fixes long IAM roleNames ([#4010](https://github.com/aws-amplify/amplify-cli/issues/4010)) ([041e97a](https://github.com/aws-amplify/amplify-cli/commit/041e97a182a13711d74c27fd5229c7b4d6fb237f)) -- build break, chore: typescript, lerna update ([#2640](https://github.com/aws-amplify/amplify-cli/issues/2640)) ([29fae36](https://github.com/aws-amplify/amplify-cli/commit/29fae366f4cab054feefa58c7dc733002d19570c)) -- export Typescript definitions and fix resulting type errors ([#2452](https://github.com/aws-amplify/amplify-cli/issues/2452)) ([7de3845](https://github.com/aws-amplify/amplify-cli/commit/7de384594d3b9cbf22cdaa85107fc8df26c141ec)), closes [#2451](https://github.com/aws-amplify/amplify-cli/issues/2451) -- github partial rename for sync query constant ([#4125](https://github.com/aws-amplify/amplify-cli/issues/4125)) ([506c48a](https://github.com/aws-amplify/amplify-cli/commit/506c48aabdc2825935f006b025cea59583c21572)) -- **graphql-dynamodb-transformer:** fix [#3141](https://github.com/aws-amplify/amplify-cli/issues/3141) add attribute type enum for queries ([#3930](https://github.com/aws-amplify/amplify-cli/issues/3930)) ([1a151b3](https://github.com/aws-amplify/amplify-cli/commit/1a151b3b98c70d3b3adbccc90e619c34378785ed)) -- **graphql-dynamodb-transformer:** prevent doble escape of nextToken ([#3452](https://github.com/aws-amplify/amplify-cli/issues/3452)) ([b6decfd](https://github.com/aws-amplify/amplify-cli/commit/b6decfddf232ed8a1d8b3e51ad881bc083b45114)), closes [#3411](https://github.com/aws-amplify/amplify-cli/issues/3411) -- sanitize input in transformer resolver([#3316](https://github.com/aws-amplify/amplify-cli/issues/3316)) ([a3bc0a5](https://github.com/aws-amplify/amplify-cli/commit/a3bc0a5e5d3faa7946d16d0f6595ce8c2f3c11dc)) -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) -- **graphql-dynamodb-transformer:** added scan index forward ([72cda1e](https://github.com/aws-amplify/amplify-cli/commit/72cda1e178b2fd87e42b200efbc5c87e49c964b1)), closes [#1676](https://github.com/aws-amplify/amplify-cli/issues/1676) -- **graphql-dynamodb-transformer:** allow id for non model objects ([#2530](https://github.com/aws-amplify/amplify-cli/issues/2530)) ([0d3c849](https://github.com/aws-amplify/amplify-cli/commit/0d3c849002917016cbffcba7ac22de9538f83acc)), closes [#1984](https://github.com/aws-amplify/amplify-cli/issues/1984) [#1984](https://github.com/aws-amplify/amplify-cli/issues/1984) -- **graphql-dynamodb-transformer:** fix cloudformation error config ([#2772](https://github.com/aws-amplify/amplify-cli/issues/2772)) ([10ca188](https://github.com/aws-amplify/amplify-cli/commit/10ca188703c71262a90b687ab758323bd2ef7f88)) - -### Features - -- ff to turn off schema reserve word validation ([#5745](https://github.com/aws-amplify/amplify-cli/issues/5745)) ([de79514](https://github.com/aws-amplify/amplify-cli/commit/de79514c18bea7236a05f0658513b95318501d16)) -- **amplify-category-api:** change default graphql query limit to 100 ([#4124](https://github.com/aws-amplify/amplify-cli/issues/4124)) ([1a68c4d](https://github.com/aws-amplify/amplify-cli/commit/1a68c4d589e2101357dec4e980719fc547964e23)) -- **amplify-category-function:** refactor to support runtime and template plugins ([#3517](https://github.com/aws-amplify/amplify-cli/issues/3517)) ([607ae21](https://github.com/aws-amplify/amplify-cli/commit/607ae21287941805f44ea8a9b78dd12d16d71f85)) -- **graphql-dynamodb-transformer:** expose createdAt and updatedAt on model ([#4149](https://github.com/aws-amplify/amplify-cli/issues/4149)) ([8e0662e](https://github.com/aws-amplify/amplify-cli/commit/8e0662eac8c88da9393f32c33457a597acf591ed)), closes [#401](https://github.com/aws-amplify/amplify-cli/issues/401) -- **graphql-key-transformer:** auto population of id and timestamp ([#4382](https://github.com/aws-amplify/amplify-cli/issues/4382)) ([6586611](https://github.com/aws-amplify/amplify-cli/commit/6586611293a07db9959247ff82f95542a239ff1f)) -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c1927da10f8c54f38a523021187361131c)) -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- implement multi-auth functionality ([#1916](https://github.com/aws-amplify/amplify-cli/issues/1916)) ([b99f58e](https://github.com/aws-amplify/amplify-cli/commit/b99f58e4a2b85cbe9f430838554ae3c277440132)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe8925a4e73358b03ba927267a2df328b78)) -- updated version of [#2118](https://github.com/aws-amplify/amplify-cli/issues/2118) with addressed review comments ([#2230](https://github.com/aws-amplify/amplify-cli/issues/2230)) ([be3c499](https://github.com/aws-amplify/amplify-cli/commit/be3c499edcc6bec63b38e9241c5af7b83c930022)) - -* Adding Auth on Subscriptions (#2068) ([81c630d](https://github.com/aws-amplify/amplify-cli/commit/81c630d782a6be720e513677a34b7a7dacbdc629)), closes [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) - -### BREAKING CHANGES - -- If an owner is used in the auth directive it will either be a requirement if it's - the only rule or an optional input if used with other rules -- If an owner is included in the auth directive it will either be a requirement if - it's the only rule or an optional input if used with other rules -- the subscription operations will require an argument if owner is the only auth rule -- Subscriptions will require an argument if an owner is only rule set - If owner & - group rules are owner will be an optional arg - -## [6.20.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.20.0...graphql-dynamodb-transformer@6.20.3) (2020-11-20) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.20.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.20.0...graphql-dynamodb-transformer@6.20.2) (2020-11-20) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.20.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.20.0...graphql-dynamodb-transformer@6.20.1) (2020-11-19) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -# [6.20.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.17...graphql-dynamodb-transformer@6.20.0) (2020-11-08) - -### Features - -- ff to turn off schema reserve word validation ([#5745](https://github.com/aws-amplify/amplify-cli/issues/5745)) ([de79514](https://github.com/aws-amplify/amplify-cli/commit/de79514c18bea7236a05f0658513b95318501d16)) - -## [6.19.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.16...graphql-dynamodb-transformer@6.19.17) (2020-10-30) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.19.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.15...graphql-dynamodb-transformer@6.19.16) (2020-10-22) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.19.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.14...graphql-dynamodb-transformer@6.19.15) (2020-10-17) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.19.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.13...graphql-dynamodb-transformer@6.19.14) (2020-10-01) - -### Bug Fixes - -- [#4944](https://github.com/aws-amplify/amplify-cli/issues/4944), [#5332](https://github.com/aws-amplify/amplify-cli/issues/5332) ([#5431](https://github.com/aws-amplify/amplify-cli/issues/5431)) ([6104bde](https://github.com/aws-amplify/amplify-cli/commit/6104bde76533614cd41bd0d97aaad06660275add)) - -## [6.19.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.12...graphql-dynamodb-transformer@6.19.13) (2020-09-16) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.19.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.11...graphql-dynamodb-transformer@6.19.12) (2020-09-02) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** support model without id ([#4570](https://github.com/aws-amplify/amplify-cli/issues/4570)) ([7cb0648](https://github.com/aws-amplify/amplify-cli/commit/7cb064874d95527882eb58b1a18fa99dd2377ca7)) - -## [6.19.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.10...graphql-dynamodb-transformer@6.19.11) (2020-08-31) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.19.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.9...graphql-dynamodb-transformer@6.19.10) (2020-08-14) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.19.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.8...graphql-dynamodb-transformer@6.19.9) (2020-08-11) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.19.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.6...graphql-dynamodb-transformer@6.19.8) (2020-07-29) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.19.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.6...graphql-dynamodb-transformer@6.19.7) (2020-07-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.19.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.5...graphql-dynamodb-transformer@6.19.6) (2020-07-18) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.19.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.4...graphql-dynamodb-transformer@6.19.5) (2020-07-15) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.19.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.3...graphql-dynamodb-transformer@6.19.4) (2020-06-25) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.19.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.2...graphql-dynamodb-transformer@6.19.3) (2020-06-18) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.19.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.1...graphql-dynamodb-transformer@6.19.2) (2020-06-11) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.19.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.19.0...graphql-dynamodb-transformer@6.19.1) (2020-06-10) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -# [6.19.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.18.1...graphql-dynamodb-transformer@6.19.0) (2020-06-02) - -### Bug Fixes - -- add custom enum filter to connection filter ([#4269](https://github.com/aws-amplify/amplify-cli/issues/4269)) ([a29d427](https://github.com/aws-amplify/amplify-cli/commit/a29d427dc23f82f04d4e7b79402dd9642591e759)) - -### Features - -- **graphql-key-transformer:** auto population of id and timestamp ([#4382](https://github.com/aws-amplify/amplify-cli/issues/4382)) ([c0a4f88](https://github.com/aws-amplify/amplify-cli/commit/c0a4f8889fc363bb9c9d08ff822c591874777f7b)) - -## [6.18.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.18.0...graphql-dynamodb-transformer@6.18.1) (2020-05-26) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -# [6.18.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.17.0...graphql-dynamodb-transformer@6.18.0) (2020-05-15) - -### Features - -- **graphql-dynamodb-transformer:** expose createdAt and updatedAt on model ([#4149](https://github.com/aws-amplify/amplify-cli/issues/4149)) ([8e0662e](https://github.com/aws-amplify/amplify-cli/commit/8e0662eac8c88da9393f32c33457a597acf591ed)), closes [#401](https://github.com/aws-amplify/amplify-cli/issues/401) - -# [6.17.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.16.1...graphql-dynamodb-transformer@6.17.0) (2020-05-08) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** fixes long IAM roleNames ([#4010](https://github.com/aws-amplify/amplify-cli/issues/4010)) ([041e97a](https://github.com/aws-amplify/amplify-cli/commit/041e97a182a13711d74c27fd5229c7b4d6fb237f)) -- [#3438](https://github.com/aws-amplify/amplify-cli/issues/3438), many-to-many with conflict resolution generated wrong schema ([#4171](https://github.com/aws-amplify/amplify-cli/issues/4171)) ([9e8606c](https://github.com/aws-amplify/amplify-cli/commit/9e8606c4a300b5690839ec0869f7384aff189b1f)) -- github partial rename for sync query constant ([#4125](https://github.com/aws-amplify/amplify-cli/issues/4125)) ([506c48a](https://github.com/aws-amplify/amplify-cli/commit/506c48aabdc2825935f006b025cea59583c21572)) - -### Features - -- **amplify-category-api:** change default graphql query limit to 100 ([#4124](https://github.com/aws-amplify/amplify-cli/issues/4124)) ([1a68c4d](https://github.com/aws-amplify/amplify-cli/commit/1a68c4d589e2101357dec4e980719fc547964e23)) - -## [6.16.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.16.0...graphql-dynamodb-transformer@6.16.1) (2020-04-23) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** fix [#3141](https://github.com/aws-amplify/amplify-cli/issues/3141) add attribute type enum for queries ([#3930](https://github.com/aws-amplify/amplify-cli/issues/3930)) ([1a151b3](https://github.com/aws-amplify/amplify-cli/commit/1a151b3b98c70d3b3adbccc90e619c34378785ed)) - -# [6.16.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.15.1...graphql-dynamodb-transformer@6.16.0) (2020-03-22) - -### Features - -- **amplify-category-function:** refactor to support runtime and template plugins ([#3517](https://github.com/aws-amplify/amplify-cli/issues/3517)) ([607ae21](https://github.com/aws-amplify/amplify-cli/commit/607ae21287941805f44ea8a9b78dd12d16d71f85)) - -## [6.15.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.13.4...graphql-dynamodb-transformer@6.15.1) (2020-03-07) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.14.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.13.6-beta.0...graphql-dynamodb-transformer@6.14.1) (2020-03-05) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.13.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.13.3...graphql-dynamodb-transformer@6.13.4) (2020-02-18) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** prevent doble escape of nextToken ([#3452](https://github.com/aws-amplify/amplify-cli/issues/3452)) ([b6decfd](https://github.com/aws-amplify/amplify-cli/commit/b6decfddf232ed8a1d8b3e51ad881bc083b45114)), closes [#3411](https://github.com/aws-amplify/amplify-cli/issues/3411) - -## [6.13.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.13.2...graphql-dynamodb-transformer@6.13.3) (2020-02-13) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [6.13.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.13.1...graphql-dynamodb-transformer@6.13.2) (2020-02-07) - -### Bug Fixes - -- sanitize input in transformer resolver([#3316](https://github.com/aws-amplify/amplify-cli/issues/3316)) ([a3bc0a5](https://github.com/aws-amplify/amplify-cli/commit/a3bc0a5e5d3faa7946d16d0f6595ce8c2f3c11dc)) - -## [6.13.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@6.13.0...graphql-dynamodb-transformer@6.13.1) (2020-01-24) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -# [6.13.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@5.18.0...graphql-dynamodb-transformer@6.13.0) (2020-01-23) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** fix cloudformation error config ([#2772](https://github.com/aws-amplify/amplify-cli/issues/2772)) ([10ca188](https://github.com/aws-amplify/amplify-cli/commit/10ca188703c71262a90b687ab758323bd2ef7f88)) -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.12.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@5.18.0...graphql-dynamodb-transformer@6.12.0) (2020-01-09) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** fix cloudformation error config ([#2772](https://github.com/aws-amplify/amplify-cli/issues/2772)) ([10ca188](https://github.com/aws-amplify/amplify-cli/commit/10ca188703c71262a90b687ab758323bd2ef7f88)) -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.11.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@5.18.0...graphql-dynamodb-transformer@6.11.0) (2019-12-31) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** fix cloudformation error config ([#2772](https://github.com/aws-amplify/amplify-cli/issues/2772)) ([10ca188](https://github.com/aws-amplify/amplify-cli/commit/10ca188703c71262a90b687ab758323bd2ef7f88)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.10.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@5.18.0...graphql-dynamodb-transformer@6.10.0) (2019-12-28) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** fix cloudformation error config ([#2772](https://github.com/aws-amplify/amplify-cli/issues/2772)) ([10ca188](https://github.com/aws-amplify/amplify-cli/commit/10ca188703c71262a90b687ab758323bd2ef7f88)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.9.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@5.18.0...graphql-dynamodb-transformer@6.9.0) (2019-12-26) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** fix cloudformation error config ([#2772](https://github.com/aws-amplify/amplify-cli/issues/2772)) ([10ca188](https://github.com/aws-amplify/amplify-cli/commit/10ca188703c71262a90b687ab758323bd2ef7f88)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.8.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@5.18.0...graphql-dynamodb-transformer@6.8.0) (2019-12-25) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** fix cloudformation error config ([#2772](https://github.com/aws-amplify/amplify-cli/issues/2772)) ([10ca188](https://github.com/aws-amplify/amplify-cli/commit/10ca188703c71262a90b687ab758323bd2ef7f88)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.7.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@5.18.0...graphql-dynamodb-transformer@6.7.0) (2019-12-20) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** fix cloudformation error config ([#2772](https://github.com/aws-amplify/amplify-cli/issues/2772)) ([10ca188](https://github.com/aws-amplify/amplify-cli/commit/10ca188703c71262a90b687ab758323bd2ef7f88)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.6.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@5.18.0...graphql-dynamodb-transformer@6.6.0) (2019-12-10) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** fix cloudformation error config ([#2772](https://github.com/aws-amplify/amplify-cli/issues/2772)) ([10ca188](https://github.com/aws-amplify/amplify-cli/commit/10ca188703c71262a90b687ab758323bd2ef7f88)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.4.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@5.18.0...graphql-dynamodb-transformer@6.4.0) (2019-12-03) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** fix cloudformation error config ([#2772](https://github.com/aws-amplify/amplify-cli/issues/2772)) ([10ca188](https://github.com/aws-amplify/amplify-cli/commit/10ca188703c71262a90b687ab758323bd2ef7f88)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.3.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@5.18.0...graphql-dynamodb-transformer@6.3.0) (2019-12-01) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** fix cloudformation error config ([#2772](https://github.com/aws-amplify/amplify-cli/issues/2772)) ([10ca188](https://github.com/aws-amplify/amplify-cli/commit/10ca188703c71262a90b687ab758323bd2ef7f88)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.2.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@5.18.0...graphql-dynamodb-transformer@6.2.0) (2019-11-27) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** fix cloudformation error config ([#2772](https://github.com/aws-amplify/amplify-cli/issues/2772)) ([10ca188](https://github.com/aws-amplify/amplify-cli/commit/10ca188703c71262a90b687ab758323bd2ef7f88)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [6.1.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@5.18.0...graphql-dynamodb-transformer@6.1.0) (2019-11-27) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** fix cloudformation error config ([#2772](https://github.com/aws-amplify/amplify-cli/issues/2772)) ([10ca188](https://github.com/aws-amplify/amplify-cli/commit/10ca188703c71262a90b687ab758323bd2ef7f88)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [5.0.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.8.5...graphql-dynamodb-transformer@5.0.0) (2019-08-30) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** added scan index forward ([72cda1e](https://github.com/aws-amplify/amplify-cli/commit/72cda1e)), closes [#1676](https://github.com/aws-amplify/amplify-cli/issues/1676) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -* Adding Auth on Subscriptions (#2068) ([81c630d](https://github.com/aws-amplify/amplify-cli/commit/81c630d)), closes [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) - -### BREAKING CHANGES - -- If an owner is used in the auth directive it will either be a requirement if it's - the only rule or an optional input if used with other rules -- If an owner is included in the auth directive it will either be a requirement if - it's the only rule or an optional input if used with other rules -- the subscription operations will require an argument if owner is the only auth rule -- Subscriptions will require an argument if an owner is only rule set - If owner & - group rules are owner will be an optional arg - -# [4.0.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.8.5...graphql-dynamodb-transformer@4.0.0) (2019-08-28) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** added scan index forward ([72cda1e](https://github.com/aws-amplify/amplify-cli/commit/72cda1e)), closes [#1676](https://github.com/aws-amplify/amplify-cli/issues/1676) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -* Adding Auth on Subscriptions (#2068) ([81c630d](https://github.com/aws-amplify/amplify-cli/commit/81c630d)), closes [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) - -### BREAKING CHANGES - -- If an owner is used in the auth directive it will either be a requirement if it's - the only rule or an optional input if used with other rules -- If an owner is included in the auth directive it will either be a requirement if - it's the only rule or an optional input if used with other rules -- the subscription operations will require an argument if owner is the only auth rule -- Subscriptions will require an argument if an owner is only rule set - If owner & - group rules are owner will be an optional arg - -# [3.12.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.8.5...graphql-dynamodb-transformer@3.12.0) (2019-08-13) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** added scan index forward ([72cda1e](https://github.com/aws-amplify/amplify-cli/commit/72cda1e)), closes [#1676](https://github.com/aws-amplify/amplify-cli/issues/1676) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [3.11.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.8.5...graphql-dynamodb-transformer@3.11.0) (2019-08-07) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [3.10.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.8.5...graphql-dynamodb-transformer@3.10.0) (2019-08-02) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [3.9.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.8.5...graphql-dynamodb-transformer@3.9.0) (2019-07-31) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -## [3.8.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.8.4...graphql-dynamodb-transformer@3.8.5) (2019-07-24) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [3.8.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.8.2...graphql-dynamodb-transformer@3.8.4) (2019-06-30) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [3.8.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.8.1...graphql-dynamodb-transformer@3.8.2) (2019-06-26) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [3.8.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.8.0...graphql-dynamodb-transformer@3.8.1) (2019-06-12) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -# [3.8.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.7.0...graphql-dynamodb-transformer@3.8.0) (2019-05-29) - -### Features - -- feature/[@key](https://github.com/key) ([#1463](https://github.com/aws-amplify/amplify-cli/issues/1463)) ([00ed819](https://github.com/aws-amplify/amplify-cli/commit/00ed819)) - -# [3.7.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.6.1...graphql-dynamodb-transformer@3.7.0) (2019-05-21) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** backward compatibility ([de3e47c](https://github.com/aws-amplify/amplify-cli/commit/de3e47c)) - -### Features - -- **graphql-dynamodb-transformer:** add more specific mapping ([5dc2d3b](https://github.com/aws-amplify/amplify-cli/commit/5dc2d3b)) -- **graphql-dynamodb-transformer:** always output stream arn ([df1712b](https://github.com/aws-amplify/amplify-cli/commit/df1712b)), closes [#980](https://github.com/aws-amplify/amplify-cli/issues/980) - -## [3.6.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.6.0...graphql-dynamodb-transformer@3.6.1) (2019-05-17) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** always output datasource name ([#1182](https://github.com/aws-amplify/amplify-cli/issues/1182)) ([a58e1ac](https://github.com/aws-amplify/amplify-cli/commit/a58e1ac)) - -# [3.6.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.4.2...graphql-dynamodb-transformer@3.6.0) (2019-05-07) - -### Features - -- **graphql-dynamodb-transformer:** output table name ([#1215](https://github.com/aws-amplify/amplify-cli/issues/1215)) ([038b876](https://github.com/aws-amplify/amplify-cli/commit/038b876)), closes [#1145](https://github.com/aws-amplify/amplify-cli/issues/1145) [#1145](https://github.com/aws-amplify/amplify-cli/issues/1145) - -# [3.5.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.4.2...graphql-dynamodb-transformer@3.5.0) (2019-05-06) - -### Features - -- **graphql-dynamodb-transformer:** output table name ([#1215](https://github.com/aws-amplify/amplify-cli/issues/1215)) ([038b876](https://github.com/aws-amplify/amplify-cli/commit/038b876)), closes [#1145](https://github.com/aws-amplify/amplify-cli/issues/1145) [#1145](https://github.com/aws-amplify/amplify-cli/issues/1145) - -## [3.4.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.4.1...graphql-dynamodb-transformer@3.4.2) (2019-04-16) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [3.4.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.3.1...graphql-dynamodb-transformer@3.4.1) (2019-04-09) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [3.3.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.0.9...graphql-dynamodb-transformer@3.3.1) (2019-04-03) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [3.0.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.0.8...graphql-dynamodb-transformer@3.0.9) (2019-03-22) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [3.0.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.0.7...graphql-dynamodb-transformer@3.0.8) (2019-03-05) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [3.0.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.0.6...graphql-dynamodb-transformer@3.0.7) (2019-02-20) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** generate filters for connection ([#889](https://github.com/aws-amplify/amplify-cli/issues/889)) ([166d12c](https://github.com/aws-amplify/amplify-cli/commit/166d12c)), closes [#865](https://github.com/aws-amplify/amplify-cli/issues/865) - -## [3.0.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.0.5...graphql-dynamodb-transformer@3.0.6) (2019-02-12) - -### Bug Fixes - -- cloudform/type versions ([ec6f99f](https://github.com/aws-amplify/amplify-cli/commit/ec6f99f)) - -## [3.0.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.0.3-beta.0...graphql-dynamodb-transformer@3.0.5) (2019-02-11) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [3.0.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.0.3-beta.0...graphql-dynamodb-transformer@3.0.3) (2019-02-11) - -**Note:** Version bump only for package graphql-dynamodb-transformer - -## [3.0.3-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@3.0.2...graphql-dynamodb-transformer@3.0.3-beta.0) (2019-02-11) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -# [2.0.0-multienv.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.34-multienv.1...graphql-dynamodb-transformer@2.0.0-multienv.2) (2018-12-31) - -### Bug Fixes - -- update grahql transformer package versions for multienv ([8b4b2bd](https://github.com/aws-amplify/amplify-cli/commit/8b4b2bd)) - - - -## [1.0.34-multienv.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.34-multienv.0...graphql-dynamodb-transformer@1.0.34-multienv.1) (2018-12-19) - -### Bug Fixes - -- **amplify-category-api:** Updating dependsOn for certain resources ([#597](https://github.com/aws-amplify/amplify-cli/issues/597)) ([7a8f5f7](https://github.com/aws-amplify/amplify-cli/commit/7a8f5f7)) - - - -## [1.0.34-multienv.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.33...graphql-dynamodb-transformer@1.0.34-multienv.0) (2018-11-16) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.33](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.33-beta.0...graphql-dynamodb-transformer@1.0.33) (2018-11-09) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.33-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.12...graphql-dynamodb-transformer@1.0.33-beta.0) (2018-11-09) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.32](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.32-beta.0...graphql-dynamodb-transformer@1.0.32) (2018-11-05) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.32-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.12...graphql-dynamodb-transformer@1.0.32-beta.0) (2018-11-05) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.31](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.12...graphql-dynamodb-transformer@1.0.31) (2018-11-02) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.30](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.30-beta.0...graphql-dynamodb-transformer@1.0.30) (2018-11-02) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.30-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.12...graphql-dynamodb-transformer@1.0.30-beta.0) (2018-11-02) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.29](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.29-beta.0...graphql-dynamodb-transformer@1.0.29) (2018-10-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.29-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.12...graphql-dynamodb-transformer@1.0.29-beta.0) (2018-10-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.28](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.28-beta.0...graphql-dynamodb-transformer@1.0.28) (2018-10-18) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.28-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.12...graphql-dynamodb-transformer@1.0.28-beta.0) (2018-10-12) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.11...graphql-dynamodb-transformer@1.0.12) (2018-08-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.10...graphql-dynamodb-transformer@1.0.11) (2018-08-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.9...graphql-dynamodb-transformer@1.0.10) (2018-08-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.8...graphql-dynamodb-transformer@1.0.9) (2018-08-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.7...graphql-dynamodb-transformer@1.0.8) (2018-08-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.6...graphql-dynamodb-transformer@1.0.7) (2018-08-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.5...graphql-dynamodb-transformer@1.0.6) (2018-08-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## [1.0.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-dynamodb-transformer@1.0.4...graphql-dynamodb-transformer@1.0.5) (2018-08-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## 1.0.4 (2018-08-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## 1.0.3 (2018-08-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## 1.0.2 (2018-08-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer - - - -## 1.0.1 (2018-08-23) - -**Note:** Version bump only for package graphql-dynamodb-transformer diff --git a/packages/graphql-dynamodb-transformer/package.json b/packages/graphql-dynamodb-transformer/package.json deleted file mode 100644 index 1ab15e2466..0000000000 --- a/packages/graphql-dynamodb-transformer/package.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "name": "graphql-dynamodb-transformer", - "version": "7.2.80", - "description": "An AppSync model transform that takes a simple model and creates a DynamoDB table, DynamoDB stream.", - "repository": { - "type": "git", - "url": "https://github.com/aws-amplify/amplify-category-api.git", - "directory": "packages/graphql-dynamodb-transformer" - }, - "author": "Amazon Web Services", - "license": "Apache-2.0", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "keywords": [ - "graphql", - "appsync", - "aws" - ], - "scripts": { - "test": "jest", - "build": "tsc", - "clean": "rimraf ./lib", - "watch": "tsc -w", - "extract-api": "ts-node ../../scripts/extract-api.ts" - }, - "dependencies": { - "@types/pluralize": "^0.0.29", - "cloudform-types": "^4.2.0", - "graphql": "^15.5.0", - "graphql-mapping-template": "4.20.16", - "graphql-transformer-common": "4.31.1", - "graphql-transformer-core": "8.2.13", - "md5": "^2.2.1", - "pluralize": "^8.0.0" - }, - "devDependencies": { - "@types/md5": "^2.3.1" - }, - "jest": { - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, - "testURL": "http://localhost", - "testRegex": "(src/__tests__/.*.test.ts)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], - "collectCoverage": true, - "coverageProvider": "v8", - "coverageThreshold": { - "global": { - "branches": 68, - "functions": 77, - "lines": 81 - } - }, - "coverageReporters": [ - "clover", - "text" - ], - "collectCoverageFrom": [ - "src/**/*.ts" - ], - "coveragePathIgnorePatterns": [ - "/__tests__/" - ] - } -} diff --git a/packages/graphql-dynamodb-transformer/src/DynamoDBModelTransformer.ts b/packages/graphql-dynamodb-transformer/src/DynamoDBModelTransformer.ts deleted file mode 100644 index c5ddf4aa3e..0000000000 --- a/packages/graphql-dynamodb-transformer/src/DynamoDBModelTransformer.ts +++ /dev/null @@ -1,745 +0,0 @@ -import { DeletionPolicy, AppSync } from 'cloudform-types'; -import { DirectiveNode, ObjectTypeDefinitionNode, InputObjectTypeDefinitionNode, FieldDefinitionNode, parse } from 'graphql'; -import { - blankObject, - makeConnectionField, - makeField, - makeInputValueDefinition, - wrapNonNull, - makeNamedType, - makeNonNullType, - ModelResourceIDs, - ResolverResourceIDs, - getBaseType, -} from 'graphql-transformer-common'; -import { getDirectiveArguments, Transformer, TransformerContext, SyncConfig, InvalidDirectiveError } from 'graphql-transformer-core'; -import { ModelDirectiveV1 } from '@aws-amplify/graphql-directives'; -import { - getNonModelObjectArray, - makeCreateInputObject, - makeDeleteInputObject, - makeEnumFilterInputObjects, - makeModelConnectionType, - makeModelSortDirectionEnumObject, - makeModelXFilterInputObject, - makeNonModelInputObject, - makeScalarFilterInputs, - makeSubscriptionField, - makeUpdateInputObject, - makeModelXConditionInputObject, - makeAttributeTypeEnum, - getFieldsOptionalNonNullableField, -} from './definitions'; -import { ModelDirectiveArgs, getCreatedAtFieldName, getUpdatedAtFieldName } from './ModelDirectiveArgs'; -import { ResourceFactory } from './resources'; - -const METADATA_KEY = 'DynamoDBTransformerMetadata'; - -export interface DynamoDBModelTransformerOptions { - EnableDeletionProtection?: boolean; - SyncConfig?: SyncConfig; -} - -// Transform config version constants -// We have constants instead of magic number all around, later these should be moved to feature -// flags and transformers should be feature and not version dependent - -// To support generation of conditions and new naming, version 5 was introduced -export const CONDITIONS_MINIMUM_VERSION = 5; - -/** - * The @model transformer. - * - * This transform creates a single DynamoDB table for all of your application's - * data. It uses a standard key structure and nested map to store object values. - * A relationKey field - * - * { - * type (HASH), - * id (SORT), - * value (MAP), - * createdAt, (LSI w/ type) - * updatedAt (LSI w/ type) - * } - */ - -export const directiveDefinition = parse(ModelDirectiveV1.definition); - -export class DynamoDBModelTransformer extends Transformer { - resources: ResourceFactory; - - opts: DynamoDBModelTransformerOptions; - - constructor(opts: DynamoDBModelTransformerOptions = {}) { - super('DynamoDBModelTransformer', directiveDefinition); - this.opts = this.getOpts(opts); - this.resources = new ResourceFactory(); - } - - public before = (ctx: TransformerContext): void => { - const template = this.resources.initTemplate(); - ctx.mergeResources(template.Resources); - ctx.mergeParameters(template.Parameters); - ctx.mergeOutputs(template.Outputs); - ctx.mergeConditions(template.Conditions); - }; - - public after = (ctx: TransformerContext): void => { - // append hoisted initalization code to the top of request mapping template - const ddbMetata = ctx.metadata.get(METADATA_KEY); - if (ddbMetata) { - Object.entries(ddbMetata.hoistedRequestMappingContent || {}).forEach( - ([resourceId, hoistedContentGenerator]: [string, () => string | void]) => { - const hoistedContent = hoistedContentGenerator(); - if (hoistedContent) { - const resource: AppSync.Resolver = ctx.getResource(resourceId) as any; - resource.Properties.RequestMappingTemplate = [hoistedContent, resource.Properties.RequestMappingTemplate].join('\n'); - ctx.setResource(resourceId, resource); - } - }, - ); - } - }; - - /** - * Given the initial input and context manipulate the context to handle this object directive. - * @param initial The input passed to the transform. - * @param ctx The accumulated context for the transform. - */ - public object = (def: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext): void => { - const isTypeNameReserved = - def.name.value === ctx.getQueryTypeName() || - def.name.value === ctx.getMutationTypeName() || - def.name.value === ctx.getSubscriptionTypeName(); - - if (isTypeNameReserved && ctx.featureFlags.getBoolean('validateTypeNameReservedWords', true)) { - throw new InvalidDirectiveError( - `'${def.name.value}' is a reserved type name and currently in use within the default schema element.`, - ); - } - - // Add a stack mapping so that all model resources are pulled - // into their own stack at the end of the transformation. - const stackName = def.name.value; - - const nonModelArray: ObjectTypeDefinitionNode[] = getNonModelObjectArray(def, ctx, new Map()); - - nonModelArray.forEach((value: ObjectTypeDefinitionNode) => { - const nonModelObject = makeNonModelInputObject(value, nonModelArray, ctx); - if (!this.typeExist(nonModelObject.name.value, ctx)) { - ctx.addInput(nonModelObject); - } - }); - - this.addIdField(def, directive, ctx); - - // Set Sync Config if it exists - - // Create the dynamodb table to hold the @model type - // TODO: Handle types with more than a single "id" hash key - const typeName = def.name.value; - this.setSyncConfig(ctx, typeName); - const isSyncEnabled = !!this.opts.SyncConfig; - const tableLogicalID = ModelResourceIDs.ModelTableResourceID(typeName); - const iamRoleLogicalID = ModelResourceIDs.ModelTableIAMRoleID(typeName); - const dataSourceRoleLogicalID = ModelResourceIDs.ModelTableDataSourceID(typeName); - const deletionPolicy = this.opts.EnableDeletionProtection ? DeletionPolicy.Retain : DeletionPolicy.Delete; - ctx.setResource(tableLogicalID, this.resources.makeModelTable(typeName, undefined, undefined, deletionPolicy, isSyncEnabled)); - ctx.mapResourceToStack(stackName, tableLogicalID); - ctx.setResource(iamRoleLogicalID, this.resources.makeIAMRole(typeName, this.opts.SyncConfig)); - ctx.mapResourceToStack(stackName, iamRoleLogicalID); - ctx.setResource( - dataSourceRoleLogicalID, - this.resources.makeDynamoDBDataSource(tableLogicalID, iamRoleLogicalID, typeName, isSyncEnabled), - ); - ctx.mapResourceToStack(stackName, dataSourceRoleLogicalID); - - const streamArnOutputId = `GetAtt${ModelResourceIDs.ModelTableStreamArn(typeName)}`; - ctx.setOutput( - // "GetAtt" is a backward compatibility addition to prevent breaking current deploys. - streamArnOutputId, - this.resources.makeTableStreamArnOutput(tableLogicalID), - ); - ctx.mapResourceToStack(stackName, streamArnOutputId); - - const datasourceOutputId = `GetAtt${dataSourceRoleLogicalID}Name`; - ctx.setOutput(datasourceOutputId, this.resources.makeDataSourceOutput(dataSourceRoleLogicalID)); - ctx.mapResourceToStack(stackName, datasourceOutputId); - - const tableNameOutputId = `GetAtt${tableLogicalID}Name`; - ctx.setOutput(tableNameOutputId, this.resources.makeTableNameOutput(tableLogicalID)); - ctx.mapResourceToStack(stackName, tableNameOutputId); - - this.createQueries(def, directive, ctx); - this.createMutations(def, directive, ctx, nonModelArray); - this.createSubscriptions(def, directive, ctx); - - // Update ModelXConditionInput type - this.updateMutationConditionInput(ctx, def); - - // change type to include sync related fields if sync is enabled - if (isSyncEnabled) { - const obj = ctx.getObject(def.name.value); - const newFields = [ - ...obj.fields, - makeField('_version', [], wrapNonNull(makeNamedType('Int'))), - makeField('_deleted', [], makeNamedType('Boolean')), - makeField('_lastChangedAt', [], wrapNonNull(makeNamedType('AWSTimestamp'))), - ]; - - const newObj = { - ...obj, - fields: newFields, - }; - - ctx.updateObject(newObj); - } - this.addTimestampFields(def, directive, ctx); - }; - - private addTimestampFields(def: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext): void { - const createdAtField = getCreatedAtFieldName(directive); - const updatedAtField = getUpdatedAtFieldName(directive); - const existingCreatedAtField = def.fields.find((f) => f.name.value === createdAtField); - const existingUpdatedAtField = def.fields.find((f) => f.name.value === updatedAtField); - // Todo: Consolidate how warnings are shown. Instead of printing them here, the invoker of transformer should get - // all the warnings together and decide how to render those warning - if (!DynamoDBModelTransformer.isTimestampCompatibleField(existingCreatedAtField)) { - console.log( - `${def.name.value}.${existingCreatedAtField.name.value} is of type ${getBaseType( - existingCreatedAtField.type, - )}. To support auto population change the type to AWSDateTime or String`, - ); - } - if (!DynamoDBModelTransformer.isTimestampCompatibleField(existingUpdatedAtField)) { - console.log( - `${def.name.value}.${existingUpdatedAtField.name.value} is of type ${getBaseType( - existingUpdatedAtField.type, - )}. To support auto population change the type to AWSDateTime or String`, - ); - } - const obj = ctx.getObject(def.name.value); - const newObj: ObjectTypeDefinitionNode = { - ...obj, - fields: [ - ...obj.fields, - ...(createdAtField && !existingCreatedAtField ? [makeField(createdAtField, [], wrapNonNull(makeNamedType('AWSDateTime')))] : []), // createdAt field - ...(updatedAtField && !existingUpdatedAtField ? [makeField(updatedAtField, [], wrapNonNull(makeNamedType('AWSDateTime')))] : []), // updated field - ], - }; - ctx.updateObject(newObj); - } - - // Add ID field to type when does not have id - private addIdField(def: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext): void { - const hasIdField = def.fields.find((f) => f.name.value === 'id'); - if (!hasIdField) { - const obj = ctx.getObject(def.name.value); - const newObj: ObjectTypeDefinitionNode = { - ...obj, - fields: [makeField('id', [], wrapNonNull(makeNamedType('ID'))), ...obj.fields], - }; - ctx.updateObject(newObj); - } - } - - private createMutations = ( - def: ObjectTypeDefinitionNode, - directive: DirectiveNode, - ctx: TransformerContext, - nonModelArray: ObjectTypeDefinitionNode[], - ) => { - const typeName = def.name.value; - const isSyncEnabled = !!this.opts.SyncConfig; - - const mutationFields = []; - // Get any name overrides provided by the user. If an empty map it provided - // then we do not generate those fields. - const directiveArguments: ModelDirectiveArgs = getDirectiveArguments(directive); - - // Configure mutations based on *mutations* argument - let shouldMakeCreate = true; - let shouldMakeUpdate = true; - let shouldMakeDelete = true; - let createFieldNameOverride = undefined; - let updateFieldNameOverride = undefined; - let deleteFieldNameOverride = undefined; - - // timestamp fields - const createdAtField = getCreatedAtFieldName(directive); - const updatedAtField = getUpdatedAtFieldName(directive); - - const existingCreatedAtField = def.fields.find((f) => f.name.value === createdAtField); - const existingUpdatedAtField = def.fields.find((f) => f.name.value === updatedAtField); - - // auto populate the timestamp field only if they are of AWSDateTime type - const timestampFields = { - createdAtField: DynamoDBModelTransformer.isTimestampCompatibleField(existingCreatedAtField) ? createdAtField : undefined, - updatedAtField: DynamoDBModelTransformer.isTimestampCompatibleField(existingUpdatedAtField) ? updatedAtField : undefined, - }; - - // Figure out which mutations to make and if they have name overrides - if (directiveArguments.mutations === null) { - shouldMakeCreate = false; - shouldMakeUpdate = false; - shouldMakeDelete = false; - } else if (directiveArguments.mutations) { - if (!directiveArguments.mutations.create) { - shouldMakeCreate = false; - } else { - createFieldNameOverride = directiveArguments.mutations.create; - } - if (!directiveArguments.mutations.update) { - shouldMakeUpdate = false; - } else { - updateFieldNameOverride = directiveArguments.mutations.update; - } - if (!directiveArguments.mutations.delete) { - shouldMakeDelete = false; - } else { - deleteFieldNameOverride = directiveArguments.mutations.delete; - } - } - - const conditionInputName = ModelResourceIDs.ModelConditionInputTypeName(typeName); - - // Create the mutations. - if (shouldMakeCreate) { - const createInput = makeCreateInputObject(def, directive, nonModelArray, ctx, isSyncEnabled); - if (!ctx.getType(createInput.name.value)) { - ctx.addInput(createInput); - } - const createResolver = this.resources.makeCreateResolver({ - type: def.name.value, - nameOverride: createFieldNameOverride, - syncConfig: this.opts.SyncConfig, - }); - const resourceId = ResolverResourceIDs.DynamoDBCreateResolverResourceID(typeName); - this.addInitalizationMetadata(ctx, resourceId, () => { - const inputObj = ctx.getType(createInput.name.value) as InputObjectTypeDefinitionNode; - if (inputObj) { - return this.resources.initalizeDefaultInputForCreateMutation(inputObj, timestampFields); - } - }); - - ctx.setResource(resourceId, createResolver); - ctx.mapResourceToStack(typeName, resourceId); - const args = [makeInputValueDefinition('input', makeNonNullType(makeNamedType(createInput.name.value)))]; - if (this.supportsConditions(ctx)) { - args.push(makeInputValueDefinition('condition', makeNamedType(conditionInputName))); - } - mutationFields.push(makeField(createResolver.Properties.FieldName.toString(), args, makeNamedType(def.name.value))); - } - - if (shouldMakeUpdate) { - const updateInput = makeUpdateInputObject(def, nonModelArray, ctx, isSyncEnabled); - const optionalNonNullableFields = getFieldsOptionalNonNullableField( - updateInput.fields.map((r) => r), - def, - ); - if (!ctx.getType(updateInput.name.value)) { - ctx.addInput(updateInput); - } - const updateResolver = this.resources.makeUpdateResolver({ - type: def.name.value, - nameOverride: updateFieldNameOverride, - syncConfig: this.opts.SyncConfig, - timestamps: timestampFields, - optionalNonNullableFields, - }); - const resourceId = ResolverResourceIDs.DynamoDBUpdateResolverResourceID(typeName); - ctx.setResource(resourceId, updateResolver); - ctx.mapResourceToStack(typeName, resourceId); - const args = [makeInputValueDefinition('input', makeNonNullType(makeNamedType(updateInput.name.value)))]; - if (this.supportsConditions(ctx)) { - args.push(makeInputValueDefinition('condition', makeNamedType(conditionInputName))); - } - mutationFields.push(makeField(updateResolver.Properties.FieldName.toString(), args, makeNamedType(def.name.value))); - } - - if (shouldMakeDelete) { - const deleteInput = makeDeleteInputObject(def, isSyncEnabled); - if (!ctx.getType(deleteInput.name.value)) { - ctx.addInput(deleteInput); - } - const deleteResolver = this.resources.makeDeleteResolver({ - type: def.name.value, - nameOverride: deleteFieldNameOverride, - syncConfig: this.opts.SyncConfig, - }); - const resourceId = ResolverResourceIDs.DynamoDBDeleteResolverResourceID(typeName); - ctx.setResource(resourceId, deleteResolver); - ctx.mapResourceToStack(typeName, resourceId); - const args = [makeInputValueDefinition('input', makeNonNullType(makeNamedType(deleteInput.name.value)))]; - if (this.supportsConditions(ctx)) { - args.push(makeInputValueDefinition('condition', makeNamedType(conditionInputName))); - } - mutationFields.push(makeField(deleteResolver.Properties.FieldName.toString(), args, makeNamedType(def.name.value))); - } - ctx.addMutationFields(mutationFields); - - if (shouldMakeCreate || shouldMakeUpdate || shouldMakeDelete) { - this.generateConditionInputs(ctx, def); - } - }; - - private createQueries = (def: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => { - const typeName = def.name.value; - const queryFields = []; - const directiveArguments: ModelDirectiveArgs = getDirectiveArguments(directive); - - // Configure queries based on *queries* argument - let shouldMakeGet = true; - let shouldMakeList = true; - let getFieldNameOverride = undefined; - let listFieldNameOverride = undefined; - const isSyncEnabled = !!this.opts.SyncConfig; - - // Figure out which queries to make and if they have name overrides. - // If queries is undefined (default), create all queries - // If queries is explicetly set to null, do not create any - // else if queries is defined, check overrides - if (directiveArguments.queries === null) { - shouldMakeGet = false; - shouldMakeList = false; - } else if (directiveArguments.queries) { - if (!directiveArguments.queries.get) { - shouldMakeGet = false; - } else { - getFieldNameOverride = directiveArguments.queries.get; - } - if (!directiveArguments.queries.list) { - shouldMakeList = false; - } else { - listFieldNameOverride = directiveArguments.queries.list; - } - } - - if (shouldMakeList) { - if (!this.typeExist('ModelSortDirection', ctx)) { - const tableSortDirection = makeModelSortDirectionEnumObject(); - ctx.addEnum(tableSortDirection); - } - } - - // Create sync query if @model present for datastore - if (isSyncEnabled) { - // change here for selective Sync for @model (Just add the queryMap for table and query expression) - const syncResolver = this.resources.makeSyncResolver(typeName); - const syncResourceID = ResolverResourceIDs.SyncResolverResourceID(typeName); - ctx.setResource(syncResourceID, syncResolver); - ctx.mapResourceToStack(typeName, syncResourceID); - this.generateModelXConnectionType(ctx, def, isSyncEnabled); - this.generateFilterInputs(ctx, def); - queryFields.push( - makeField( - syncResolver.Properties.FieldName.toString(), - [ - makeInputValueDefinition('filter', makeNamedType(ModelResourceIDs.ModelFilterInputTypeName(def.name.value))), - makeInputValueDefinition('limit', makeNamedType('Int')), - makeInputValueDefinition('nextToken', makeNamedType('String')), - makeInputValueDefinition('lastSync', makeNamedType('AWSTimestamp')), - ], - makeNamedType(ModelResourceIDs.ModelConnectionTypeName(def.name.value)), - ), - ); - } - - // Create get queries - if (shouldMakeGet) { - const getResolver = this.resources.makeGetResolver(def.name.value, getFieldNameOverride, isSyncEnabled, ctx.getQueryTypeName()); - const resourceId = ResolverResourceIDs.DynamoDBGetResolverResourceID(typeName); - ctx.setResource(resourceId, getResolver); - ctx.mapResourceToStack(typeName, resourceId); - - queryFields.push( - makeField( - getResolver.Properties.FieldName.toString(), - [makeInputValueDefinition('id', makeNonNullType(makeNamedType('ID')))], - makeNamedType(def.name.value), - ), - ); - } - - if (shouldMakeList) { - this.generateModelXConnectionType(ctx, def); - - // Create the list resolver - const listResolver = this.resources.makeListResolver( - def.name.value, - ctx.featureFlags.getBoolean('improvePluralization'), - listFieldNameOverride, - isSyncEnabled, - ctx.getQueryTypeName(), - ); - const resourceId = ResolverResourceIDs.DynamoDBListResolverResourceID(typeName); - ctx.setResource(resourceId, listResolver); - ctx.mapResourceToStack(typeName, resourceId); - - queryFields.push(makeConnectionField(listResolver.Properties.FieldName.toString(), def.name.value)); - this.generateFilterInputs(ctx, def); - } - - ctx.addQueryFields(queryFields); - }; - - /** - * Creates subscriptions for a @model object type. By default creates a subscription for - * create, update, and delete mutations. - * - * Subscriptions are one to many in that a subscription may subscribe to multiple mutations. - * You may thus provide multiple names of the subscriptions that will be triggered by each - * mutation. - * - * type Post @model(subscriptions: { onCreate: ["onPostCreated", "onFeedUpdated"] }) { - * id: ID! - * title: String! - * } - * - * will create two subscription fields: - * - * type Subscription { - * onPostCreated: Post @aws_subscribe(mutations: ["createPost"]) - * onFeedUpdated: Post @aws_subscribe(mutations: ["createPost"]) - * } - * Subscription Levels - * subscriptions.level === OFF || subscriptions === null - * Will not create subscription operations - * subcriptions.level === PUBLIC - * Will continue as is creating subscription operations - * subscriptions.level === ON || subscriptions === undefined - * If auth is enabled it will enabled protection on subscription operations and resolvers - */ - private createSubscriptions = (def: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => { - const typeName = def.name.value; - const subscriptionFields = []; - - const directiveArguments: ModelDirectiveArgs = getDirectiveArguments(directive); - - const subscriptionsArgument = directiveArguments.subscriptions; - const createResolver = ctx.getResource(ResolverResourceIDs.DynamoDBCreateResolverResourceID(typeName)); - const updateResolver = ctx.getResource(ResolverResourceIDs.DynamoDBUpdateResolverResourceID(typeName)); - const deleteResolver = ctx.getResource(ResolverResourceIDs.DynamoDBDeleteResolverResourceID(typeName)); - - if (subscriptionsArgument === null) { - return; - } - if (subscriptionsArgument && subscriptionsArgument.level === 'off') { - return; - } - if (subscriptionsArgument && (subscriptionsArgument.onCreate || subscriptionsArgument.onUpdate || subscriptionsArgument.onDelete)) { - // Add the custom subscriptions - const subscriptionToMutationsMap: { [subField: string]: string[] } = {}; - const onCreate = subscriptionsArgument.onCreate || []; - const onUpdate = subscriptionsArgument.onUpdate || []; - const onDelete = subscriptionsArgument.onDelete || []; - const subFields = [...onCreate, ...onUpdate, ...onDelete]; - // initialize the reverse lookup - for (const field of subFields) { - subscriptionToMutationsMap[field] = []; - } - // Add the correct mutation to the lookup - for (const field of Object.keys(subscriptionToMutationsMap)) { - if (onCreate.includes(field) && createResolver) { - subscriptionToMutationsMap[field].push(createResolver.Properties.FieldName); - } - if (onUpdate.includes(field) && updateResolver) { - subscriptionToMutationsMap[field].push(updateResolver.Properties.FieldName); - } - if (onDelete.includes(field) && deleteResolver) { - subscriptionToMutationsMap[field].push(deleteResolver.Properties.FieldName); - } - } - for (const subFieldName of Object.keys(subscriptionToMutationsMap)) { - const subField = makeSubscriptionField(subFieldName, typeName, subscriptionToMutationsMap[subFieldName]); - subscriptionFields.push(subField); - } - } else { - // Add the default subscriptions - if (createResolver) { - const onCreateField = makeSubscriptionField(ModelResourceIDs.ModelOnCreateSubscriptionName(typeName), typeName, [ - createResolver.Properties.FieldName, - ]); - subscriptionFields.push(onCreateField); - } - if (updateResolver) { - const onUpdateField = makeSubscriptionField(ModelResourceIDs.ModelOnUpdateSubscriptionName(typeName), typeName, [ - updateResolver.Properties.FieldName, - ]); - subscriptionFields.push(onUpdateField); - } - if (deleteResolver) { - const onDeleteField = makeSubscriptionField(ModelResourceIDs.ModelOnDeleteSubscriptionName(typeName), typeName, [ - deleteResolver.Properties.FieldName, - ]); - subscriptionFields.push(onDeleteField); - } - } - - ctx.addSubscriptionFields(subscriptionFields); - }; - - private typeExist(type: string, ctx: TransformerContext): boolean { - return Boolean(type in ctx.nodeMap); - } - - private generateModelXConnectionType(ctx: TransformerContext, def: ObjectTypeDefinitionNode, isSync: Boolean = false): void { - const tableXConnectionName = ModelResourceIDs.ModelConnectionTypeName(def.name.value); - if (this.typeExist(tableXConnectionName, ctx)) { - return; - } - - // Create the ModelXConnection - const connectionType = blankObject(tableXConnectionName); - ctx.addObject(connectionType); - ctx.addObjectExtension(makeModelConnectionType(def.name.value, isSync)); - } - - private generateFilterInputs(ctx: TransformerContext, def: ObjectTypeDefinitionNode): void { - const scalarFilters = makeScalarFilterInputs(this.supportsConditions(ctx)); - for (const filter of scalarFilters) { - if (!this.typeExist(filter.name.value, ctx)) { - ctx.addInput(filter); - } - } - - // Create the Enum filters - const enumFilters = makeEnumFilterInputObjects(def, ctx, this.supportsConditions(ctx)); - for (const filter of enumFilters) { - if (!this.typeExist(filter.name.value, ctx)) { - ctx.addInput(filter); - } - } - - // Create the ModelXFilterInput - const tableXQueryFilterInput = makeModelXFilterInputObject(def, ctx, this.supportsConditions(ctx)); - if (!this.typeExist(tableXQueryFilterInput.name.value, ctx)) { - ctx.addInput(tableXQueryFilterInput); - } - - if (this.supportsConditions(ctx)) { - const attributeTypeEnum = makeAttributeTypeEnum(); - if (!this.typeExist(attributeTypeEnum.name.value, ctx)) { - ctx.addType(attributeTypeEnum); - } - } - } - - /** - * Generate Predicate type for Sync Query for DataStore - * @param ctx : transformer context - * @param def : ObjectTypeDefinition - */ - - private generateConditionInputs(ctx: TransformerContext, def: ObjectTypeDefinitionNode): void { - const scalarFilters = makeScalarFilterInputs(this.supportsConditions(ctx)); - for (const filter of scalarFilters) { - if (!this.typeExist(filter.name.value, ctx)) { - ctx.addInput(filter); - } - } - - // Create the Enum filters - const enumFilters = makeEnumFilterInputObjects(def, ctx, this.supportsConditions(ctx)); - for (const filter of enumFilters) { - if (!this.typeExist(filter.name.value, ctx)) { - ctx.addInput(filter); - } - } - - if (this.supportsConditions(ctx)) { - // Create the ModelXConditionInput - const tableXMutationConditionInput = makeModelXConditionInputObject(def, ctx, this.supportsConditions(ctx)); - if (!this.typeExist(tableXMutationConditionInput.name.value, ctx)) { - ctx.addInput(tableXMutationConditionInput); - } - - const attributeTypeEnum = makeAttributeTypeEnum(); - if (!this.typeExist(attributeTypeEnum.name.value, ctx)) { - ctx.addType(attributeTypeEnum); - } - } - } - - private getOpts(opts: DynamoDBModelTransformerOptions) { - const defaultOpts = { - EnableDeletionProtection: false, - }; - return { - ...defaultOpts, - ...opts, - }; - } - - private setSyncConfig(ctx: TransformerContext, typeName: string) { - let syncConfig: SyncConfig; - const resolverConfig = ctx.getResolverConfig(); - if (resolverConfig && resolverConfig.project) { - syncConfig = resolverConfig.project; - } - if (resolverConfig && resolverConfig.models && resolverConfig.models[typeName]) { - const typeResolverConfig = resolverConfig.models[typeName]; - if (typeResolverConfig.ConflictDetection && typeResolverConfig.ConflictHandler) { - syncConfig = typeResolverConfig; - } else { - console.warn(`Invalid resolverConfig for type ${typeName}. Using the project resolverConfig instead.`); - } - } - return (this.opts.SyncConfig = syncConfig); - } - - // Due to the current architecture of Transformers we've to handle the 'id' field removal - // here, because KeyTransformer will not be invoked if there are no @key directives declared - // on the type. - private updateMutationConditionInput(ctx: TransformerContext, type: ObjectTypeDefinitionNode): void { - if (this.supportsConditions(ctx)) { - // Get the existing ModelXConditionInput - const tableXMutationConditionInputName = ModelResourceIDs.ModelConditionInputTypeName(type.name.value); - - if (this.typeExist(tableXMutationConditionInputName, ctx)) { - const tableXMutationConditionInput = ctx.getType(tableXMutationConditionInputName); - - const keyDirectives = type.directives.filter((d) => d.name.value === 'key'); - - // If there are @key directives defined we've nothing to do, it will handle everything - if (keyDirectives && keyDirectives.length > 0) { - return; - } - - // Remove the field named 'id' from the condition if there is one - const idField = tableXMutationConditionInput.fields.find((f) => f.name.value === 'id'); - - if (idField) { - const reducedFields = tableXMutationConditionInput.fields.filter((f) => Boolean(f.name.value !== 'id')); - - const updatedInput = { - ...tableXMutationConditionInput, - fields: reducedFields, - }; - - ctx.putType(updatedInput); - } - } - } - } - - private supportsConditions(context: TransformerContext) { - return context.getTransformerVersion() >= CONDITIONS_MINIMUM_VERSION; - } - - private static isTimestampCompatibleField(field?: FieldDefinitionNode): boolean { - if (field && !(getBaseType(field.type) === 'AWSDateTime' || getBaseType(field.type) === 'String')) { - return false; - } - return true; - } - - private addInitalizationMetadata(ctx: TransformerContext, resourceId: string, initCodeGenerator: () => string | void): void { - const ddbMetadata = ctx.metadata.has(METADATA_KEY) ? ctx.metadata.get(METADATA_KEY) : {}; - ddbMetadata.hoistedRequestMappingContent = { - ...ddbMetadata?.hoistedRequestMappingContent, - [resourceId]: initCodeGenerator, - }; - ctx.metadata.set(METADATA_KEY, ddbMetadata); - } -} diff --git a/packages/graphql-dynamodb-transformer/src/ModelDirectiveArgs.ts b/packages/graphql-dynamodb-transformer/src/ModelDirectiveArgs.ts deleted file mode 100644 index d746641c0e..0000000000 --- a/packages/graphql-dynamodb-transformer/src/ModelDirectiveArgs.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { getDirectiveArguments } from 'graphql-transformer-core'; -import { DirectiveNode } from 'graphql'; - -export interface QueryNameMap { - get?: string; - list?: string; - query?: string; -} - -export interface MutationNameMap { - create?: string; - update?: string; - delete?: string; -} - -export type ModelSubscriptionLevel = 'off' | 'public' | 'on'; - -export interface SubscriptionNameMap { - onCreate?: string[]; - onUpdate?: string[]; - onDelete?: string[]; - level?: ModelSubscriptionLevel; -} - -export interface ModelDirectiveTimestampConfiguration { - createdAt?: string; - updatedAt?: string; -} - -export interface ModelDirectiveArgs { - queries?: QueryNameMap; - mutations?: MutationNameMap; - subscriptions?: SubscriptionNameMap; - timestamps?: ModelDirectiveTimestampConfiguration; -} - -export function getCreatedAtFieldName(directive: DirectiveNode): string | undefined { - return getTimestampFieldName(directive, 'createdAt', 'createdAt'); -} - -export function getUpdatedAtFieldName(directive: DirectiveNode): string | undefined { - return getTimestampFieldName(directive, 'updatedAt', 'updatedAt'); -} - -export function getTimestampFieldName(directive: DirectiveNode, fieldName: string, defaultFiledValue: string): string | undefined { - const directiveArguments: ModelDirectiveArgs = getDirectiveArguments(directive); - const timestamp = directiveArguments.timestamps; - - /* When explicitly set to null, note that the check here is strict equality to null and not undefined - * type Post @model(timestamps:null) { - id: ID! - } - */ - if (timestamp === null) return null; - if (timestamp && timestamp[fieldName] !== undefined) { - return timestamp[fieldName]; - } - return defaultFiledValue; -} diff --git a/packages/graphql-dynamodb-transformer/src/__tests__/DynamoDBModelTransformer.test.ts b/packages/graphql-dynamodb-transformer/src/__tests__/DynamoDBModelTransformer.test.ts deleted file mode 100644 index b077235ce1..0000000000 --- a/packages/graphql-dynamodb-transformer/src/__tests__/DynamoDBModelTransformer.test.ts +++ /dev/null @@ -1,854 +0,0 @@ -import { - ObjectTypeDefinitionNode, - parse, - FieldDefinitionNode, - DocumentNode, - DefinitionNode, - Kind, - InputObjectTypeDefinitionNode, - ListValueNode, - InputValueDefinitionNode, - TypeNode, - NamedTypeNode, -} from 'graphql'; -import { FeatureFlagProvider, GraphQLTransform, TRANSFORM_BASE_VERSION, TRANSFORM_CURRENT_VERSION } from 'graphql-transformer-core'; -import { getBaseType } from 'graphql-transformer-common'; -import { DynamoDBModelTransformer } from '../DynamoDBModelTransformer'; - -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - if (name === 'validateTypeNameReservedWords') { - return false; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -test('DynamoDBModelTransformer validation happy case', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); -}); - -test('DynamoDBModelTransformer with query overrides', () => { - const validSchema = `type Post @model(queries: { get: "customGetPost", list: "customListPost" }) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - const createPostInput = getInputType(parsed, 'CreatePostInput'); - expectFieldsOnInputType(createPostInput, ['id', 'title', 'createdAt', 'updatedAt']); - // This id should always be optional. - // aka a named type node aka name.value would not be set if it were a non null node - const idField = createPostInput.fields.find((f) => f.name.value === 'id'); - expect((idField.type as NamedTypeNode).name.value).toEqual('ID'); - const queryType = getObjectType(parsed, 'Query'); - expect(queryType).toBeDefined(); - expectFields(queryType, ['customGetPost']); - expectFields(queryType, ['customListPost']); - const subscriptionType = getObjectType(parsed, 'Subscription'); - expect(subscriptionType).toBeDefined(); - expectFields(subscriptionType, ['onCreatePost', 'onUpdatePost', 'onDeletePost']); - const subField = subscriptionType.fields.find((f) => f.name.value === 'onCreatePost'); - expect(subField.directives.length).toEqual(1); - expect(subField.directives[0].name.value).toEqual('aws_subscribe'); -}); - -test('DynamoDBModelTransformer with mutation overrides', () => { - const validSchema = `type Post @model(mutations: { create: "customCreatePost", update: "customUpdatePost", delete: "customDeletePost" }) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - const mutationType = getObjectType(parsed, 'Mutation'); - expect(mutationType).toBeDefined(); - expectFields(mutationType, ['customCreatePost', 'customUpdatePost', 'customDeletePost']); -}); - -test('DynamoDBModelTransformer with only create mutations', () => { - const validSchema = `type Post @model(mutations: { create: "customCreatePost" }) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - const mutationType = getObjectType(parsed, 'Mutation'); - expect(mutationType).toBeDefined(); - expectFields(mutationType, ['customCreatePost']); - doNotExpectFields(mutationType, ['updatePost']); -}); - -test('DynamoDBModelTransformer with multiple model directives', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - - type User @model { - id: ID! - name: String! - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - const queryType = getObjectType(parsed, 'Query'); - expect(queryType).toBeDefined(); - expectFields(queryType, ['listPosts']); - expectFields(queryType, ['listUsers']); - - const stringInputType = getInputType(parsed, 'ModelStringFilterInput'); - expect(stringInputType).toBeDefined(); - const booleanInputType = getInputType(parsed, 'ModelBooleanFilterInput'); - expect(booleanInputType).toBeDefined(); - const intInputType = getInputType(parsed, 'ModelIntFilterInput'); - expect(intInputType).toBeDefined(); - const floatInputType = getInputType(parsed, 'ModelFloatFilterInput'); - expect(floatInputType).toBeDefined(); - const idInputType = getInputType(parsed, 'ModelIDFilterInput'); - expect(idInputType).toBeDefined(); - const postInputType = getInputType(parsed, 'ModelPostFilterInput'); - expect(postInputType).toBeDefined(); - const userInputType = getInputType(parsed, 'ModelUserFilterInput'); - expect(userInputType).toBeDefined(); - - expect(verifyInputCount(parsed, 'ModelStringFilterInput', 1)).toBeTruthy(); - expect(verifyInputCount(parsed, 'ModelBooleanFilterInput', 1)).toBeTruthy(); - expect(verifyInputCount(parsed, 'ModelIntFilterInput', 1)).toBeTruthy(); - expect(verifyInputCount(parsed, 'ModelFloatFilterInput', 1)).toBeTruthy(); - expect(verifyInputCount(parsed, 'ModelIDFilterInput', 1)).toBeTruthy(); - expect(verifyInputCount(parsed, 'ModelPostFilterInput', 1)).toBeTruthy(); - expect(verifyInputCount(parsed, 'ModelUserFilterInput', 1)).toBeTruthy(); -}); - -test('DynamoDBModelTransformer with filter', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - createdAt: String - updatedAt: String - }`; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - const queryType = getObjectType(parsed, 'Query'); - expect(queryType).toBeDefined(); - expectFields(queryType, ['listPosts']); - - const connectionType = getObjectType(parsed, 'ModelPostConnection'); - expect(connectionType).toBeDefined(); - - expect(verifyInputCount(parsed, 'ModelStringFilterInput', 1)).toBeTruthy(); - expect(verifyInputCount(parsed, 'ModelBooleanFilterInput', 1)).toBeTruthy(); - expect(verifyInputCount(parsed, 'ModelIntFilterInput', 1)).toBeTruthy(); - expect(verifyInputCount(parsed, 'ModelFloatFilterInput', 1)).toBeTruthy(); - expect(verifyInputCount(parsed, 'ModelIDFilterInput', 1)).toBeTruthy(); - expect(verifyInputCount(parsed, 'ModelPostFilterInput', 1)).toBeTruthy(); -}); - -test('DynamoDBModelTransformer with mutations set to null', () => { - const validSchema = `type Post @model(mutations: null) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - const mutationType = getObjectType(parsed, 'Mutation'); - expect(mutationType).not.toBeDefined(); -}); -test('DynamoDBModelTransformer with queries set to null', () => { - const validSchema = `type Post @model(queries: null) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - const mutationType = getObjectType(parsed, 'Mutation'); - expect(mutationType).toBeDefined(); - const queryType = getObjectType(parsed, 'Query'); - expect(queryType).not.toBeDefined(); -}); -test('DynamoDBModelTransformer with subscriptions set to null', () => { - const validSchema = `type Post @model(subscriptions: null) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - const mutationType = getObjectType(parsed, 'Mutation'); - expect(mutationType).toBeDefined(); - const queryType = getObjectType(parsed, 'Query'); - expect(queryType).toBeDefined(); - const subscriptionType = getObjectType(parsed, 'Subscription'); - expect(subscriptionType).not.toBeDefined(); -}); -test('DynamoDBModelTransformer with queries and mutations set to null', () => { - const validSchema = `type Post @model(queries: null, mutations: null, subscriptions: null) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - const mutationType = getObjectType(parsed, 'Mutation'); - expect(mutationType).not.toBeDefined(); - const queryType = getObjectType(parsed, 'Query'); - expect(queryType).not.toBeDefined(); - const subscriptionType = getObjectType(parsed, 'Subscription'); - expect(subscriptionType).not.toBeDefined(); -}); -test('DynamoDBModelTransformer with advanced subscriptions', () => { - const validSchema = `type Post @model(subscriptions: { - onCreate: ["onFeedUpdated", "onCreatePost"], - onUpdate: ["onFeedUpdated"], - onDelete: ["onFeedUpdated"] - }) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - const subscriptionType = getObjectType(parsed, 'Subscription'); - expect(subscriptionType).toBeDefined(); - expectFields(subscriptionType, ['onFeedUpdated', 'onCreatePost']); - const subField = subscriptionType.fields.find((f) => f.name.value === 'onFeedUpdated'); - expect(subField.directives.length).toEqual(1); - expect(subField.directives[0].name.value).toEqual('aws_subscribe'); - const mutationsList = subField.directives[0].arguments.find((a) => a.name.value === 'mutations').value as ListValueNode; - const mutList = mutationsList.values.map((v: any) => v.value); - expect(mutList.length).toEqual(3); - expect(mutList).toContain('createPost'); - expect(mutList).toContain('updatePost'); - expect(mutList).toContain('deletePost'); -}); - -test('DynamoDBModelTransformer with non-model types and enums', () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - createdAt: String - updatedAt: String - metadata: [PostMetadata!]! - appearsIn: [Episode]! - } - type PostMetadata { - tags: Tag - } - type Tag { - published: Boolean - metadata: PostMetadata - } - enum Episode { - NEWHOPE - EMPIRE - JEDI - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - - const postMetaDataInputType = getInputType(parsed, 'PostMetadataInput'); - expect(postMetaDataInputType).toBeDefined(); - const tagInputType = getInputType(parsed, 'TagInput'); - expect(tagInputType).toBeDefined(); - expectFieldsOnInputType(tagInputType, ['metadata']); - const createPostInputType = getInputType(parsed, 'CreatePostInput'); - expectFieldsOnInputType(createPostInputType, ['metadata', 'appearsIn']); - const updatePostInputType = getInputType(parsed, 'UpdatePostInput'); - expectFieldsOnInputType(updatePostInputType, ['metadata', 'appearsIn']); - - const postModelObject = getObjectType(parsed, 'Post'); - const postMetaDataInputField = getFieldOnInputType(createPostInputType, 'metadata'); - const postMetaDataField = getFieldOnObjectType(postModelObject, 'metadata'); - // this checks that the non-model type was properly "unwrapped", renamed, and "rewrapped" - // in the generated CreatePostInput type - its types should be the same as in the Post @model type - verifyMatchingTypes(postMetaDataInputField.type, postMetaDataField.type); - - expect(verifyInputCount(parsed, 'PostMetadataInput', 1)).toBeTruthy(); - expect(verifyInputCount(parsed, 'TagInput', 1)).toBeTruthy(); -}); - -test('DynamoDBModelTransformer with mutation input overrides when mutations are disabled', () => { - const validSchema = `type Post @model(mutations: null) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - input CreatePostInput { - different: String - } - input UpdatePostInput { - different2: String - } - input DeletePostInput { - different3: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - const createPostInput = getInputType(parsed, 'CreatePostInput'); - expectFieldsOnInputType(createPostInput, ['different']); - const updatePostInput = getInputType(parsed, 'UpdatePostInput'); - expectFieldsOnInputType(updatePostInput, ['different2']); - const deletePostInput = getInputType(parsed, 'DeletePostInput'); - expectFieldsOnInputType(deletePostInput, ['different3']); -}); - -test('DynamoDBModelTransformer with mutation input overrides when mutations are enabled', () => { - const validSchema = `type Post @model { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - # User defined types always take precedence. - input CreatePostInput { - different: String - } - input UpdatePostInput { - different2: String - } - input DeletePostInput { - different3: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - const createPostInput = getInputType(parsed, 'CreatePostInput'); - expectFieldsOnInputType(createPostInput, ['different']); - const updatePostInput = getInputType(parsed, 'UpdatePostInput'); - expectFieldsOnInputType(updatePostInput, ['different2']); - const deletePostInput = getInputType(parsed, 'DeletePostInput'); - expectFieldsOnInputType(deletePostInput, ['different3']); -}); - -test('non model objects contain id as a type for fields', () => { - const validSchema = ` - type Post @model { - id: ID! - comments: [Comment] - } - type Comment { - id: String! - text: String! - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - const commentInput = getInputType(parsed, 'CommentInput'); - expectFieldsOnInputType(commentInput, ['id', 'text']); - const commentObject = getObjectType(parsed, 'Comment'); - const commentInputObject = getInputType(parsed, 'CommentInput'); - const commentObjectIDField = getFieldOnObjectType(commentObject, 'id'); - const commentInputIDField = getFieldOnInputType(commentInputObject, 'id'); - verifyMatchingTypes(commentObjectIDField.type, commentInputIDField.type); -}); - -test('schema includes attribute enum when only queries specified', () => { - const validSchema = ` - type Entity @model(mutations: null, subscriptions: null) { - id: ID! - str: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - transformConfig: { - Version: 5, - }, - }); - const result = transformer.transform(validSchema); - expect(result).toBeDefined(); - expect(result.schema).toBeDefined(); - expect(result.schema).toMatchSnapshot(); -}); - -test('only get does not generate superfluous input and filter types', () => { - const validSchema = ` - type Entity @model(mutations: null, subscriptions: null, queries: {get: "getEntity"}) { - id: ID! - str: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - transformConfig: { - Version: 5, - }, - }); - const result = transformer.transform(validSchema); - expect(result).toBeDefined(); - expect(result.schema).toBeDefined(); - expect(result.schema).toMatchSnapshot(); -}); - -test('timestamp parameters when generating resolvers and output schema', () => { - const validSchema = ` - type Post @model(timestamps: { createdAt: "createdOn", updatedAt: "updatedOn"}) { - id: ID! - str: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const result = transformer.transform(validSchema); - expect(result).toBeDefined(); - expect(result.schema).toBeDefined(); - expect(result.schema).toMatchSnapshot(); - - expect(result.resolvers['Mutation.createPost.req.vtl']).toMatchSnapshot(); - expect(result.resolvers['Mutation.updatePost.req.vtl']).toMatchSnapshot(); -}); - -test('resolver template not to auto generate createdAt and updatedAt when the type in schema is not AWSDateTime', () => { - const validSchema = ` - type Post @model { - id: ID! - str: String - createdAt: AWSTimestamp - updatedAt: AWSTimestamp - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const result = transformer.transform(validSchema); - expect(result).toBeDefined(); - expect(result.schema).toBeDefined(); - expect(result.schema).toMatchSnapshot(); - - expect(result.resolvers['Mutation.createPost.req.vtl']).toMatchSnapshot(); - expect(result.resolvers['Mutation.updatePost.req.vtl']).toMatchSnapshot(); -}); - -test('create and update mutation input should have timestamps as nullable fields when the type makes it non-nullable', () => { - const validSchema = ` - type Post @model { - id: ID! - str: String - createdAt: AWSDateTime! - updatedAt: AWSDateTime! - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const result = transformer.transform(validSchema); - expect(result).toBeDefined(); - expect(result.schema).toBeDefined(); - expect(result.schema).toMatchSnapshot(); - - expect(result.resolvers['Mutation.createPost.req.vtl']).toMatchSnapshot(); - expect(result.resolvers['Mutation.updatePost.req.vtl']).toMatchSnapshot(); -}); - -test('not to include createdAt and updatedAt field when timestamps is set to null', () => { - const validSchema = ` - type Post @model(timestamps: null) { - id: ID! - str: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const result = transformer.transform(validSchema); - expect(result).toBeDefined(); - expect(result.schema).toBeDefined(); - expect(result.schema).toMatchSnapshot(); - - expect(result.resolvers['Mutation.createPost.req.vtl']).toMatchSnapshot(); - expect(result.resolvers['Mutation.updatePost.req.vtl']).toMatchSnapshot(); -}); - -test(`V${TRANSFORM_BASE_VERSION} transformer snapshot test`, () => { - const schema = transformerVersionSnapshot(TRANSFORM_BASE_VERSION); - expect(schema).toMatchSnapshot(); -}); - -test(`V5 transformer snapshot test`, () => { - const schema = transformerVersionSnapshot(5); - expect(schema).toMatchSnapshot(); -}); - -test(`Current version transformer snapshot test`, () => { - const schema = transformerVersionSnapshot(TRANSFORM_CURRENT_VERSION); - expect(schema).toMatchSnapshot(); -}); - -test('DynamoDB transformer should add default primary key when not defined', () => { - const validSchema = ` - type Post @model{ - str: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const result = transformer.transform(validSchema); - expect(result).toBeDefined(); - expect(result.schema).toBeDefined(); - expect(result.schema).toBeDefined(); - const schema = parse(result.schema); - - const createPostInput: InputObjectTypeDefinitionNode = schema.definitions.find( - (d) => d.kind === 'InputObjectTypeDefinition' && d.name.value === 'CreatePostInput', - ) as InputObjectTypeDefinitionNode | undefined; - expect(createPostInput).toBeDefined(); - const defaultIdField: InputValueDefinitionNode = createPostInput.fields.find((f) => f.name.value === 'id'); - expect(defaultIdField).toBeDefined(); - expect(getBaseType(defaultIdField.type)).toEqual('ID'); -}); - -test('DynamoDB transformer should not add default primary key when ID is defined', () => { - const validSchema = ` - type Post @model{ - id: Int - str: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const result = transformer.transform(validSchema); - expect(result).toBeDefined(); - expect(result.schema).toBeDefined(); - expect(result.schema).toBeDefined(); - const schema = parse(result.schema); - - const createPostInput: InputObjectTypeDefinitionNode = schema.definitions.find( - (d) => d.kind === 'InputObjectTypeDefinition' && d.name.value === 'CreatePostInput', - ) as InputObjectTypeDefinitionNode | undefined; - expect(createPostInput).toBeDefined(); - const defaultIdField: InputValueDefinitionNode = createPostInput.fields.find((f) => f.name.value === 'id'); - expect(defaultIdField).toBeDefined(); - expect(getBaseType(defaultIdField.type)).toEqual('Int'); - // It should not add default value for ctx.arg.id as id is of type Int - expect(result.resolvers['Mutation.createPost.req.vtl']).toMatchSnapshot(); -}); - -test('DynamoDB transformer should throw for reserved type name usage', () => { - const invalidSchema = ` - type Subscription @model{ - id: Int - str: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - }); - expect(() => transformer.transform(invalidSchema)).toThrowError( - "Subscription' is a reserved type name and currently in use within the default schema element.", - ); -}); - -test('Schema should compile successfully when subscription is missing from schema', () => { - const validSchema = ` - type Post @model { - id: Int - str: String - } - - type Query { - Custom: String - } - - schema { - query: Query - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const parsed = parse(out.schema); - const subscriptionType = getObjectType(parsed, 'Subscription'); - expect(subscriptionType).toBeDefined(); - expectFields(subscriptionType, ['onCreatePost', 'onUpdatePost', 'onDeletePost']); - const mutationType = getObjectType(parsed, 'Mutation'); - expect(mutationType).toBeDefined(); - expectFields(mutationType, ['createPost', 'updatePost', 'deletePost']); -}); - -test('Should not validate reserved type names when validateTypeNameReservedWords is off', () => { - const schema = ` - type Subscription @model{ - id: Int - str: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags: { - getBoolean: jest.fn().mockImplementation((name) => (name === 'validateTypeNameReservedWords' ? false : undefined)), - } as unknown as FeatureFlagProvider, - }); - const out = transformer.transform(schema); - expect(out).toBeDefined(); - const parsed = parse(out.schema); - const subscriptionType = getObjectType(parsed, 'Subscription'); - expect(subscriptionType).toBeDefined(); -}); - -it('should generate id for the update input object', async () => { - const validSchema = ` - type Todo @model { - uid: String! - username: String - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - const definition = out.schema; - expect(definition).toBeDefined(); - - const parsed = parse(definition); - - const updateTodoInput = getInputType(parsed, 'UpdateTodoInput'); - expect(updateTodoInput).toBeDefined(); - - expectFieldsOnInputType(updateTodoInput!, ['id']); - const updateTodoIdField = getFieldOnInputType(updateTodoInput!, 'id'); - expect(updateTodoIdField.type.kind).toBe('NonNullType'); -}); - -function transformerVersionSnapshot(version: number): string { - const validSchema = ` - type Post @model - { - id: ID! - content: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer()], - featureFlags, - transformConfig: { - Version: version, - }, - }); - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - return out.schema; -} - -function expectFields(type: ObjectTypeDefinitionNode, fields: string[]) { - for (const fieldName of fields) { - const foundField = type.fields.find((f: FieldDefinitionNode) => f.name.value === fieldName); - expect(foundField).toBeDefined(); - } -} - -function expectFieldsOnInputType(type: InputObjectTypeDefinitionNode, fields: string[]) { - for (const fieldName of fields) { - const foundField = type.fields.find((f: InputValueDefinitionNode) => f.name.value === fieldName); - expect(foundField).toBeDefined(); - } -} - -function getFieldOnInputType(type: InputObjectTypeDefinitionNode, field: string): InputValueDefinitionNode { - return type.fields.find((f: InputValueDefinitionNode) => f.name.value === field); -} - -function getFieldOnObjectType(type: ObjectTypeDefinitionNode, field: string): FieldDefinitionNode { - return type.fields.find((f: FieldDefinitionNode) => f.name.value === field); -} - -function doNotExpectFields(type: ObjectTypeDefinitionNode, fields: string[]) { - for (const fieldName of fields) { - expect(type.fields.find((f: FieldDefinitionNode) => f.name.value === fieldName)).toBeUndefined(); - } -} - -function getObjectType(doc: DocumentNode, type: string): ObjectTypeDefinitionNode | undefined { - return doc.definitions.find((def: DefinitionNode) => def.kind === Kind.OBJECT_TYPE_DEFINITION && def.name.value === type) as - | ObjectTypeDefinitionNode - | undefined; -} - -function getInputType(doc: DocumentNode, type: string): InputObjectTypeDefinitionNode | undefined { - return doc.definitions.find((def: DefinitionNode) => def.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION && def.name.value === type) as - | InputObjectTypeDefinitionNode - | undefined; -} - -function verifyInputCount(doc: DocumentNode, type: string, count: number): boolean { - return doc.definitions.filter((def) => def.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION && def.name.value === type).length == count; -} - -function verifyMatchingTypes(t1: TypeNode, t2: TypeNode): boolean { - if (t1.kind !== t2.kind) { - return false; - } - - if (t1.kind !== Kind.NAMED_TYPE && t2.kind !== Kind.NAMED_TYPE) { - verifyMatchingTypes(t1.type, t2.type); - } else { - return false; - } -} diff --git a/packages/graphql-dynamodb-transformer/src/__tests__/ModelDirectiveArgs.test.ts b/packages/graphql-dynamodb-transformer/src/__tests__/ModelDirectiveArgs.test.ts deleted file mode 100644 index ec0a719ca3..0000000000 --- a/packages/graphql-dynamodb-transformer/src/__tests__/ModelDirectiveArgs.test.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { buildASTSchema, concatAST, DirectiveNode, parse } from 'graphql'; -import { directiveDefinition } from '../DynamoDBModelTransformer'; -import { getCreatedAtFieldName, getUpdatedAtFieldName } from '../ModelDirectiveArgs'; - -function getDirective(doc: string, typeName: string): DirectiveNode { - const schema = buildASTSchema(concatAST([directiveDefinition, parse(doc)])); - const selectedType = schema.getTypeMap()[typeName]; - return selectedType.astNode.directives.find((d) => d.name.value === 'model'); -} -describe('getCreatedAtField', () => { - it('should return createdAt when there is no timestamps configuration', () => { - const doc = /* GraphQL */ ` - type Post @model { - id: ID! - title: String - } - `; - const modelDirective = getDirective(doc, 'Post'); - expect(modelDirective).toBeDefined(); - expect(getCreatedAtFieldName(modelDirective)).toEqual('createdAt'); - }); - - it('should return null when timestamps are set to null', () => { - const doc = /* GraphQL */ ` - type Post @model(timestamps: null) { - id: ID! - title: String - } - `; - const modelDirective = getDirective(doc, 'Post'); - expect(modelDirective).toBeDefined(); - expect(getCreatedAtFieldName(modelDirective)).toBeNull(); - }); - - it('should return null when createdAt is set to null', () => { - const doc = /* GraphQL */ ` - type Post @model(timestamps: { createdAt: null }) { - id: ID! - title: String - } - `; - const modelDirective = getDirective(doc, 'Post'); - expect(modelDirective).toBeDefined(); - expect(getCreatedAtFieldName(modelDirective)).toBeNull(); - }); - - it('should return createdOn when createdAt is set to createdOn', () => { - const doc = /* GraphQL */ ` - type Post @model(timestamps: { createdAt: "createdOn" }) { - id: ID! - title: String - } - `; - const modelDirective = getDirective(doc, 'Post'); - expect(modelDirective).toBeDefined(); - expect(getCreatedAtFieldName(modelDirective)).toEqual('createdOn'); - }); - - it('should return createdAt when createdAt is not set in timestamps', () => { - const doc = /* GraphQL */ ` - type Post @model(timestamps: { updatedAt: "updatedOn" }) { - id: ID! - title: String - } - `; - const modelDirective = getDirective(doc, 'Post'); - expect(modelDirective).toBeDefined(); - expect(getCreatedAtFieldName(modelDirective)).toEqual('createdAt'); - }); -}); - -describe('getUpdatedAtField', () => { - it('should return updatedAt when there is no timestamps configuration', () => { - const doc = /* GraphQL */ ` - type Post @model { - id: ID! - title: String - } - `; - const modelDirective = getDirective(doc, 'Post'); - expect(modelDirective).toBeDefined(); - expect(getUpdatedAtFieldName(modelDirective)).toEqual('updatedAt'); - }); - - it('should return null for updatedAt when timestamps are set to null', () => { - const doc = /* GraphQL */ ` - type Post @model(timestamps: null) { - id: ID! - title: String - } - `; - const modelDirective = getDirective(doc, 'Post'); - expect(modelDirective).toBeDefined(); - expect(getUpdatedAtFieldName(modelDirective)).toBeNull(); - }); - - it('should return null when updatedAt is set to null', () => { - const doc = /* GraphQL */ ` - type Post @model(timestamps: { updatedAt: null }) { - id: ID! - title: String - } - `; - const modelDirective = getDirective(doc, 'Post'); - expect(modelDirective).toBeDefined(); - expect(getUpdatedAtFieldName(modelDirective)).toBeNull(); - }); - - it('should return updatedOn when updatedAt is set to updatedOn', () => { - const doc = /* GraphQL */ ` - type Post @model(timestamps: { updatedAt: "updatedOn" }) { - id: ID! - title: String - } - `; - const modelDirective = getDirective(doc, 'Post'); - expect(modelDirective).toBeDefined(); - expect(getUpdatedAtFieldName(modelDirective)).toEqual('updatedOn'); - }); - - it('should return updatedAt when updatedAt is not set in timestamps', () => { - const doc = /* GraphQL */ ` - type Post @model(timestamps: { createdAt: "createdOnOn" }) { - id: ID! - title: String - } - `; - const modelDirective = getDirective(doc, 'Post'); - expect(modelDirective).toBeDefined(); - expect(getUpdatedAtFieldName(modelDirective)).toEqual('updatedAt'); - }); -}); diff --git a/packages/graphql-dynamodb-transformer/src/__tests__/__snapshots__/DynamoDBModelTransformer.test.ts.snap b/packages/graphql-dynamodb-transformer/src/__tests__/__snapshots__/DynamoDBModelTransformer.test.ts.snap deleted file mode 100644 index 51920197fb..0000000000 --- a/packages/graphql-dynamodb-transformer/src/__tests__/__snapshots__/DynamoDBModelTransformer.test.ts.snap +++ /dev/null @@ -1,1842 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Current version transformer snapshot test 1`] = ` -"type Post { - id: ID! - content: String - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} - -enum ModelSortDirection { - ASC - DESC -} - -type ModelPostConnection { - items: [Post]! - nextToken: String -} - -input ModelStringInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String - attributeExists: Boolean - attributeType: ModelAttributeTypes - size: ModelSizeInput -} - -input ModelIDInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID - attributeExists: Boolean - attributeType: ModelAttributeTypes - size: ModelSizeInput -} - -input ModelIntInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelFloatInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelBooleanInput { - ne: Boolean - eq: Boolean - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelSizeInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelPostFilterInput { - id: ModelIDInput - content: ModelStringInput - and: [ModelPostFilterInput] - or: [ModelPostFilterInput] - not: ModelPostFilterInput -} - -enum ModelAttributeTypes { - binary - binarySet - bool - list - map - number - numberSet - string - stringSet - _null -} - -type Query { - getPost(id: ID!): Post - listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection -} - -input CreatePostInput { - id: ID - content: String -} - -input UpdatePostInput { - id: ID! - content: String -} - -input DeletePostInput { - id: ID! -} - -type Mutation { - createPost(input: CreatePostInput!, condition: ModelPostConditionInput): Post - updatePost(input: UpdatePostInput!, condition: ModelPostConditionInput): Post - deletePost(input: DeletePostInput!, condition: ModelPostConditionInput): Post -} - -input ModelPostConditionInput { - content: ModelStringInput - and: [ModelPostConditionInput] - or: [ModelPostConditionInput] - not: ModelPostConditionInput -} - -type Subscription { - onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) - onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) - onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) -} -" -`; - -exports[`DynamoDB transformer should not add default primary key when ID is defined 1`] = ` -"## [Start] Set default values. ** -#set( $createdAt = $util.time.nowISO8601() ) -## Automatically set the createdAt timestamp. ** -$util.qr($context.args.input.put(\\"createdAt\\", $util.defaultIfNull($ctx.args.input.createdAt, $createdAt))) -## Automatically set the updatedAt timestamp. ** -$util.qr($context.args.input.put(\\"updatedAt\\", $util.defaultIfNull($ctx.args.input.updatedAt, $createdAt))) -## [End] Set default values. ** -## [Start] Prepare DynamoDB PutItem Request. ** -$util.qr($context.args.input.put(\\"__typename\\", \\"Post\\")) -#if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_not_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_not_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end -#else - #set( $condition = { - \\"expression\\": \\"attribute_not_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) -#end -#if( $context.args.condition ) - #set( $condition.expressionValues = {} ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"PutItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": $util.dynamodb.toDynamoDBJson($ctx.args.input.id) -} #end, - \\"attributeValues\\": $util.dynamodb.toMapValuesJson($context.args.input), - \\"condition\\": $util.toJson($condition) -} -## [End] Prepare DynamoDB PutItem Request. **" -`; - -exports[`V4 transformer snapshot test 1`] = ` -"type Post { - id: ID! - content: String - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} - -enum ModelSortDirection { - ASC - DESC -} - -type ModelPostConnection { - items: [Post]! - nextToken: String -} - -input ModelStringFilterInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String -} - -input ModelIDFilterInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID -} - -input ModelIntFilterInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelFloatFilterInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] -} - -input ModelBooleanFilterInput { - ne: Boolean - eq: Boolean -} - -input ModelPostFilterInput { - id: ModelIDFilterInput - content: ModelStringFilterInput - and: [ModelPostFilterInput] - or: [ModelPostFilterInput] - not: ModelPostFilterInput -} - -type Query { - getPost(id: ID!): Post - listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection -} - -input CreatePostInput { - id: ID - content: String -} - -input UpdatePostInput { - id: ID! - content: String -} - -input DeletePostInput { - id: ID! -} - -type Mutation { - createPost(input: CreatePostInput!): Post - updatePost(input: UpdatePostInput!): Post - deletePost(input: DeletePostInput!): Post -} - -type Subscription { - onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) - onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) - onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) -} -" -`; - -exports[`V5 transformer snapshot test 1`] = ` -"type Post { - id: ID! - content: String - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} - -enum ModelSortDirection { - ASC - DESC -} - -type ModelPostConnection { - items: [Post]! - nextToken: String -} - -input ModelStringInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String - attributeExists: Boolean - attributeType: ModelAttributeTypes - size: ModelSizeInput -} - -input ModelIDInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID - attributeExists: Boolean - attributeType: ModelAttributeTypes - size: ModelSizeInput -} - -input ModelIntInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelFloatInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelBooleanInput { - ne: Boolean - eq: Boolean - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelSizeInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelPostFilterInput { - id: ModelIDInput - content: ModelStringInput - and: [ModelPostFilterInput] - or: [ModelPostFilterInput] - not: ModelPostFilterInput -} - -enum ModelAttributeTypes { - binary - binarySet - bool - list - map - number - numberSet - string - stringSet - _null -} - -type Query { - getPost(id: ID!): Post - listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection -} - -input CreatePostInput { - id: ID - content: String -} - -input UpdatePostInput { - id: ID! - content: String -} - -input DeletePostInput { - id: ID! -} - -type Mutation { - createPost(input: CreatePostInput!, condition: ModelPostConditionInput): Post - updatePost(input: UpdatePostInput!, condition: ModelPostConditionInput): Post - deletePost(input: DeletePostInput!, condition: ModelPostConditionInput): Post -} - -input ModelPostConditionInput { - content: ModelStringInput - and: [ModelPostConditionInput] - or: [ModelPostConditionInput] - not: ModelPostConditionInput -} - -type Subscription { - onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) - onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) - onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) -} -" -`; - -exports[`create and update mutation input should have timestamps as nullable fields when the type makes it non-nullable 1`] = ` -"type Post { - id: ID! - str: String - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} - -enum ModelSortDirection { - ASC - DESC -} - -type ModelPostConnection { - items: [Post]! - nextToken: String -} - -input ModelStringFilterInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String -} - -input ModelIDFilterInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID -} - -input ModelIntFilterInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelFloatFilterInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] -} - -input ModelBooleanFilterInput { - ne: Boolean - eq: Boolean -} - -input ModelPostFilterInput { - id: ModelIDFilterInput - str: ModelStringFilterInput - createdAt: ModelStringFilterInput - updatedAt: ModelStringFilterInput - and: [ModelPostFilterInput] - or: [ModelPostFilterInput] - not: ModelPostFilterInput -} - -type Query { - getPost(id: ID!): Post - listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection -} - -input CreatePostInput { - id: ID - str: String - createdAt: AWSDateTime - updatedAt: AWSDateTime -} - -input UpdatePostInput { - id: ID! - str: String - createdAt: AWSDateTime - updatedAt: AWSDateTime -} - -input DeletePostInput { - id: ID! -} - -type Mutation { - createPost(input: CreatePostInput!): Post - updatePost(input: UpdatePostInput!): Post - deletePost(input: DeletePostInput!): Post -} - -type Subscription { - onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) - onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) - onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) -} -" -`; - -exports[`create and update mutation input should have timestamps as nullable fields when the type makes it non-nullable 2`] = ` -"## [Start] Set default values. ** -$util.qr($context.args.input.put(\\"id\\", $util.defaultIfNull($ctx.args.input.id, $util.autoId()))) -#set( $createdAt = $util.time.nowISO8601() ) -## Automatically set the createdAt timestamp. ** -$util.qr($context.args.input.put(\\"createdAt\\", $util.defaultIfNull($ctx.args.input.createdAt, $createdAt))) -## Automatically set the updatedAt timestamp. ** -$util.qr($context.args.input.put(\\"updatedAt\\", $util.defaultIfNull($ctx.args.input.updatedAt, $createdAt))) -## [End] Set default values. ** -## [Start] Prepare DynamoDB PutItem Request. ** -$util.qr($context.args.input.put(\\"__typename\\", \\"Post\\")) -#if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_not_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_not_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end -#else - #set( $condition = { - \\"expression\\": \\"attribute_not_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) -#end -#if( $context.args.condition ) - #set( $condition.expressionValues = {} ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"PutItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": $util.dynamodb.toDynamoDBJson($ctx.args.input.id) -} #end, - \\"attributeValues\\": $util.dynamodb.toMapValuesJson($context.args.input), - \\"condition\\": $util.toJson($condition) -} -## [End] Prepare DynamoDB PutItem Request. **" -`; - -exports[`create and update mutation input should have timestamps as nullable fields when the type makes it non-nullable 3`] = ` -"#set( $optionalNonNullableFields = [\\"createdAt\\", \\"updatedAt\\"] ) -#foreach( $field in $optionalNonNullableFields ) - #if( $context.arguments.input.keySet().contains($field) && $util.isNull($context.args.input.get($field)) ) -$util.error(\\"An argument you marked as Non-Null is set to Null in the query or the body of your request.\\") - #end -#end -#if( $authCondition && $authCondition.expression != \\"\\" ) - #set( $condition = $authCondition ) - #if( $modelObjectKey ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#id)\\")) - $util.qr($condition.expressionNames.put(\\"#id\\", \\"id\\")) - #end -#else - #if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - #set( $condition = { - \\"expression\\": \\"attribute_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) - #end -#end -## Automatically set the updatedAt timestamp. ** -$util.qr($context.args.input.put(\\"updatedAt\\", $util.defaultIfNull($ctx.args.input.updatedAt, $util.time.nowISO8601()))) -$util.qr($context.args.input.put(\\"__typename\\", \\"Post\\")) -## Update condition if type is @versioned ** -#if( $versionedCondition ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $versionedCondition.expression\\")) - $util.qr($condition.expressionNames.putAll($versionedCondition.expressionNames)) - $util.qr($condition.expressionValues.putAll($versionedCondition.expressionValues)) -#end -#if( $context.args.condition ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -#set( $expNames = {} ) -#set( $expValues = {} ) -#set( $expSet = {} ) -#set( $expAdd = {} ) -#set( $expRemove = [] ) -#if( $modelObjectKey ) - #set( $keyFields = [] ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($keyFields.add(\\"$entry.key\\")) - #end -#else - #set( $keyFields = [\\"id\\"] ) -#end -#foreach( $entry in $util.map.copyAndRemoveAllKeys($context.args.input, $keyFields).entrySet() ) - #if( !$util.isNull($dynamodbNameOverrideMap) && $dynamodbNameOverrideMap.containsKey(\\"$entry.key\\") ) - #set( $entryKeyAttributeName = $dynamodbNameOverrideMap.get(\\"$entry.key\\") ) - #else - #set( $entryKeyAttributeName = $entry.key ) - #end - #if( $util.isNull($entry.value) ) - #set( $discard = $expRemove.add(\\"#$entryKeyAttributeName\\") ) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - #else - $util.qr($expSet.put(\\"#$entryKeyAttributeName\\", \\":$entryKeyAttributeName\\")) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - $util.qr($expValues.put(\\":$entryKeyAttributeName\\", $util.dynamodb.toDynamoDB($entry.value))) - #end -#end -#set( $expression = \\"\\" ) -#if( !$expSet.isEmpty() ) - #set( $expression = \\"SET\\" ) - #foreach( $entry in $expSet.entrySet() ) - #set( $expression = \\"$expression $entry.key = $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expAdd.isEmpty() ) - #set( $expression = \\"$expression ADD\\" ) - #foreach( $entry in $expAdd.entrySet() ) - #set( $expression = \\"$expression $entry.key $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expRemove.isEmpty() ) - #set( $expression = \\"$expression REMOVE\\" ) - #foreach( $entry in $expRemove ) - #set( $expression = \\"$expression $entry\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#set( $update = {} ) -$util.qr($update.put(\\"expression\\", \\"$expression\\")) -#if( !$expNames.isEmpty() ) - $util.qr($update.put(\\"expressionNames\\", $expNames)) -#end -#if( !$expValues.isEmpty() ) - $util.qr($update.put(\\"expressionValues\\", $expValues)) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"UpdateItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": { - \\"S\\": $util.toJson($context.args.input.id) - } -} #end, - \\"update\\": $util.toJson($update), - \\"condition\\": $util.toJson($condition) -}" -`; - -exports[`not to include createdAt and updatedAt field when timestamps is set to null 1`] = ` -"type Post { - id: ID! - str: String -} - -enum ModelSortDirection { - ASC - DESC -} - -type ModelPostConnection { - items: [Post]! - nextToken: String -} - -input ModelStringFilterInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String -} - -input ModelIDFilterInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID -} - -input ModelIntFilterInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelFloatFilterInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] -} - -input ModelBooleanFilterInput { - ne: Boolean - eq: Boolean -} - -input ModelPostFilterInput { - id: ModelIDFilterInput - str: ModelStringFilterInput - and: [ModelPostFilterInput] - or: [ModelPostFilterInput] - not: ModelPostFilterInput -} - -type Query { - getPost(id: ID!): Post - listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection -} - -input CreatePostInput { - id: ID - str: String -} - -input UpdatePostInput { - id: ID! - str: String -} - -input DeletePostInput { - id: ID! -} - -type Mutation { - createPost(input: CreatePostInput!): Post - updatePost(input: UpdatePostInput!): Post - deletePost(input: DeletePostInput!): Post -} - -type Subscription { - onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) - onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) - onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) -} -" -`; - -exports[`not to include createdAt and updatedAt field when timestamps is set to null 2`] = ` -"## [Start] Set default values. ** -$util.qr($context.args.input.put(\\"id\\", $util.defaultIfNull($ctx.args.input.id, $util.autoId()))) -## [End] Set default values. ** -## [Start] Prepare DynamoDB PutItem Request. ** -$util.qr($context.args.input.put(\\"__typename\\", \\"Post\\")) -#if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_not_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_not_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end -#else - #set( $condition = { - \\"expression\\": \\"attribute_not_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) -#end -#if( $context.args.condition ) - #set( $condition.expressionValues = {} ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"PutItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": $util.dynamodb.toDynamoDBJson($ctx.args.input.id) -} #end, - \\"attributeValues\\": $util.dynamodb.toMapValuesJson($context.args.input), - \\"condition\\": $util.toJson($condition) -} -## [End] Prepare DynamoDB PutItem Request. **" -`; - -exports[`not to include createdAt and updatedAt field when timestamps is set to null 3`] = ` -"#set( $optionalNonNullableFields = [] ) -#foreach( $field in $optionalNonNullableFields ) - #if( $context.arguments.input.keySet().contains($field) && $util.isNull($context.args.input.get($field)) ) -$util.error(\\"An argument you marked as Non-Null is set to Null in the query or the body of your request.\\") - #end -#end -#if( $authCondition && $authCondition.expression != \\"\\" ) - #set( $condition = $authCondition ) - #if( $modelObjectKey ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#id)\\")) - $util.qr($condition.expressionNames.put(\\"#id\\", \\"id\\")) - #end -#else - #if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - #set( $condition = { - \\"expression\\": \\"attribute_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) - #end -#end -$util.qr($context.args.input.put(\\"__typename\\", \\"Post\\")) -## Update condition if type is @versioned ** -#if( $versionedCondition ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $versionedCondition.expression\\")) - $util.qr($condition.expressionNames.putAll($versionedCondition.expressionNames)) - $util.qr($condition.expressionValues.putAll($versionedCondition.expressionValues)) -#end -#if( $context.args.condition ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -#set( $expNames = {} ) -#set( $expValues = {} ) -#set( $expSet = {} ) -#set( $expAdd = {} ) -#set( $expRemove = [] ) -#if( $modelObjectKey ) - #set( $keyFields = [] ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($keyFields.add(\\"$entry.key\\")) - #end -#else - #set( $keyFields = [\\"id\\"] ) -#end -#foreach( $entry in $util.map.copyAndRemoveAllKeys($context.args.input, $keyFields).entrySet() ) - #if( !$util.isNull($dynamodbNameOverrideMap) && $dynamodbNameOverrideMap.containsKey(\\"$entry.key\\") ) - #set( $entryKeyAttributeName = $dynamodbNameOverrideMap.get(\\"$entry.key\\") ) - #else - #set( $entryKeyAttributeName = $entry.key ) - #end - #if( $util.isNull($entry.value) ) - #set( $discard = $expRemove.add(\\"#$entryKeyAttributeName\\") ) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - #else - $util.qr($expSet.put(\\"#$entryKeyAttributeName\\", \\":$entryKeyAttributeName\\")) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - $util.qr($expValues.put(\\":$entryKeyAttributeName\\", $util.dynamodb.toDynamoDB($entry.value))) - #end -#end -#set( $expression = \\"\\" ) -#if( !$expSet.isEmpty() ) - #set( $expression = \\"SET\\" ) - #foreach( $entry in $expSet.entrySet() ) - #set( $expression = \\"$expression $entry.key = $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expAdd.isEmpty() ) - #set( $expression = \\"$expression ADD\\" ) - #foreach( $entry in $expAdd.entrySet() ) - #set( $expression = \\"$expression $entry.key $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expRemove.isEmpty() ) - #set( $expression = \\"$expression REMOVE\\" ) - #foreach( $entry in $expRemove ) - #set( $expression = \\"$expression $entry\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#set( $update = {} ) -$util.qr($update.put(\\"expression\\", \\"$expression\\")) -#if( !$expNames.isEmpty() ) - $util.qr($update.put(\\"expressionNames\\", $expNames)) -#end -#if( !$expValues.isEmpty() ) - $util.qr($update.put(\\"expressionValues\\", $expValues)) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"UpdateItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": { - \\"S\\": $util.toJson($context.args.input.id) - } -} #end, - \\"update\\": $util.toJson($update), - \\"condition\\": $util.toJson($condition) -}" -`; - -exports[`only get does not generate superfluous input and filter types 1`] = ` -"type Entity { - id: ID! - str: String - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} - -type Query { - getEntity(id: ID!): Entity -} -" -`; - -exports[`resolver template not to auto generate createdAt and updatedAt when the type in schema is not AWSDateTime 1`] = ` -"type Post { - id: ID! - str: String - createdAt: AWSTimestamp - updatedAt: AWSTimestamp -} - -enum ModelSortDirection { - ASC - DESC -} - -type ModelPostConnection { - items: [Post]! - nextToken: String -} - -input ModelStringFilterInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String -} - -input ModelIDFilterInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID -} - -input ModelIntFilterInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelFloatFilterInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] -} - -input ModelBooleanFilterInput { - ne: Boolean - eq: Boolean -} - -input ModelPostFilterInput { - id: ModelIDFilterInput - str: ModelStringFilterInput - createdAt: ModelIntFilterInput - updatedAt: ModelIntFilterInput - and: [ModelPostFilterInput] - or: [ModelPostFilterInput] - not: ModelPostFilterInput -} - -type Query { - getPost(id: ID!): Post - listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection -} - -input CreatePostInput { - id: ID - str: String - createdAt: AWSTimestamp - updatedAt: AWSTimestamp -} - -input UpdatePostInput { - id: ID! - str: String - createdAt: AWSTimestamp - updatedAt: AWSTimestamp -} - -input DeletePostInput { - id: ID! -} - -type Mutation { - createPost(input: CreatePostInput!): Post - updatePost(input: UpdatePostInput!): Post - deletePost(input: DeletePostInput!): Post -} - -type Subscription { - onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) - onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) - onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) -} -" -`; - -exports[`resolver template not to auto generate createdAt and updatedAt when the type in schema is not AWSDateTime 2`] = ` -"## [Start] Set default values. ** -$util.qr($context.args.input.put(\\"id\\", $util.defaultIfNull($ctx.args.input.id, $util.autoId()))) -## [End] Set default values. ** -## [Start] Prepare DynamoDB PutItem Request. ** -$util.qr($context.args.input.put(\\"__typename\\", \\"Post\\")) -#if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_not_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_not_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end -#else - #set( $condition = { - \\"expression\\": \\"attribute_not_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) -#end -#if( $context.args.condition ) - #set( $condition.expressionValues = {} ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"PutItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": $util.dynamodb.toDynamoDBJson($ctx.args.input.id) -} #end, - \\"attributeValues\\": $util.dynamodb.toMapValuesJson($context.args.input), - \\"condition\\": $util.toJson($condition) -} -## [End] Prepare DynamoDB PutItem Request. **" -`; - -exports[`resolver template not to auto generate createdAt and updatedAt when the type in schema is not AWSDateTime 3`] = ` -"#set( $optionalNonNullableFields = [] ) -#foreach( $field in $optionalNonNullableFields ) - #if( $context.arguments.input.keySet().contains($field) && $util.isNull($context.args.input.get($field)) ) -$util.error(\\"An argument you marked as Non-Null is set to Null in the query or the body of your request.\\") - #end -#end -#if( $authCondition && $authCondition.expression != \\"\\" ) - #set( $condition = $authCondition ) - #if( $modelObjectKey ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#id)\\")) - $util.qr($condition.expressionNames.put(\\"#id\\", \\"id\\")) - #end -#else - #if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - #set( $condition = { - \\"expression\\": \\"attribute_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) - #end -#end -$util.qr($context.args.input.put(\\"__typename\\", \\"Post\\")) -## Update condition if type is @versioned ** -#if( $versionedCondition ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $versionedCondition.expression\\")) - $util.qr($condition.expressionNames.putAll($versionedCondition.expressionNames)) - $util.qr($condition.expressionValues.putAll($versionedCondition.expressionValues)) -#end -#if( $context.args.condition ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -#set( $expNames = {} ) -#set( $expValues = {} ) -#set( $expSet = {} ) -#set( $expAdd = {} ) -#set( $expRemove = [] ) -#if( $modelObjectKey ) - #set( $keyFields = [] ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($keyFields.add(\\"$entry.key\\")) - #end -#else - #set( $keyFields = [\\"id\\"] ) -#end -#foreach( $entry in $util.map.copyAndRemoveAllKeys($context.args.input, $keyFields).entrySet() ) - #if( !$util.isNull($dynamodbNameOverrideMap) && $dynamodbNameOverrideMap.containsKey(\\"$entry.key\\") ) - #set( $entryKeyAttributeName = $dynamodbNameOverrideMap.get(\\"$entry.key\\") ) - #else - #set( $entryKeyAttributeName = $entry.key ) - #end - #if( $util.isNull($entry.value) ) - #set( $discard = $expRemove.add(\\"#$entryKeyAttributeName\\") ) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - #else - $util.qr($expSet.put(\\"#$entryKeyAttributeName\\", \\":$entryKeyAttributeName\\")) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - $util.qr($expValues.put(\\":$entryKeyAttributeName\\", $util.dynamodb.toDynamoDB($entry.value))) - #end -#end -#set( $expression = \\"\\" ) -#if( !$expSet.isEmpty() ) - #set( $expression = \\"SET\\" ) - #foreach( $entry in $expSet.entrySet() ) - #set( $expression = \\"$expression $entry.key = $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expAdd.isEmpty() ) - #set( $expression = \\"$expression ADD\\" ) - #foreach( $entry in $expAdd.entrySet() ) - #set( $expression = \\"$expression $entry.key $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expRemove.isEmpty() ) - #set( $expression = \\"$expression REMOVE\\" ) - #foreach( $entry in $expRemove ) - #set( $expression = \\"$expression $entry\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#set( $update = {} ) -$util.qr($update.put(\\"expression\\", \\"$expression\\")) -#if( !$expNames.isEmpty() ) - $util.qr($update.put(\\"expressionNames\\", $expNames)) -#end -#if( !$expValues.isEmpty() ) - $util.qr($update.put(\\"expressionValues\\", $expValues)) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"UpdateItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": { - \\"S\\": $util.toJson($context.args.input.id) - } -} #end, - \\"update\\": $util.toJson($update), - \\"condition\\": $util.toJson($condition) -}" -`; - -exports[`schema includes attribute enum when only queries specified 1`] = ` -"type Entity { - id: ID! - str: String - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} - -enum ModelSortDirection { - ASC - DESC -} - -type ModelEntityConnection { - items: [Entity]! - nextToken: String -} - -input ModelStringInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String - attributeExists: Boolean - attributeType: ModelAttributeTypes - size: ModelSizeInput -} - -input ModelIDInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID - attributeExists: Boolean - attributeType: ModelAttributeTypes - size: ModelSizeInput -} - -input ModelIntInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelFloatInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelBooleanInput { - ne: Boolean - eq: Boolean - attributeExists: Boolean - attributeType: ModelAttributeTypes -} - -input ModelSizeInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelEntityFilterInput { - id: ModelIDInput - str: ModelStringInput - and: [ModelEntityFilterInput] - or: [ModelEntityFilterInput] - not: ModelEntityFilterInput -} - -enum ModelAttributeTypes { - binary - binarySet - bool - list - map - number - numberSet - string - stringSet - _null -} - -type Query { - getEntity(id: ID!): Entity - listEntities(filter: ModelEntityFilterInput, limit: Int, nextToken: String): ModelEntityConnection -} -" -`; - -exports[`timestamp parameters when generating resolvers and output schema 1`] = ` -"type Post { - id: ID! - str: String - createdOn: AWSDateTime! - updatedOn: AWSDateTime! -} - -enum ModelSortDirection { - ASC - DESC -} - -type ModelPostConnection { - items: [Post]! - nextToken: String -} - -input ModelStringFilterInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String -} - -input ModelIDFilterInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID -} - -input ModelIntFilterInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelFloatFilterInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] -} - -input ModelBooleanFilterInput { - ne: Boolean - eq: Boolean -} - -input ModelPostFilterInput { - id: ModelIDFilterInput - str: ModelStringFilterInput - and: [ModelPostFilterInput] - or: [ModelPostFilterInput] - not: ModelPostFilterInput -} - -type Query { - getPost(id: ID!): Post - listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection -} - -input CreatePostInput { - id: ID - str: String -} - -input UpdatePostInput { - id: ID! - str: String -} - -input DeletePostInput { - id: ID! -} - -type Mutation { - createPost(input: CreatePostInput!): Post - updatePost(input: UpdatePostInput!): Post - deletePost(input: DeletePostInput!): Post -} - -type Subscription { - onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) - onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) - onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) -} -" -`; - -exports[`timestamp parameters when generating resolvers and output schema 2`] = ` -"## [Start] Set default values. ** -$util.qr($context.args.input.put(\\"id\\", $util.defaultIfNull($ctx.args.input.id, $util.autoId()))) -#set( $createdAt = $util.time.nowISO8601() ) -## Automatically set the createdAt timestamp. ** -$util.qr($context.args.input.put(\\"createdOn\\", $util.defaultIfNull($ctx.args.input.createdOn, $createdAt))) -## Automatically set the updatedAt timestamp. ** -$util.qr($context.args.input.put(\\"updatedOn\\", $util.defaultIfNull($ctx.args.input.updatedOn, $createdAt))) -## [End] Set default values. ** -## [Start] Prepare DynamoDB PutItem Request. ** -$util.qr($context.args.input.put(\\"__typename\\", \\"Post\\")) -#if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_not_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_not_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end -#else - #set( $condition = { - \\"expression\\": \\"attribute_not_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) -#end -#if( $context.args.condition ) - #set( $condition.expressionValues = {} ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"PutItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": $util.dynamodb.toDynamoDBJson($ctx.args.input.id) -} #end, - \\"attributeValues\\": $util.dynamodb.toMapValuesJson($context.args.input), - \\"condition\\": $util.toJson($condition) -} -## [End] Prepare DynamoDB PutItem Request. **" -`; - -exports[`timestamp parameters when generating resolvers and output schema 3`] = ` -"#set( $optionalNonNullableFields = [] ) -#foreach( $field in $optionalNonNullableFields ) - #if( $context.arguments.input.keySet().contains($field) && $util.isNull($context.args.input.get($field)) ) -$util.error(\\"An argument you marked as Non-Null is set to Null in the query or the body of your request.\\") - #end -#end -#if( $authCondition && $authCondition.expression != \\"\\" ) - #set( $condition = $authCondition ) - #if( $modelObjectKey ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#id)\\")) - $util.qr($condition.expressionNames.put(\\"#id\\", \\"id\\")) - #end -#else - #if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - #set( $condition = { - \\"expression\\": \\"attribute_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) - #end -#end -## Automatically set the updatedAt timestamp. ** -$util.qr($context.args.input.put(\\"updatedOn\\", $util.defaultIfNull($ctx.args.input.updatedOn, $util.time.nowISO8601()))) -$util.qr($context.args.input.put(\\"__typename\\", \\"Post\\")) -## Update condition if type is @versioned ** -#if( $versionedCondition ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $versionedCondition.expression\\")) - $util.qr($condition.expressionNames.putAll($versionedCondition.expressionNames)) - $util.qr($condition.expressionValues.putAll($versionedCondition.expressionValues)) -#end -#if( $context.args.condition ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -#set( $expNames = {} ) -#set( $expValues = {} ) -#set( $expSet = {} ) -#set( $expAdd = {} ) -#set( $expRemove = [] ) -#if( $modelObjectKey ) - #set( $keyFields = [] ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($keyFields.add(\\"$entry.key\\")) - #end -#else - #set( $keyFields = [\\"id\\"] ) -#end -#foreach( $entry in $util.map.copyAndRemoveAllKeys($context.args.input, $keyFields).entrySet() ) - #if( !$util.isNull($dynamodbNameOverrideMap) && $dynamodbNameOverrideMap.containsKey(\\"$entry.key\\") ) - #set( $entryKeyAttributeName = $dynamodbNameOverrideMap.get(\\"$entry.key\\") ) - #else - #set( $entryKeyAttributeName = $entry.key ) - #end - #if( $util.isNull($entry.value) ) - #set( $discard = $expRemove.add(\\"#$entryKeyAttributeName\\") ) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - #else - $util.qr($expSet.put(\\"#$entryKeyAttributeName\\", \\":$entryKeyAttributeName\\")) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - $util.qr($expValues.put(\\":$entryKeyAttributeName\\", $util.dynamodb.toDynamoDB($entry.value))) - #end -#end -#set( $expression = \\"\\" ) -#if( !$expSet.isEmpty() ) - #set( $expression = \\"SET\\" ) - #foreach( $entry in $expSet.entrySet() ) - #set( $expression = \\"$expression $entry.key = $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expAdd.isEmpty() ) - #set( $expression = \\"$expression ADD\\" ) - #foreach( $entry in $expAdd.entrySet() ) - #set( $expression = \\"$expression $entry.key $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expRemove.isEmpty() ) - #set( $expression = \\"$expression REMOVE\\" ) - #foreach( $entry in $expRemove ) - #set( $expression = \\"$expression $entry\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#set( $update = {} ) -$util.qr($update.put(\\"expression\\", \\"$expression\\")) -#if( !$expNames.isEmpty() ) - $util.qr($update.put(\\"expressionNames\\", $expNames)) -#end -#if( !$expValues.isEmpty() ) - $util.qr($update.put(\\"expressionValues\\", $expValues)) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"UpdateItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": { - \\"S\\": $util.toJson($context.args.input.id) - } -} #end, - \\"update\\": $util.toJson($update), - \\"condition\\": $util.toJson($condition) -}" -`; diff --git a/packages/graphql-dynamodb-transformer/src/definitions.ts b/packages/graphql-dynamodb-transformer/src/definitions.ts deleted file mode 100644 index 1dbc51b175..0000000000 --- a/packages/graphql-dynamodb-transformer/src/definitions.ts +++ /dev/null @@ -1,814 +0,0 @@ -import { - ObjectTypeDefinitionNode, - InputObjectTypeDefinitionNode, - InputValueDefinitionNode, - FieldDefinitionNode, - Kind, - TypeNode, - EnumTypeDefinitionNode, - ObjectTypeExtensionNode, - NamedTypeNode, - DirectiveNode, - InterfaceTypeDefinitionNode, - EnumValueDefinitionNode, -} from 'graphql'; -import { - wrapNonNull, - unwrapNonNull, - isNonNullType, - makeNamedType, - toUpper, - graphqlName, - makeListType, - isScalar, - getBaseType, - blankObjectExtension, - extensionWithFields, - makeField, - makeInputValueDefinition, - ModelResourceIDs, - makeDirective, - makeArgument, - makeValueNode, - withNamedNodeNamed, - isListType, - makeNonNullType, -} from 'graphql-transformer-common'; -import { TransformerContext } from 'graphql-transformer-core'; -import { getCreatedAtFieldName, getUpdatedAtFieldName } from './ModelDirectiveArgs'; - -const STRING_CONDITIONS = ['ne', 'eq', 'le', 'lt', 'ge', 'gt', 'contains', 'notContains', 'between', 'beginsWith']; -const ID_CONDITIONS = ['ne', 'eq', 'le', 'lt', 'ge', 'gt', 'contains', 'notContains', 'between', 'beginsWith']; -const INT_CONDITIONS = ['ne', 'eq', 'le', 'lt', 'ge', 'gt', 'between']; -const FLOAT_CONDITIONS = ['ne', 'eq', 'le', 'lt', 'ge', 'gt', 'between']; -const BOOLEAN_CONDITIONS = ['ne', 'eq']; -const SIZE_CONDITIONS = ['ne', 'eq', 'le', 'lt', 'ge', 'gt', 'between']; - -const STRING_FUNCTIONS = new Set(['attributeExists', 'attributeType', 'size']); -const ID_FUNCTIONS = new Set(['attributeExists', 'attributeType', 'size']); -const INT_FUNCTIONS = new Set(['attributeExists', 'attributeType']); -const FLOAT_FUNCTIONS = new Set(['attributeExists', 'attributeType']); -const BOOLEAN_FUNCTIONS = new Set(['attributeExists', 'attributeType']); - -const ATTRIBUTE_TYPES = ['binary', 'binarySet', 'bool', 'list', 'map', 'number', 'numberSet', 'string', 'stringSet', '_null']; - -export function getNonModelObjectArray( - obj: ObjectTypeDefinitionNode, - ctx: TransformerContext, - pMap: Map, -): ObjectTypeDefinitionNode[] { - // loop over all fields in the object, picking out all nonscalars that are not @model types - for (const field of obj.fields) { - if (!isScalar(field.type)) { - const def = ctx.getType(getBaseType(field.type)); - - if ( - def && - def.kind === Kind.OBJECT_TYPE_DEFINITION && - !def.directives.find((e) => e.name.value === 'model') && - pMap.get(def.name.value) === undefined - ) { - // recursively find any non @model types referenced by the current - // non @model type - pMap.set(def.name.value, def); - getNonModelObjectArray(def, ctx, pMap); - } - } - } - - return Array.from(pMap.values()); -} - -export function makeNonModelInputObject( - obj: ObjectTypeDefinitionNode, - nonModelTypes: ObjectTypeDefinitionNode[], - ctx: TransformerContext, -): InputObjectTypeDefinitionNode { - const name = ModelResourceIDs.NonModelInputObjectName(obj.name.value); - const fields: InputValueDefinitionNode[] = obj.fields - .filter((field: FieldDefinitionNode) => { - const fieldType = ctx.getType(getBaseType(field.type)); - if ( - isScalar(field.type) || - nonModelTypes.find((e) => e.name.value === getBaseType(field.type)) || - (fieldType && fieldType.kind === Kind.ENUM_TYPE_DEFINITION) - ) { - return true; - } - return false; - }) - .map((field: FieldDefinitionNode) => { - const type = nonModelTypes.find((e) => e.name.value === getBaseType(field.type)) - ? withNamedNodeNamed(field.type, ModelResourceIDs.NonModelInputObjectName(getBaseType(field.type))) - : field.type; - return { - kind: Kind.INPUT_VALUE_DEFINITION, - name: field.name, - type, - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - }; - }); - return { - kind: 'InputObjectTypeDefinition', - // TODO: Service does not support new style descriptions so wait. - // description: { - // kind: 'StringValue', - // value: `Input type for ${obj.name.value} mutations` - // }, - name: { - kind: 'Name', - value: name, - }, - fields, - directives: [], - }; -} - -export function makeCreateInputObject( - obj: ObjectTypeDefinitionNode, - directive: DirectiveNode, - nonModelTypes: ObjectTypeDefinitionNode[], - ctx: TransformerContext, - isSync: boolean = false, -): InputObjectTypeDefinitionNode { - const name = ModelResourceIDs.ModelCreateInputObjectName(obj.name.value); - const createdAtField = getCreatedAtFieldName(directive); - const updatedAtField = getUpdatedAtFieldName(directive); - - // List of fields that can be assigend in resolver if they are not passed in input - const autoGeneratableFieldsWithType: Record = { - id: ['ID'], - [createdAtField]: ['AWSDateTime', 'String'], - [updatedAtField]: ['AWSDateTime', 'String'], - }; - - const hasIdField = obj.fields.find((f) => f.name.value === 'id'); - const fields: InputValueDefinitionNode[] = obj.fields - .filter((field: FieldDefinitionNode) => { - const fieldType = ctx.getType(getBaseType(field.type)); - if ( - isScalar(field.type) || - nonModelTypes.find((e) => e.name.value === getBaseType(field.type)) || - (fieldType && fieldType.kind === Kind.ENUM_TYPE_DEFINITION) - ) { - return true; - } - return false; - }) - .map((field: FieldDefinitionNode) => { - let type: TypeNode; - const fieldName = field.name.value; - if ( - Object.keys(autoGeneratableFieldsWithType).indexOf(fieldName) !== -1 && - autoGeneratableFieldsWithType[fieldName].indexOf(unwrapNonNull(field.type).name.value) !== -1 - ) { - // ids are always optional. when provided the value is used. - // when not provided the value is not used. - type = unwrapNonNull(field.type); - } else { - type = nonModelTypes.find((e) => e.name.value === getBaseType(field.type)) - ? withNamedNodeNamed(field.type, ModelResourceIDs.NonModelInputObjectName(getBaseType(field.type))) - : field.type; - } - return { - kind: Kind.INPUT_VALUE_DEFINITION, - name: field.name, - type, - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - }; - }); - // add the version if this project is a sync project - if (isSync) { - fields.push(makeInputValueDefinition('_version', makeNamedType('Int'))); - } - return { - kind: 'InputObjectTypeDefinition', - // TODO: Service does not support new style descriptions so wait. - // description: { - // kind: 'StringValue', - // value: `Input type for ${obj.name.value} mutations` - // }, - name: { - kind: 'Name', - value: name, - }, - fields: [ - // add default id field and expose that - ...(hasIdField ? [] : [makeInputValueDefinition('id', makeNamedType('ID'))]), - ...fields, - ], - directives: [], - }; -} -export function getFieldsOptionalNonNullableField(fields: InputValueDefinitionNode[], obj: ObjectTypeDefinitionNode): string[] { - const fieldMap = fields.reduce((map, field) => { - map.set(field.name.value, field); - return map; - }, new Map()); - - return obj.fields - .filter( - (r) => - fieldMap.has(r.name.value) && // field exists in the model - isNonNullType(r.type) && // field was non null type in model - fieldMap.get(r.name.value).type.kind !== Kind.NON_NULL_TYPE, // field is not nullable type in update mutation model - ) - .map((r) => r.name.value); -} - -export function makeUpdateInputObject( - obj: ObjectTypeDefinitionNode, - nonModelTypes: ObjectTypeDefinitionNode[], - ctx: TransformerContext, - isSync: boolean = false, -): InputObjectTypeDefinitionNode { - const name = ModelResourceIDs.ModelUpdateInputObjectName(obj.name.value); - const hasIdField = obj.fields.find((f) => f.name.value === 'id'); - const fields: InputValueDefinitionNode[] = obj.fields - .filter((f) => { - const fieldType = ctx.getType(getBaseType(f.type)); - if ( - isScalar(f.type) || - nonModelTypes.find((e) => e.name.value === getBaseType(f.type)) || - (fieldType && fieldType.kind === Kind.ENUM_TYPE_DEFINITION) - ) { - return true; - } - return false; - }) - .map((field: FieldDefinitionNode) => { - let type; - if (field.name.value === 'id') { - type = wrapNonNull(field.type); - } else { - type = unwrapNonNull(field.type); - } - type = nonModelTypes.find((e) => e.name.value === getBaseType(field.type)) - ? withNamedNodeNamed(type, ModelResourceIDs.NonModelInputObjectName(getBaseType(field.type))) - : type; - return { - kind: Kind.INPUT_VALUE_DEFINITION, - name: field.name, - type, - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - }; - }); - if (isSync) { - fields.push(makeInputValueDefinition('_version', makeNamedType('Int'))); - } - return { - kind: Kind.INPUT_OBJECT_TYPE_DEFINITION, - // TODO: Service does not support new style descriptions so wait. - // description: { - // kind: 'StringValue', - // value: `Input type for ${obj.name.value} mutations` - // }, - name: { - kind: 'Name', - value: name, - }, - fields: [ - // add default id field and expose that - ...(hasIdField ? [] : [makeInputValueDefinition('id', makeNonNullType(makeNamedType('ID')))]), - ...fields, - ], - directives: [], - }; -} - -export function makeDeleteInputObject(obj: ObjectTypeDefinitionNode, isSync: boolean = false): InputObjectTypeDefinitionNode { - const name = ModelResourceIDs.ModelDeleteInputObjectName(obj.name.value); - const fields: InputValueDefinitionNode[] = [ - { - kind: Kind.INPUT_VALUE_DEFINITION, - name: { kind: 'Name', value: 'id' }, - type: wrapNonNull(makeNamedType('ID')), - // TODO: Service does not support new style descriptions so wait. - // description: { - // kind: 'StringValue', - // value: `The id of the ${obj.name.value} to delete.` - // }, - directives: [], - }, - ]; - if (isSync) { - fields.push(makeInputValueDefinition('_version', makeNamedType('Int'))); - } - return { - kind: Kind.INPUT_OBJECT_TYPE_DEFINITION, - // TODO: Service does not support new style descriptions so wait. - // description: { - // kind: 'StringValue', - // value: `Input type for ${obj.name.value} delete mutations` - // }, - name: { - kind: 'Name', - value: name, - }, - fields, - directives: [], - }; -} - -export function makeModelXFilterInputObject( - obj: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, - ctx: TransformerContext, - supportsConditions: Boolean, -): InputObjectTypeDefinitionNode { - const name = ModelResourceIDs.ModelFilterInputTypeName(obj.name.value); - const fields: InputValueDefinitionNode[] = obj.fields - .filter((field: FieldDefinitionNode) => { - const fieldType = ctx.getType(getBaseType(field.type)); - if (isScalar(field.type) || (fieldType && fieldType.kind === Kind.ENUM_TYPE_DEFINITION)) { - return true; - } - }) - .map((field: FieldDefinitionNode) => { - const baseType = getBaseType(field.type); - const fieldType = ctx.getType(baseType); - const isList = isListType(field.type); - const isEnumType = fieldType && fieldType.kind === Kind.ENUM_TYPE_DEFINITION; - const filterTypeName = - isEnumType && isList - ? ModelResourceIDs.ModelFilterListInputTypeName(baseType, !supportsConditions) - : ModelResourceIDs.ModelScalarFilterInputTypeName(baseType, !supportsConditions); - - return { - kind: Kind.INPUT_VALUE_DEFINITION, - name: field.name, - type: makeNamedType(filterTypeName), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - }; - }); - - fields.push( - { - kind: Kind.INPUT_VALUE_DEFINITION, - name: { - kind: 'Name', - value: 'and', - }, - type: makeListType(makeNamedType(name)), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - }, - { - kind: Kind.INPUT_VALUE_DEFINITION, - name: { - kind: 'Name', - value: 'or', - }, - type: makeListType(makeNamedType(name)), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - }, - { - kind: Kind.INPUT_VALUE_DEFINITION, - name: { - kind: 'Name', - value: 'not', - }, - type: makeNamedType(name), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - }, - ); - - return { - kind: 'InputObjectTypeDefinition', - // TODO: Service does not support new style descriptions so wait. - // description: { - // kind: 'StringValue', - // value: `Input type for ${obj.name.value} mutations` - // }, - name: { - kind: 'Name', - value: name, - }, - fields, - directives: [], - }; -} - -export function makeModelXConditionInputObject( - obj: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, - ctx: TransformerContext, - supportsConditions: Boolean, -): InputObjectTypeDefinitionNode { - const name = ModelResourceIDs.ModelConditionInputTypeName(obj.name.value); - const fields: InputValueDefinitionNode[] = obj.fields - .filter((field: FieldDefinitionNode) => { - const fieldType = ctx.getType(getBaseType(field.type)); - if (isScalar(field.type) || (fieldType && fieldType.kind === Kind.ENUM_TYPE_DEFINITION)) { - return true; - } - }) - .map((field: FieldDefinitionNode) => { - const baseType = getBaseType(field.type); - const fieldType = ctx.getType(baseType); - const isList = isListType(field.type); - const isEnumType = fieldType && fieldType.kind === Kind.ENUM_TYPE_DEFINITION; - const conditionTypeName = - isEnumType && isList - ? ModelResourceIDs.ModelFilterListInputTypeName(baseType, !supportsConditions) - : ModelResourceIDs.ModelScalarFilterInputTypeName(baseType, !supportsConditions); - - return { - kind: Kind.INPUT_VALUE_DEFINITION, - name: field.name, - type: makeNamedType(conditionTypeName), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - }; - }); - - fields.push( - { - kind: Kind.INPUT_VALUE_DEFINITION, - name: { - kind: 'Name', - value: 'and', - }, - type: makeListType(makeNamedType(name)), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - }, - { - kind: Kind.INPUT_VALUE_DEFINITION, - name: { - kind: 'Name', - value: 'or', - }, - type: makeListType(makeNamedType(name)), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - }, - { - kind: Kind.INPUT_VALUE_DEFINITION, - name: { - kind: 'Name', - value: 'not', - }, - type: makeNamedType(name), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - }, - ); - - return { - kind: 'InputObjectTypeDefinition', - // TODO: Service does not support new style descriptions so wait. - // description: { - // kind: 'StringValue', - // value: `Input type for ${obj.name.value} mutations` - // }, - name: { - kind: 'Name', - value: name, - }, - fields, - directives: [], - }; -} - -export function makeEnumFilterInputObjects( - obj: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, - ctx: TransformerContext, - supportsConditions: Boolean, -): InputObjectTypeDefinitionNode[] { - return obj.fields - .filter((field: FieldDefinitionNode) => { - const fieldType = ctx.getType(getBaseType(field.type)); - return fieldType && fieldType.kind === Kind.ENUM_TYPE_DEFINITION; - }) - .map((enumField: FieldDefinitionNode) => { - const typeName = getBaseType(enumField.type); - const isList = isListType(enumField.type); - const name = isList - ? ModelResourceIDs.ModelFilterListInputTypeName(typeName, !supportsConditions) - : ModelResourceIDs.ModelScalarFilterInputTypeName(typeName, !supportsConditions); - const fields = []; - - fields.push({ - kind: Kind.INPUT_VALUE_DEFINITION, - name: { - kind: 'Name', - value: 'eq', - }, - type: isList ? makeListType(makeNamedType(typeName)) : makeNamedType(typeName), - directives: [], - }); - - fields.push({ - kind: Kind.INPUT_VALUE_DEFINITION, - name: { - kind: 'Name', - value: 'ne', - }, - type: isList ? makeListType(makeNamedType(typeName)) : makeNamedType(typeName), - directives: [], - }); - - if (isList) { - fields.push({ - kind: Kind.INPUT_VALUE_DEFINITION, - name: { - kind: 'Name', - value: 'contains', - }, - type: makeNamedType(typeName), - directives: [], - }); - - fields.push({ - kind: Kind.INPUT_VALUE_DEFINITION, - name: { - kind: 'Name', - value: 'notContains', - }, - type: makeNamedType(typeName), - directives: [], - }); - } - - return { - kind: Kind.INPUT_OBJECT_TYPE_DEFINITION, - name: { - kind: 'Name', - value: name, - }, - fields, - directives: [], - } as InputObjectTypeDefinitionNode; - }); -} - -export function makeModelSortDirectionEnumObject(): EnumTypeDefinitionNode { - const name = graphqlName('ModelSortDirection'); - return { - kind: Kind.ENUM_TYPE_DEFINITION, - name: { - kind: 'Name', - value: name, - }, - values: [ - { - kind: Kind.ENUM_VALUE_DEFINITION, - name: { kind: 'Name', value: 'ASC' }, - directives: [], - }, - { - kind: Kind.ENUM_VALUE_DEFINITION, - name: { kind: 'Name', value: 'DESC' }, - directives: [], - }, - ], - directives: [], - }; -} - -export function makeModelScalarFilterInputObject(type: string, supportsConditions: Boolean): InputObjectTypeDefinitionNode { - const name = ModelResourceIDs.ModelFilterScalarInputTypeName(type, !supportsConditions); - const conditions = getScalarConditions(type); - const fields: InputValueDefinitionNode[] = conditions.map((condition: string) => ({ - kind: Kind.INPUT_VALUE_DEFINITION, - name: { kind: 'Name' as const, value: condition }, - type: getScalarFilterInputType(condition, type, name), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - })); - let functionInputFields = []; - if (supportsConditions) { - functionInputFields = makeFunctionInputFields(type); - } - return { - kind: Kind.INPUT_OBJECT_TYPE_DEFINITION, - // TODO: Service does not support new style descriptions so wait. - // description: { - // kind: 'StringValue', - // value: `Input type for ${obj.name.value} mutations` - // }, - name: { - kind: 'Name', - value: name, - }, - fields: [...fields, ...functionInputFields], - directives: [], - }; -} - -function getScalarFilterInputType(condition: string, type: string, filterInputName: string): TypeNode { - switch (condition) { - case 'between': - return makeListType(makeNamedType(type)); - case 'and': - case 'or': - return makeNamedType(filterInputName); - default: - return makeNamedType(type); - } -} - -function getScalarConditions(type: string): string[] { - switch (type) { - case 'String': - return STRING_CONDITIONS; - case 'ID': - return ID_CONDITIONS; - case 'Int': - return INT_CONDITIONS; - case 'Float': - return FLOAT_CONDITIONS; - case 'Boolean': - return BOOLEAN_CONDITIONS; - default: - throw new Error('Valid types are String, ID, Int, Float, Boolean'); - } -} - -function makeSizeInputType(): InputObjectTypeDefinitionNode { - const name = ModelResourceIDs.ModelSizeInputTypeName(); - const fields: InputValueDefinitionNode[] = SIZE_CONDITIONS.map((condition: string) => ({ - kind: Kind.INPUT_VALUE_DEFINITION, - name: { kind: 'Name' as const, value: condition }, - type: getScalarFilterInputType(condition, 'Int', '' /* unused */), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - })); - return { - kind: Kind.INPUT_OBJECT_TYPE_DEFINITION, - // TODO: Service does not support new style descriptions so wait. - // description: { - // kind: 'StringValue', - // value: `Input type for ${obj.name.value} mutations` - // }, - name: { - kind: 'Name', - value: name, - }, - fields, - directives: [], - }; -} - -function getFunctionListForType(typeName: string): Set { - switch (typeName) { - case 'String': - return STRING_FUNCTIONS; - case 'ID': - return ID_FUNCTIONS; - case 'Int': - return INT_FUNCTIONS; - case 'Float': - return FLOAT_FUNCTIONS; - case 'Boolean': - return BOOLEAN_FUNCTIONS; - default: - throw new Error('Valid types are String, ID, Int, Float, Boolean'); - } -} - -function makeFunctionInputFields(typeName: string): InputValueDefinitionNode[] { - const functions = getFunctionListForType(typeName); - const fields = new Array(); - - if (functions.has('attributeExists')) { - fields.push({ - kind: Kind.INPUT_VALUE_DEFINITION, - name: { kind: 'Name' as const, value: 'attributeExists' }, - type: makeNamedType('Boolean'), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - }); - } - - if (functions.has('attributeType')) { - fields.push({ - kind: Kind.INPUT_VALUE_DEFINITION, - name: { kind: 'Name' as const, value: 'attributeType' }, - type: makeNamedType(ModelResourceIDs.ModelAttributeTypesName()), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - }); - } - - if (functions.has('size')) { - fields.push({ - kind: Kind.INPUT_VALUE_DEFINITION, - name: { kind: 'Name' as const, value: 'size' }, - type: makeNamedType(ModelResourceIDs.ModelSizeInputTypeName()), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - }); - } - - return fields; -} - -export function makeAttributeTypeEnum(): EnumTypeDefinitionNode { - const makeEnumValue = (enumValue: string): EnumValueDefinitionNode => ({ - kind: Kind.ENUM_VALUE_DEFINITION, - name: { kind: 'Name' as const, value: enumValue }, - directives: [], - }); - - return { - kind: Kind.ENUM_TYPE_DEFINITION, - name: { kind: 'Name' as const, value: ModelResourceIDs.ModelAttributeTypesName() }, - values: ATTRIBUTE_TYPES.map((t) => makeEnumValue(t)), - directives: [], - }; -} - -export function makeModelConnectionType(typeName: string, isSync: Boolean = false): ObjectTypeExtensionNode { - const connectionName = ModelResourceIDs.ModelConnectionTypeName(typeName); - let connectionTypeExtension = blankObjectExtension(connectionName); - connectionTypeExtension = extensionWithFields(connectionTypeExtension, [ - makeField('items', [], makeNonNullType(makeListType(makeNamedType(typeName)))), - ]); - connectionTypeExtension = extensionWithFields(connectionTypeExtension, [makeField('nextToken', [], makeNamedType('String'))]); - if (isSync) { - connectionTypeExtension = extensionWithFields(connectionTypeExtension, [makeField('startedAt', [], makeNamedType('AWSTimestamp'))]); - } - return connectionTypeExtension; -} - -export function makeSubscriptionField(fieldName: string, returnTypeName: string, mutations: string[]): FieldDefinitionNode { - return makeField(fieldName, [], makeNamedType(returnTypeName), [ - makeDirective('aws_subscribe', [makeArgument('mutations', makeValueNode(mutations))]), - ]); -} - -export type SortKeyFieldInfoTypeName = 'Composite' | string; - -export interface SortKeyFieldInfo { - // The name of the sort key field. - fieldName: string; - // The GraphQL type of the sort key field. - typeName: SortKeyFieldInfoTypeName; - // Name of the model this field is on. - model?: string; - // The name of the key that this sortKey is on. - keyName?: string; -} - -export function makeModelConnectionField( - fieldName: string, - returnTypeName: string, - sortKeyInfo?: SortKeyFieldInfo, - directives?: DirectiveNode[], -): FieldDefinitionNode { - const args = [ - makeInputValueDefinition('filter', makeNamedType(ModelResourceIDs.ModelFilterInputTypeName(returnTypeName))), - makeInputValueDefinition('sortDirection', makeNamedType('ModelSortDirection')), - makeInputValueDefinition('limit', makeNamedType('Int')), - makeInputValueDefinition('nextToken', makeNamedType('String')), - ]; - if (sortKeyInfo) { - let namedType: NamedTypeNode; - if (sortKeyInfo.typeName === 'Composite') { - namedType = makeNamedType(ModelResourceIDs.ModelCompositeKeyConditionInputTypeName(sortKeyInfo.model, toUpper(sortKeyInfo.keyName))); - } else { - namedType = makeNamedType(ModelResourceIDs.ModelKeyConditionInputTypeName(sortKeyInfo.typeName)); - } - - args.unshift(makeInputValueDefinition(sortKeyInfo.fieldName, namedType)); - } - return makeField(fieldName, args, makeNamedType(ModelResourceIDs.ModelConnectionTypeName(returnTypeName)), directives); -} - -export function makeScalarFilterInputs(supportsConditions: Boolean): InputObjectTypeDefinitionNode[] { - const inputs = [ - makeModelScalarFilterInputObject('String', supportsConditions), - makeModelScalarFilterInputObject('ID', supportsConditions), - makeModelScalarFilterInputObject('Int', supportsConditions), - makeModelScalarFilterInputObject('Float', supportsConditions), - makeModelScalarFilterInputObject('Boolean', supportsConditions), - ]; - - if (supportsConditions) { - inputs.push(makeSizeInputType()); - } - - return inputs; -} diff --git a/packages/graphql-dynamodb-transformer/src/index.ts b/packages/graphql-dynamodb-transformer/src/index.ts deleted file mode 100644 index 701b1a07ea..0000000000 --- a/packages/graphql-dynamodb-transformer/src/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './DynamoDBModelTransformer'; -export * from './definitions'; -export * from './ModelDirectiveArgs'; -// No-op change to trigger re-publish diff --git a/packages/graphql-dynamodb-transformer/src/resources.ts b/packages/graphql-dynamodb-transformer/src/resources.ts deleted file mode 100644 index 49cb397741..0000000000 --- a/packages/graphql-dynamodb-transformer/src/resources.ts +++ /dev/null @@ -1,870 +0,0 @@ -import { DynamoDB, AppSync, IAM, Fn, StringParameter, NumberParameter, Refs, IntrinsicFunction, DeletionPolicy } from 'cloudform-types'; -import Output from 'cloudform-types/types/output'; -import { - DynamoDBMappingTemplate, - printBlock, - str, - print, - ref, - obj, - set, - nul, - ifElse, - compoundExpression, - qref, - bool, - equals, - iff, - raw, - comment, - forEach, - list, - and, - RESOLVER_VERSION_ID, - Expression, -} from 'graphql-mapping-template'; -import { - ResourceConstants, - plurality, - graphqlName, - toUpper, - ModelResourceIDs, - SyncResourceIDs, - getBaseType, -} from 'graphql-transformer-common'; -import { plural } from 'pluralize'; -import { SyncConfig, SyncUtils } from 'graphql-transformer-core'; -import Template from 'cloudform-types/types/template'; -import md5 from 'md5'; -import { InputObjectTypeDefinitionNode } from 'graphql'; - -type MutationResolverInput = { - type: string; - syncConfig: SyncConfig; - nameOverride?: string; - mutationTypeName?: string; - timestamps?: { - createdAtField?: string; - updatedAtField?: string; - }; -}; - -type MutationUpdateResolverInput = MutationResolverInput & { - optionalNonNullableFields: string[]; -}; - -export class ResourceFactory { - public makeParams() { - return { - [ResourceConstants.PARAMETERS.DynamoDBModelTableReadIOPS]: new NumberParameter({ - Description: 'The number of read IOPS the table should support.', - Default: 5, - }), - [ResourceConstants.PARAMETERS.DynamoDBModelTableWriteIOPS]: new NumberParameter({ - Description: 'The number of write IOPS the table should support.', - Default: 5, - }), - [ResourceConstants.PARAMETERS.DynamoDBBillingMode]: new StringParameter({ - Description: 'Configure @model types to create DynamoDB tables with PAY_PER_REQUEST or PROVISIONED billing modes.', - Default: 'PAY_PER_REQUEST', - AllowedValues: ['PAY_PER_REQUEST', 'PROVISIONED'], - }), - [ResourceConstants.PARAMETERS.DynamoDBEnablePointInTimeRecovery]: new StringParameter({ - Description: 'Whether to enable Point in Time Recovery on the table', - Default: 'false', - AllowedValues: ['true', 'false'], - }), - [ResourceConstants.PARAMETERS.DynamoDBEnableServerSideEncryption]: new StringParameter({ - Description: 'Enable server side encryption powered by KMS.', - Default: 'true', - AllowedValues: ['true', 'false'], - }), - }; - } - - /** - * Creates the barebones template for an application. - */ - public initTemplate(): Template { - return { - Parameters: this.makeParams(), - Resources: { - [ResourceConstants.RESOURCES.GraphQLAPILogicalID]: this.makeAppSyncAPI(), - }, - Outputs: { - [ResourceConstants.OUTPUTS.GraphQLAPIIdOutput]: this.makeAPIIDOutput(), - [ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput]: this.makeAPIEndpointOutput(), - }, - Conditions: { - [ResourceConstants.CONDITIONS.ShouldUsePayPerRequestBilling]: Fn.Equals( - Fn.Ref(ResourceConstants.PARAMETERS.DynamoDBBillingMode), - 'PAY_PER_REQUEST', - ), - - [ResourceConstants.CONDITIONS.ShouldUsePointInTimeRecovery]: Fn.Equals( - Fn.Ref(ResourceConstants.PARAMETERS.DynamoDBEnablePointInTimeRecovery), - 'true', - ), - [ResourceConstants.CONDITIONS.ShouldUseServerSideEncryption]: Fn.Equals( - Fn.Ref(ResourceConstants.PARAMETERS.DynamoDBEnableServerSideEncryption), - 'true', - ), - }, - }; - } - - /** - * Create the AppSync API. - */ - public makeAppSyncAPI() { - return new AppSync.GraphQLApi({ - Name: Fn.If( - ResourceConstants.CONDITIONS.HasEnvironmentParameter, - Fn.Join('-', [Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiName), Fn.Ref(ResourceConstants.PARAMETERS.Env)]), - Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiName), - ), - AuthenticationType: 'API_KEY', - }); - } - - public makeAppSyncSchema(schema: string) { - return new AppSync.GraphQLSchema({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - Definition: schema, - }); - } - - /** - * Outputs - */ - public makeAPIIDOutput(): Output { - return { - Description: 'Your GraphQL API ID.', - Value: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - Export: { - Name: Fn.Join(':', [Refs.StackName, 'GraphQLApiId']), - }, - }; - } - - public makeAPIEndpointOutput(): Output { - return { - Description: 'Your GraphQL API endpoint.', - Value: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'GraphQLUrl'), - Export: { - Name: Fn.Join(':', [Refs.StackName, 'GraphQLApiEndpoint']), - }, - }; - } - - public makeTableStreamArnOutput(resourceId: string): Output { - return { - Description: 'Your DynamoDB table StreamArn.', - Value: Fn.GetAtt(resourceId, 'StreamArn'), - Export: { - Name: Fn.Join(':', [Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), 'GetAtt', resourceId, 'StreamArn']), - }, - }; - } - - public makeDataSourceOutput(resourceId: string): Output { - return { - Description: 'Your model DataSource name.', - Value: Fn.GetAtt(resourceId, 'Name'), - Export: { - Name: Fn.Join(':', [Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), 'GetAtt', resourceId, 'Name']), - }, - }; - } - - public makeTableNameOutput(resourceId: string): Output { - return { - Description: 'Your DynamoDB table name.', - Value: Fn.Ref(resourceId), - Export: { - Name: Fn.Join(':', [Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), 'GetAtt', resourceId, 'Name']), - }, - }; - } - - /** - * Create a DynamoDB table for a specific type. - */ - public makeModelTable( - typeName: string, - hashKey: string = 'id', - rangeKey?: string, - deletionPolicy: DeletionPolicy = DeletionPolicy.Delete, - isSyncEnabled: boolean = false, - ) { - const keySchema = - hashKey && rangeKey - ? [ - { - AttributeName: hashKey, - KeyType: 'HASH', - }, - { - AttributeName: rangeKey, - KeyType: 'RANGE', - }, - ] - : [{ AttributeName: hashKey, KeyType: 'HASH' }]; - const attributeDefinitions = - hashKey && rangeKey - ? [ - { - AttributeName: hashKey, - AttributeType: 'S', - }, - { - AttributeName: rangeKey, - AttributeType: 'S', - }, - ] - : [{ AttributeName: hashKey, AttributeType: 'S' }]; - return new DynamoDB.Table({ - TableName: this.dynamoDBTableName(typeName), - KeySchema: keySchema, - AttributeDefinitions: attributeDefinitions, - StreamSpecification: { - StreamViewType: 'NEW_AND_OLD_IMAGES', - }, - BillingMode: Fn.If(ResourceConstants.CONDITIONS.ShouldUsePayPerRequestBilling, 'PAY_PER_REQUEST', Refs.NoValue), - ProvisionedThroughput: Fn.If(ResourceConstants.CONDITIONS.ShouldUsePayPerRequestBilling, Refs.NoValue, { - ReadCapacityUnits: Fn.Ref(ResourceConstants.PARAMETERS.DynamoDBModelTableReadIOPS), - WriteCapacityUnits: Fn.Ref(ResourceConstants.PARAMETERS.DynamoDBModelTableWriteIOPS), - }) as any, - SSESpecification: { - SSEEnabled: Fn.If(ResourceConstants.CONDITIONS.ShouldUseServerSideEncryption, true, false), - }, - PointInTimeRecoverySpecification: Fn.If( - ResourceConstants.CONDITIONS.ShouldUsePointInTimeRecovery, - { - PointInTimeRecoveryEnabled: true, - }, - Refs.NoValue, - ) as any, - ...(isSyncEnabled && { - TimeToLiveSpecification: SyncUtils.syncTTLConfig(), - }), - }).deletionPolicy(deletionPolicy); - } - - private dynamoDBTableName(typeName: string): IntrinsicFunction { - return Fn.If( - ResourceConstants.CONDITIONS.HasEnvironmentParameter, - Fn.Join('-', [ - typeName, - Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - Fn.Ref(ResourceConstants.PARAMETERS.Env), - ]), - Fn.Join('-', [typeName, Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId')]), - ); - } - - /** - * Create a single role that has access to all the resources created by the - * transform. - * @param name The name of the IAM role to create. - */ - public makeIAMRole(typeName: string, syncConfig?: SyncConfig) { - return new IAM.Role({ - RoleName: Fn.If( - ResourceConstants.CONDITIONS.HasEnvironmentParameter, - Fn.Join('-', [ - typeName.slice(0, 14) + md5(typeName).slice(15, 21), // max of 64. 64-10-26-4-3 = 21 - 'role', // 4 - Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), // 26 - Fn.Ref(ResourceConstants.PARAMETERS.Env), // 10 - ]), - Fn.Join('-', [ - typeName.slice(0, 24) + md5(typeName).slice(25, 31), // max of 64. 64-26-4-3 = 31 - 'role', - Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - ]), - ), - AssumeRolePolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Principal: { - Service: 'appsync.amazonaws.com', - }, - Action: 'sts:AssumeRole', - }, - ], - }, - Policies: [ - new IAM.Role.Policy({ - PolicyName: 'DynamoDBAccess', - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Action: [ - 'dynamodb:BatchGetItem', - 'dynamodb:BatchWriteItem', - 'dynamodb:PutItem', - 'dynamodb:DeleteItem', - 'dynamodb:GetItem', - 'dynamodb:Scan', - 'dynamodb:Query', - 'dynamodb:UpdateItem', - ], - Resource: [ - Fn.Sub('arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tablename}', { - tablename: this.dynamoDBTableName(typeName), - }), - Fn.Sub('arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tablename}/*', { - tablename: this.dynamoDBTableName(typeName), - }), - ...(syncConfig - ? [ - Fn.Sub('arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tablename}', { - tablename: Fn.If( - ResourceConstants.CONDITIONS.HasEnvironmentParameter, - Fn.Join('-', [ - SyncResourceIDs.syncTableName, - Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - Fn.Ref(ResourceConstants.PARAMETERS.Env), - ]), - Fn.Join('-', [ - SyncResourceIDs.syncTableName, - Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - ]), - ), - }), - Fn.Sub('arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tablename}/*', { - tablename: Fn.If( - ResourceConstants.CONDITIONS.HasEnvironmentParameter, - Fn.Join('-', [ - SyncResourceIDs.syncTableName, - Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - Fn.Ref(ResourceConstants.PARAMETERS.Env), - ]), - Fn.Join('-', [ - SyncResourceIDs.syncTableName, - Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - ]), - ), - }), - ] - : []), - ], - }, - ], - }, - }), - ...(syncConfig && SyncUtils.isLambdaSyncConfig(syncConfig) - ? [SyncUtils.createSyncLambdaIAMPolicy(syncConfig.LambdaConflictHandler)] - : []), - ], - }); - } - - /** - * Given the name of a data source and optional logical id return a CF - * spec for a data source pointing to the dynamodb table. - */ - public makeDynamoDBDataSource(tableId: string, iamRoleLogicalID: string, typeName: string, isSyncEnabled: boolean = false) { - return new AppSync.DataSource({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - Name: tableId, - Type: 'AMAZON_DYNAMODB', - ServiceRoleArn: Fn.GetAtt(iamRoleLogicalID, 'Arn'), - DynamoDBConfig: { - AwsRegion: Refs.Region, - TableName: this.dynamoDBTableName(typeName), - ...(isSyncEnabled && { - DeltaSyncConfig: SyncUtils.syncDataSourceConfig(), - Versioned: true, - }), - }, - }).dependsOn([iamRoleLogicalID]); - } - - /** - * Create a resolver that creates an item in DynamoDB. - * @param type - */ - public makeCreateResolver({ type, nameOverride, syncConfig, mutationTypeName = 'Mutation' }: MutationResolverInput) { - const fieldName = nameOverride ? nameOverride : graphqlName('create' + toUpper(type)); - const isSyncEnabled = !!syncConfig; - return new AppSync.Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(ModelResourceIDs.ModelTableDataSourceID(type), 'Name'), - FieldName: fieldName, - TypeName: mutationTypeName, - RequestMappingTemplate: printBlock('Prepare DynamoDB PutItem Request')( - compoundExpression([ - qref(`$context.args.input.put("__typename", "${type}")`), - this.addDefaultConditionExpression('create'), - iff( - ref('context.args.condition'), - compoundExpression([ - set(ref('condition.expressionValues'), obj({})), - set( - ref('conditionFilterExpressions'), - raw('$util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition))'), - ), - // tslint:disable-next-line - qref(`$condition.put("expression", "($condition.expression) AND $conditionFilterExpressions.expression")`), - qref(`$condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)`), - qref(`$condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)`), - ]), - ), - iff( - and([ref('condition.expressionValues'), raw('$condition.expressionValues.size() == 0')]), - set( - ref('condition'), - obj({ - expression: ref('condition.expression'), - expressionNames: ref('condition.expressionNames'), - }), - ), - ), - DynamoDBMappingTemplate.putItem({ - key: ifElse( - ref(ResourceConstants.SNIPPETS.ModelObjectKey), - raw(`$util.toJson(\$${ResourceConstants.SNIPPETS.ModelObjectKey})`), - obj({ - id: raw(`$util.dynamodb.toDynamoDBJson($ctx.args.input.id)`), - }), - true, - ), - attributeValues: ref('util.dynamodb.toMapValuesJson($context.args.input)'), - condition: ref('util.toJson($condition)'), - }), - ]), - ), - ResponseMappingTemplate: print(DynamoDBMappingTemplate.dynamoDBResponse(isSyncEnabled)), - ...(syncConfig && { SyncConfig: SyncUtils.syncResolverConfig(syncConfig) }), - }); - } - - public initalizeDefaultInputForCreateMutation(input: InputObjectTypeDefinitionNode, timestamps): string { - const hasDefaultIdField = input.fields?.find( - (field) => field.name.value === 'id' && ['ID', 'String'].includes(getBaseType(field.type)), - ); - return printBlock('Set default values')( - compoundExpression([ - ...(hasDefaultIdField ? [qref(`$context.args.input.put("id", $util.defaultIfNull($ctx.args.input.id, $util.autoId()))`)] : []), - ...(timestamps && (timestamps.createdAtField || timestamps.updatedAtField) - ? [set(ref('createdAt'), ref('util.time.nowISO8601()'))] - : []), - ...(timestamps && timestamps.createdAtField - ? [ - comment(`Automatically set the createdAt timestamp.`), - qref( - `$context.args.input.put("${timestamps.createdAtField}", $util.defaultIfNull($ctx.args.input.${timestamps.createdAtField}, $createdAt))`, - ), - ] - : []), - ...(timestamps && timestamps.updatedAtField - ? [ - comment(`Automatically set the updatedAt timestamp.`), - qref( - `$context.args.input.put("${timestamps.updatedAtField}", $util.defaultIfNull($ctx.args.input.${timestamps.updatedAtField}, $createdAt))`, - ), - ] - : []), - ]), - ); - } - - public makeUpdateResolver({ - type, - nameOverride, - syncConfig, - mutationTypeName = 'Mutation', - timestamps, - optionalNonNullableFields, - }: MutationUpdateResolverInput) { - const fieldName = nameOverride ? nameOverride : graphqlName(`update` + toUpper(type)); - const isSyncEnabled = !!syncConfig; - const optionalNonNullableExpression: Expression[] = optionalNonNullableFields.map(str); - - return new AppSync.Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(ModelResourceIDs.ModelTableDataSourceID(type), 'Name'), - FieldName: fieldName, - TypeName: mutationTypeName, - RequestMappingTemplate: print( - compoundExpression([ - set(ref('optionalNonNullableFields'), list(optionalNonNullableExpression)), - forEach(ref('field'), ref('optionalNonNullableFields'), [ - iff( - and([ref('context.arguments.input.keySet().contains($field)'), ref('util.isNull($context.args.input.get($field))')]), - ref('util.error("An argument you marked as Non-Null is set to Null in the query or the body of your request.")'), - ), - ]), - - ifElse( - raw(`$${ResourceConstants.SNIPPETS.AuthCondition} && $${ResourceConstants.SNIPPETS.AuthCondition}.expression != ""`), - compoundExpression([ - set(ref('condition'), ref(ResourceConstants.SNIPPETS.AuthCondition)), - ifElse( - ref(ResourceConstants.SNIPPETS.ModelObjectKey), - forEach(ref('entry'), ref(`${ResourceConstants.SNIPPETS.ModelObjectKey}.entrySet()`), [ - qref('$condition.put("expression", "$condition.expression AND attribute_exists(#keyCondition$velocityCount)")'), - qref('$condition.expressionNames.put("#keyCondition$velocityCount", "$entry.key")'), - ]), - compoundExpression([ - qref('$condition.put("expression", "$condition.expression AND attribute_exists(#id)")'), - qref('$condition.expressionNames.put("#id", "id")'), - ]), - ), - ]), - this.addDefaultConditionExpression('update'), - ), - ...(timestamps && timestamps.updatedAtField - ? [ - comment(`Automatically set the updatedAt timestamp.`), - qref( - `$context.args.input.put("${timestamps.updatedAtField}", $util.defaultIfNull($ctx.args.input.${timestamps.updatedAtField}, $util.time.nowISO8601()))`, - ), - ] - : []), - qref(`$context.args.input.put("__typename", "${type}")`), - comment('Update condition if type is @versioned'), - iff( - ref(ResourceConstants.SNIPPETS.VersionedCondition), - compoundExpression([ - // tslint:disable-next-line - qref( - `$condition.put("expression", "($condition.expression) AND $${ResourceConstants.SNIPPETS.VersionedCondition}.expression")`, - ), - qref(`$condition.expressionNames.putAll($${ResourceConstants.SNIPPETS.VersionedCondition}.expressionNames)`), - qref(`$condition.expressionValues.putAll($${ResourceConstants.SNIPPETS.VersionedCondition}.expressionValues)`), - ]), - ), - iff( - ref('context.args.condition'), - compoundExpression([ - set( - ref('conditionFilterExpressions'), - raw('$util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition))'), - ), - // tslint:disable-next-line - qref(`$condition.put("expression", "($condition.expression) AND $conditionFilterExpressions.expression")`), - qref(`$condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)`), - qref(`$condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)`), - ]), - ), - iff( - and([ref('condition.expressionValues'), raw('$condition.expressionValues.size() == 0')]), - set( - ref('condition'), - obj({ - expression: ref('condition.expression'), - expressionNames: ref('condition.expressionNames'), - }), - ), - ), - DynamoDBMappingTemplate.updateItem({ - key: ifElse( - ref(ResourceConstants.SNIPPETS.ModelObjectKey), - raw(`$util.toJson(\$${ResourceConstants.SNIPPETS.ModelObjectKey})`), - obj({ - id: obj({ S: ref('util.toJson($context.args.input.id)') }), - }), - true, - ), - condition: ref('util.toJson($condition)'), - objectKeyVariable: ResourceConstants.SNIPPETS.ModelObjectKey, - nameOverrideMap: ResourceConstants.SNIPPETS.DynamoDBNameOverrideMap, - isSyncEnabled, - }), - ]), - ), - ResponseMappingTemplate: print(DynamoDBMappingTemplate.dynamoDBResponse(isSyncEnabled)), - ...(syncConfig && { SyncConfig: SyncUtils.syncResolverConfig(syncConfig) }), - }); - } - - /** - * Create a resolver that creates an item in DynamoDB. - * @param type - */ - public makeGetResolver(type: string, nameOverride?: string, isSyncEnabled: boolean = false, queryTypeName: string = 'Query') { - const fieldName = nameOverride ? nameOverride : graphqlName('get' + toUpper(type)); - return new AppSync.Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(ModelResourceIDs.ModelTableDataSourceID(type), 'Name'), - FieldName: fieldName, - TypeName: queryTypeName, - RequestMappingTemplate: print( - DynamoDBMappingTemplate.getItem({ - key: ifElse( - ref(ResourceConstants.SNIPPETS.ModelObjectKey), - raw(`$util.toJson(\$${ResourceConstants.SNIPPETS.ModelObjectKey})`), - obj({ - id: ref('util.dynamodb.toDynamoDBJson($ctx.args.id)'), - }), - true, - ), - isSyncEnabled, - }), - ), - ResponseMappingTemplate: print(DynamoDBMappingTemplate.dynamoDBResponse(isSyncEnabled)), - }); - } - - /** - * Create a resolver that syncs local storage with cloud storage - * @param type - */ - public makeSyncResolver(type: string, queryTypeName: string = 'Query') { - const fieldName = graphqlName('sync' + toUpper(plural(type))); - return new AppSync.Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(ModelResourceIDs.ModelTableDataSourceID(type), 'Name'), - FieldName: fieldName, - TypeName: queryTypeName, - RequestMappingTemplate: print( - DynamoDBMappingTemplate.syncItem({ - filter: ifElse(ref('context.args.filter'), ref('util.transform.toDynamoDBFilterExpression($ctx.args.filter)'), nul()), - limit: ref(`util.defaultIfNull($ctx.args.limit, ${ResourceConstants.DEFAULT_SYNC_QUERY_PAGE_LIMIT})`), - lastSync: ref('util.toJson($util.defaultIfNull($ctx.args.lastSync, null))'), - nextToken: ref('util.toJson($util.defaultIfNull($ctx.args.nextToken, null))'), - }), - ), - ResponseMappingTemplate: print(DynamoDBMappingTemplate.dynamoDBResponse(true)), - }); - } - - /** - * Create a resolver that queries an item in DynamoDB. - * @param type - */ - public makeQueryResolver(type: string, nameOverride?: string, isSyncEnabled: boolean = false, queryTypeName: string = 'Query') { - const fieldName = nameOverride ? nameOverride : graphqlName(`query${toUpper(type)}`); - return new AppSync.Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(ModelResourceIDs.ModelTableDataSourceID(type), 'Name'), - FieldName: fieldName, - TypeName: queryTypeName, - RequestMappingTemplate: print( - compoundExpression([ - set(ref('limit'), ref(`util.defaultIfNull($context.args.limit, ${ResourceConstants.DEFAULT_PAGE_LIMIT})`)), - DynamoDBMappingTemplate.query({ - query: obj({ - expression: str('#typename = :typename'), - expressionNames: obj({ - '#typename': str('__typename'), - }), - expressionValues: obj({ - ':typename': obj({ - S: str(type), - }), - }), - }), - scanIndexForward: ifElse( - ref('context.args.sortDirection'), - ifElse(equals(ref('context.args.sortDirection'), str('ASC')), bool(true), bool(false)), - bool(true), - ), - filter: ifElse(ref('context.args.filter'), ref('util.transform.toDynamoDBFilterExpression($ctx.args.filter)'), nul()), - limit: ref('limit'), - nextToken: ifElse(ref('context.args.nextToken'), ref('util.toJson($context.args.nextToken)'), nul()), - }), - ]), - ), - ResponseMappingTemplate: print( - DynamoDBMappingTemplate.dynamoDBResponse( - isSyncEnabled, - compoundExpression([iff(raw('!$result'), set(ref('result'), ref('ctx.result'))), raw('$util.toJson($result)')]), - ), - ), - }); - } - - /** - * Create a resolver that lists items in DynamoDB. - * TODO: actually fill out the right filter expression. This is a placeholder only. - * @param type - */ - public makeListResolver( - type: string, - improvePluralization: boolean, - nameOverride?: string, - isSyncEnabled: boolean = false, - queryTypeName: string = 'Query', - ) { - const fieldName = nameOverride ? nameOverride : graphqlName('list' + plurality(toUpper(type), improvePluralization)); - const requestVariable = 'ListRequest'; - return new AppSync.Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(ModelResourceIDs.ModelTableDataSourceID(type), 'Name'), - FieldName: fieldName, - TypeName: queryTypeName, - RequestMappingTemplate: print( - compoundExpression([ - set(ref('limit'), ref(`util.defaultIfNull($context.args.limit, ${ResourceConstants.DEFAULT_PAGE_LIMIT})`)), - set( - ref(requestVariable), - obj({ - version: str(RESOLVER_VERSION_ID), - limit: ref('limit'), - }), - ), - iff(ref('context.args.nextToken'), set(ref(`${requestVariable}.nextToken`), ref('context.args.nextToken'))), - iff( - ref('context.args.filter'), - set(ref(`${requestVariable}.filter`), ref('util.parseJson("$util.transform.toDynamoDBFilterExpression($ctx.args.filter)")')), - ), - ifElse( - raw(`!$util.isNull($${ResourceConstants.SNIPPETS.ModelQueryExpression}) - && !$util.isNullOrEmpty($${ResourceConstants.SNIPPETS.ModelQueryExpression}.expression)`), - compoundExpression([ - qref(`$${requestVariable}.put("operation", "Query")`), - qref(`$${requestVariable}.put("query", $${ResourceConstants.SNIPPETS.ModelQueryExpression})`), - ifElse( - raw(`!$util.isNull($ctx.args.sortDirection) && $ctx.args.sortDirection == "DESC"`), - set(ref(`${requestVariable}.scanIndexForward`), bool(false)), - set(ref(`${requestVariable}.scanIndexForward`), bool(true)), - ), - ]), - qref(`$${requestVariable}.put("operation", "Scan")`), - ), - raw(`$util.toJson($${requestVariable})`), - ]), - ), - ResponseMappingTemplate: print(DynamoDBMappingTemplate.dynamoDBResponse(isSyncEnabled)), - }); - } - - /** - * Create a resolver that deletes an item from DynamoDB. - * @param type The name of the type to delete an item of. - * @param nameOverride A user provided override for the field name. - */ - public makeDeleteResolver({ type, nameOverride, syncConfig, mutationTypeName = 'Mutation' }: MutationResolverInput) { - const fieldName = nameOverride ? nameOverride : graphqlName('delete' + toUpper(type)); - const isSyncEnabled = !!syncConfig; - return new AppSync.Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(ModelResourceIDs.ModelTableDataSourceID(type), 'Name'), - FieldName: fieldName, - TypeName: mutationTypeName, - RequestMappingTemplate: print( - compoundExpression([ - ifElse( - ref(ResourceConstants.SNIPPETS.AuthCondition), - compoundExpression([ - set(ref('condition'), ref(ResourceConstants.SNIPPETS.AuthCondition)), - ifElse( - ref(ResourceConstants.SNIPPETS.ModelObjectKey), - forEach(ref('entry'), ref(`${ResourceConstants.SNIPPETS.ModelObjectKey}.entrySet()`), [ - qref('$condition.put("expression", "$condition.expression AND attribute_exists(#keyCondition$velocityCount)")'), - qref('$condition.expressionNames.put("#keyCondition$velocityCount", "$entry.key")'), - ]), - compoundExpression([ - qref('$condition.put("expression", "$condition.expression AND attribute_exists(#id)")'), - qref('$condition.expressionNames.put("#id", "id")'), - ]), - ), - ]), - this.addDefaultConditionExpression('delete'), - ), - iff( - ref(ResourceConstants.SNIPPETS.VersionedCondition), - compoundExpression([ - // tslint:disable-next-line - qref( - `$condition.put("expression", "($condition.expression) AND $${ResourceConstants.SNIPPETS.VersionedCondition}.expression")`, - ), - qref(`$condition.expressionNames.putAll($${ResourceConstants.SNIPPETS.VersionedCondition}.expressionNames)`), - set(ref('expressionValues'), raw('$util.defaultIfNull($condition.expressionValues, {})')), - qref(`$expressionValues.putAll($${ResourceConstants.SNIPPETS.VersionedCondition}.expressionValues)`), - set(ref('condition.expressionValues'), ref('expressionValues')), - ]), - ), - iff( - ref('context.args.condition'), - compoundExpression([ - set( - ref('conditionFilterExpressions'), - raw('$util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition))'), - ), - // tslint:disable-next-line - qref(`$condition.put("expression", "($condition.expression) AND $conditionFilterExpressions.expression")`), - qref(`$condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)`), - set(ref('conditionExpressionValues'), raw('$util.defaultIfNull($condition.expressionValues, {})')), - qref(`$conditionExpressionValues.putAll($conditionFilterExpressions.expressionValues)`), - set(ref('condition.expressionValues'), ref('conditionExpressionValues')), - qref(`$condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)`), - ]), - ), - iff( - and([ref('condition.expressionValues'), raw('$condition.expressionValues.size() == 0')]), - set( - ref('condition'), - obj({ - expression: ref('condition.expression'), - expressionNames: ref('condition.expressionNames'), - }), - ), - ), - DynamoDBMappingTemplate.deleteItem({ - key: ifElse( - ref(ResourceConstants.SNIPPETS.ModelObjectKey), - raw(`$util.toJson(\$${ResourceConstants.SNIPPETS.ModelObjectKey})`), - obj({ - id: ref('util.dynamodb.toDynamoDBJson($ctx.args.input.id)'), - }), - true, - ), - condition: ref('util.toJson($condition)'), - isSyncEnabled, - }), - ]), - ), - ResponseMappingTemplate: print(DynamoDBMappingTemplate.dynamoDBResponse(isSyncEnabled)), - ...(syncConfig && { SyncConfig: SyncUtils.syncResolverConfig(syncConfig) }), - }); - } - - /** - * Adds the default Condition Expression uses ModelObjectkey if @key is used - * @returns - */ - - private addDefaultConditionExpression = (operation: string): Expression => { - const attributeCheck = operation === 'create' ? 'attribute_not_exists' : 'attribute_exists'; - return ifElse( - ref(ResourceConstants.SNIPPETS.ModelObjectKey), - compoundExpression([ - set( - ref('condition'), - obj({ - expression: str(''), - expressionNames: obj({}), - expressionValues: obj({}), - }), - ), - forEach(ref('entry'), ref(`${ResourceConstants.SNIPPETS.ModelObjectKey}.entrySet()`), [ - ifElse( - raw('$velocityCount == 1'), - qref(`$condition.put("expression", "${attributeCheck}(#keyCondition$velocityCount)")`), - qref('$condition.put(' + `"expression", "$condition.expression AND ${attributeCheck}(#keyCondition$velocityCount)")`), - ), - qref('$condition.expressionNames.put("#keyCondition$velocityCount", "$entry.key")'), - ]), - ]), - set( - ref('condition'), - obj({ - expression: str(`${attributeCheck}(#id)`), - expressionNames: obj({ - '#id': str('id'), - }), - expressionValues: obj({}), - }), - ), - ); - }; -} diff --git a/packages/graphql-dynamodb-transformer/tsconfig.json b/packages/graphql-dynamodb-transformer/tsconfig.json deleted file mode 100644 index f3fc268a32..0000000000 --- a/packages/graphql-dynamodb-transformer/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "strict": false, // TODO enable - "rootDir": "src", - "outDir": "lib" - }, - "references": [ - { "path": "../amplify-graphql-directives" }, - { "path": "../graphql-mapping-template" }, - { "path": "../graphql-transformer-common" }, - { "path": "../graphql-transformer-core" } - ] -} diff --git a/packages/graphql-elasticsearch-transformer/.npmignore b/packages/graphql-elasticsearch-transformer/.npmignore deleted file mode 100644 index 0dece55a48..0000000000 --- a/packages/graphql-elasticsearch-transformer/.npmignore +++ /dev/null @@ -1,6 +0,0 @@ -**/__mocks__/** -**/__tests__/** -src -streaming-lambda -tsconfig.json -tsconfig.tsbuildinfo diff --git a/packages/graphql-elasticsearch-transformer/API.md b/packages/graphql-elasticsearch-transformer/API.md deleted file mode 100644 index 7b2cfb1e8c..0000000000 --- a/packages/graphql-elasticsearch-transformer/API.md +++ /dev/null @@ -1,39 +0,0 @@ -## API Report File for "graphql-elasticsearch-transformer" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { default as default_2 } from 'cloudform-types/types/appSync/dataSource'; -import { default as default_3 } from 'cloudform-types/types/lambda/function'; -import { default as default_4 } from 'cloudform-types/types/lambda/eventSourceMapping'; -import { default as default_5 } from 'cloudform-types/types/iam/role'; -import { default as default_6 } from 'cloudform-types/types/elasticsearch/domain'; -import { default as default_7 } from 'cloudform-types/types/appSync/resolver'; -import { DirectiveNode } from 'graphql'; -import { Expression } from 'graphql-mapping-template'; -import { MappingParameters } from 'graphql-transformer-core'; -import { NumberParameter } from 'cloudform-types'; -import { ObjectTypeDefinitionNode } from 'graphql'; -import Output from 'cloudform-types/types/output'; -import { StringParameter } from 'cloudform-types'; -import Template from 'cloudform-types/types/template'; -import { Transformer as Transformer_2 } from 'graphql-transformer-core'; -import { TransformerContext } from 'graphql-transformer-core'; - -// @public (undocumented) -export class SearchableModelTransformer extends Transformer_2 { - constructor(); - // (undocumented) - before: (ctx: TransformerContext) => void; - // (undocumented) - object: (def: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => void; - // Warning: (ae-forgotten-export) The symbol "ResourceFactory" needs to be exported by the entry point index.d.ts - // - // (undocumented) - resources: ResourceFactory; -} - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/graphql-elasticsearch-transformer/CHANGELOG.md b/packages/graphql-elasticsearch-transformer/CHANGELOG.md deleted file mode 100644 index 52c76c73ce..0000000000 --- a/packages/graphql-elasticsearch-transformer/CHANGELOG.md +++ /dev/null @@ -1,1101 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [5.2.81](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.80...graphql-elasticsearch-transformer@5.2.81) (2024-07-15) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.80](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.79...graphql-elasticsearch-transformer@5.2.80) (2024-07-02) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.79](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.78...graphql-elasticsearch-transformer@5.2.79) (2024-06-25) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.78](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.77...graphql-elasticsearch-transformer@5.2.78) (2024-04-26) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.77](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.76...graphql-elasticsearch-transformer@5.2.77) (2024-04-11) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.76](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.75...graphql-elasticsearch-transformer@5.2.76) (2024-03-28) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.75](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.74...graphql-elasticsearch-transformer@5.2.75) (2024-02-28) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.74](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.73...graphql-elasticsearch-transformer@5.2.74) (2024-02-05) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.73](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.72...graphql-elasticsearch-transformer@5.2.73) (2024-01-22) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.72](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.71...graphql-elasticsearch-transformer@5.2.72) (2023-12-18) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.71](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.70...graphql-elasticsearch-transformer@5.2.71) (2023-12-06) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.70](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.69...graphql-elasticsearch-transformer@5.2.70) (2023-11-18) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.69](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.68...graphql-elasticsearch-transformer@5.2.69) (2023-11-16) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.68](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.67...graphql-elasticsearch-transformer@5.2.68) (2023-11-15) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.67](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.66...graphql-elasticsearch-transformer@5.2.67) (2023-10-21) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.66](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.65...graphql-elasticsearch-transformer@5.2.66) (2023-08-30) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.65](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.64...graphql-elasticsearch-transformer@5.2.65) (2023-08-28) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.64](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.63...graphql-elasticsearch-transformer@5.2.64) (2023-08-09) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.63](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.62...graphql-elasticsearch-transformer@5.2.63) (2023-07-21) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.62](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.61...graphql-elasticsearch-transformer@5.2.62) (2023-07-17) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.61](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.60...graphql-elasticsearch-transformer@5.2.61) (2023-07-07) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.60](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.59...graphql-elasticsearch-transformer@5.2.60) (2023-07-07) - -### Bug Fixes - -- trigger republish of dependencies that failed in https://app.circleci.com/pipelines/github/aws-amplify/amplify-category-api/7981/workflows/e7366f04-6f0a-4ee4-9cc2-1772089e8005/jobs/163571 ([f2c7151](https://github.com/aws-amplify/amplify-category-api/commit/f2c7151005e4a9fd29d91ac1af1f3e482a06a5cc)) - -## [5.2.59](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.58...graphql-elasticsearch-transformer@5.2.59) (2023-07-07) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.58](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.57...graphql-elasticsearch-transformer@5.2.58) (2023-06-29) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.57](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.56...graphql-elasticsearch-transformer@5.2.57) (2023-06-20) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.56](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.55...graphql-elasticsearch-transformer@5.2.56) (2023-06-05) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.55](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.54...graphql-elasticsearch-transformer@5.2.55) (2023-05-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.54](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.53...graphql-elasticsearch-transformer@5.2.54) (2023-05-17) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.53](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.52...graphql-elasticsearch-transformer@5.2.53) (2023-04-25) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.52](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.51...graphql-elasticsearch-transformer@5.2.52) (2023-03-30) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.51](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.50...graphql-elasticsearch-transformer@5.2.51) (2023-03-15) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.50](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.49...graphql-elasticsearch-transformer@5.2.50) (2023-03-01) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.49](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.48...graphql-elasticsearch-transformer@5.2.49) (2023-02-27) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.48](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.47...graphql-elasticsearch-transformer@5.2.48) (2023-01-26) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.47](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.46...graphql-elasticsearch-transformer@5.2.47) (2023-01-12) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.46](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.45...graphql-elasticsearch-transformer@5.2.46) (2023-01-12) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.45](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.44...graphql-elasticsearch-transformer@5.2.45) (2022-12-03) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.44](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.43...graphql-elasticsearch-transformer@5.2.44) (2022-09-14) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.43](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.42...graphql-elasticsearch-transformer@5.2.43) (2022-08-04) - -### Bug Fixes - -- **graphql:** revert subscriptions server-side filtering ([20cffc0](https://github.com/aws-amplify/amplify-category-api/commit/20cffc0810c23f85127a939c0a3b812f87c2a601)) - -## [5.2.42](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.40...graphql-elasticsearch-transformer@5.2.42) (2022-07-20) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.41](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.40...graphql-elasticsearch-transformer@5.2.41) (2022-07-14) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.40](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.39...graphql-elasticsearch-transformer@5.2.40) (2022-07-01) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.39](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.38...graphql-elasticsearch-transformer@5.2.39) (2022-06-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.38](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.37...graphql-elasticsearch-transformer@5.2.38) (2022-06-13) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.37](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.36...graphql-elasticsearch-transformer@5.2.37) (2022-06-10) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.36](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.35...graphql-elasticsearch-transformer@5.2.36) (2022-06-10) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.35](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.32...graphql-elasticsearch-transformer@5.2.35) (2022-06-07) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.34](https://github.com/aws-amplify/amplify-category-api/compare/graphql-elasticsearch-transformer@5.2.32...graphql-elasticsearch-transformer@5.2.34) (2022-05-31) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.33](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.32...graphql-elasticsearch-transformer@5.2.33) (2022-05-02) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.32](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.31...graphql-elasticsearch-transformer@5.2.32) (2022-04-29) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.31](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.30...graphql-elasticsearch-transformer@5.2.31) (2022-04-27) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.30](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.29...graphql-elasticsearch-transformer@5.2.30) (2022-04-11) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.29](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.28...graphql-elasticsearch-transformer@5.2.29) (2022-04-07) - -### Bug Fixes - -- **graphql:** correct searchable instance types ([#9973](https://github.com/aws-amplify/amplify-cli/issues/9973)) ([dfcfa52](https://github.com/aws-amplify/amplify-cli/commit/dfcfa5237d538088331e8a7c7d51a9932c879429)) - -## [5.2.28](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.27...graphql-elasticsearch-transformer@5.2.28) (2022-03-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.27](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.26...graphql-elasticsearch-transformer@5.2.27) (2022-03-17) - -### Bug Fixes - -- use lib paths instead of src to reference submodule imports across data-cli split ([#9984](https://github.com/aws-amplify/amplify-cli/issues/9984)) ([7130212](https://github.com/aws-amplify/amplify-cli/commit/7130212c8342d8ecb6b35bc2072ec5034780343f)) - -## [5.2.26](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.25...graphql-elasticsearch-transformer@5.2.26) (2022-03-14) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.24...graphql-elasticsearch-transformer@5.2.25) (2022-03-07) - -### Bug Fixes - -- **graphql:** add new open search instance types to the allowed list ([#9834](https://github.com/aws-amplify/amplify-cli/issues/9834)) ([39014c3](https://github.com/aws-amplify/amplify-cli/commit/39014c3a7ea4eb6ab9644a1ef6653fa287917937)) - -## [5.2.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.23...graphql-elasticsearch-transformer@5.2.24) (2022-02-25) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.22...graphql-elasticsearch-transformer@5.2.23) (2022-02-15) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.18...graphql-elasticsearch-transformer@5.2.22) (2022-02-10) - -## 7.6.19 (2022-02-08) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.17...graphql-elasticsearch-transformer@5.2.18) (2022-02-03) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.16...graphql-elasticsearch-transformer@5.2.17) (2022-01-31) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.15...graphql-elasticsearch-transformer@5.2.16) (2022-01-27) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.14...graphql-elasticsearch-transformer@5.2.15) (2022-01-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.13...graphql-elasticsearch-transformer@5.2.14) (2022-01-13) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.11...graphql-elasticsearch-transformer@5.2.13) (2022-01-10) - -## 7.6.7 (2022-01-10) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.10...graphql-elasticsearch-transformer@5.2.11) (2021-12-21) - -### Bug Fixes - -- generate list types will nullable elements ([#9310](https://github.com/aws-amplify/amplify-cli/issues/9310)) ([e972956](https://github.com/aws-amplify/amplify-cli/commit/e9729565fef2ac7df51f7fc7f345da536f385ac1)) - -## [5.2.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.9...graphql-elasticsearch-transformer@5.2.10) (2021-12-17) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.8...graphql-elasticsearch-transformer@5.2.9) (2021-12-03) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.7...graphql-elasticsearch-transformer@5.2.8) (2021-12-02) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.6...graphql-elasticsearch-transformer@5.2.7) (2021-12-01) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.5...graphql-elasticsearch-transformer@5.2.6) (2021-11-26) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.4...graphql-elasticsearch-transformer@5.2.5) (2021-11-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.3...graphql-elasticsearch-transformer@5.2.4) (2021-11-21) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.2...graphql-elasticsearch-transformer@5.2.3) (2021-11-20) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@5.2.1...graphql-elasticsearch-transformer@5.2.2) (2021-11-17) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [5.2.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.13.0...graphql-elasticsearch-transformer@5.2.1) (2021-11-15) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -# [5.0.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.12.5...graphql-elasticsearch-transformer@5.0.0) (2021-11-13) - -### Features - -- generate list types as non-null ([#8166](https://github.com/aws-amplify/amplify-cli/issues/8166)) ([93786c1](https://github.com/aws-amplify/amplify-cli/commit/93786c13ef04c72748ca32a1ef7878c0e6b5b129)) - -# [4.13.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.12.5...graphql-elasticsearch-transformer@4.13.0) (2021-11-11) - -### Features - -- generate list types as non-null ([#8166](https://github.com/aws-amplify/amplify-cli/issues/8166)) ([93786c1](https://github.com/aws-amplify/amplify-cli/commit/93786c13ef04c72748ca32a1ef7878c0e6b5b129)) - -## [4.12.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.12.4...graphql-elasticsearch-transformer@4.12.5) (2021-10-10) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.12.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.12.3...graphql-elasticsearch-transformer@4.12.4) (2021-10-06) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.12.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.12.2...graphql-elasticsearch-transformer@4.12.3) (2021-10-01) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.12.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.12.1...graphql-elasticsearch-transformer@4.12.2) (2021-09-27) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.12.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.12.0...graphql-elasticsearch-transformer@4.12.1) (2021-09-18) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -# [4.12.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.20...graphql-elasticsearch-transformer@4.12.0) (2021-09-14) - -### Features - -- support five new regions in CLI ([#8094](https://github.com/aws-amplify/amplify-cli/issues/8094)) ([98e6c56](https://github.com/aws-amplify/amplify-cli/commit/98e6c56b21cc9a7e1145ab658c3d8611474d5c44)) - -## [4.11.20](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.19...graphql-elasticsearch-transformer@4.11.20) (2021-09-09) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.11.19](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.18...graphql-elasticsearch-transformer@4.11.19) (2021-09-02) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.11.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.17...graphql-elasticsearch-transformer@4.11.18) (2021-08-24) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.11.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.16...graphql-elasticsearch-transformer@4.11.17) (2021-08-06) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.11.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.15...graphql-elasticsearch-transformer@4.11.16) (2021-07-30) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.11.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.14...graphql-elasticsearch-transformer@4.11.15) (2021-07-27) - -### Bug Fixes - -- **graphql-searchable-transformer:** fix for awstimestamp issues with elastic search ([#7534](https://github.com/aws-amplify/amplify-cli/issues/7534)) ([dd955d0](https://github.com/aws-amplify/amplify-cli/commit/dd955d0a0d237885aaa7b6ab918d98853845d0e4)) - -## [4.11.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.13...graphql-elasticsearch-transformer@4.11.14) (2021-07-16) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.11.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.12...graphql-elasticsearch-transformer@4.11.13) (2021-06-30) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.11.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.11...graphql-elasticsearch-transformer@4.11.12) (2021-06-24) - -### Bug Fixes - -- **graphql-transformer-common:** improve generated graphql pluralization ([#7258](https://github.com/aws-amplify/amplify-cli/issues/7258)) ([fc3ad0d](https://github.com/aws-amplify/amplify-cli/commit/fc3ad0dd5a12a7912c59ae12024f593b4cdf7f2d)), closes [#4224](https://github.com/aws-amplify/amplify-cli/issues/4224) - -## [4.11.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.10...graphql-elasticsearch-transformer@4.11.11) (2021-06-15) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.11.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.9...graphql-elasticsearch-transformer@4.11.10) (2021-05-29) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.11.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.8...graphql-elasticsearch-transformer@4.11.9) (2021-05-26) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.11.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.7...graphql-elasticsearch-transformer@4.11.8) (2021-05-18) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** make primary key non null on del ([#6337](https://github.com/aws-amplify/amplify-cli/issues/6337)) ([4a5c679](https://github.com/aws-amplify/amplify-cli/commit/4a5c6795680b6b88efb19b923ee234253ca30c35)), closes [#2564](https://github.com/aws-amplify/amplify-cli/issues/2564) - -## [4.11.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.6...graphql-elasticsearch-transformer@4.11.7) (2021-05-14) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.11.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.4...graphql-elasticsearch-transformer@4.11.6) (2021-05-03) - -## 4.50.1 (2021-05-03) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.11.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.4...graphql-elasticsearch-transformer@4.11.5) (2021-05-03) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.11.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.3...graphql-elasticsearch-transformer@4.11.4) (2021-04-27) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.11.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.2...graphql-elasticsearch-transformer@4.11.3) (2021-04-19) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.11.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.11.1...graphql-elasticsearch-transformer@4.11.2) (2021-04-14) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.11.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.10.8...graphql-elasticsearch-transformer@4.11.1) (2021-04-09) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.10.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.10.7...graphql-elasticsearch-transformer@4.10.8) (2021-03-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.10.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.10.6...graphql-elasticsearch-transformer@4.10.7) (2021-03-11) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.10.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.10.5...graphql-elasticsearch-transformer@4.10.6) (2021-03-05) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.10.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.10.4...graphql-elasticsearch-transformer@4.10.5) (2021-02-26) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.10.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.10.3...graphql-elasticsearch-transformer@4.10.4) (2021-02-24) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.10.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.10.2...graphql-elasticsearch-transformer@4.10.3) (2021-02-17) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.10.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.10.1...graphql-elasticsearch-transformer@4.10.2) (2021-02-11) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.10.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.10.0...graphql-elasticsearch-transformer@4.10.1) (2021-02-10) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -# [4.10.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.9.4...graphql-elasticsearch-transformer@4.10.0) (2021-01-08) - -### Features - -- **graphql-elasticsearch-transformer:** ddb_to_ess script now accepts session token ([#6313](https://github.com/aws-amplify/amplify-cli/issues/6313)) ([9bf8b16](https://github.com/aws-amplify/amplify-cli/commit/9bf8b16ac4f67f7be553b7cb0d020ebe0c46ab8f)) - -## [4.9.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.9.3...graphql-elasticsearch-transformer@4.9.4) (2020-12-16) - -### Bug Fixes - -- [#6108](https://github.com/aws-amplify/amplify-cli/issues/6108) - add proper AWSJSON mapping in generated filter input types ([#6112](https://github.com/aws-amplify/amplify-cli/issues/6112)) ([743e84a](https://github.com/aws-amplify/amplify-cli/commit/743e84a9d968aab4648a12d3a19aa5ea14c4d755)) - -### Reverts - -- Revert "Revert "Revert "fix: #6108 - add proper AWSJSON mapping in generated filter input types (#6112)" (#6158)" (#6160)" (#6183) ([a0ca94e](https://github.com/aws-amplify/amplify-cli/commit/a0ca94e5a1a848404ef3977743f19d26300a636a)), closes [#6108](https://github.com/aws-amplify/amplify-cli/issues/6108) [#6112](https://github.com/aws-amplify/amplify-cli/issues/6112) [#6158](https://github.com/aws-amplify/amplify-cli/issues/6158) [#6160](https://github.com/aws-amplify/amplify-cli/issues/6160) [#6183](https://github.com/aws-amplify/amplify-cli/issues/6183) -- Revert "Revert "fix: #6108 - add proper AWSJSON mapping in generated filter input types (#6112)" (#6158)" (#6160) ([f425924](https://github.com/aws-amplify/amplify-cli/commit/f42592420dcb49640c680c5001b3026ae0129090)), closes [#6108](https://github.com/aws-amplify/amplify-cli/issues/6108) [#6112](https://github.com/aws-amplify/amplify-cli/issues/6112) [#6158](https://github.com/aws-amplify/amplify-cli/issues/6158) [#6160](https://github.com/aws-amplify/amplify-cli/issues/6160) -- Revert "fix: #6108 - add proper AWSJSON mapping in generated filter input types (#6112)" (#6158) ([9e57e4d](https://github.com/aws-amplify/amplify-cli/commit/9e57e4d8c887be8ee4119c87383c7379cec40c37)), closes [#6108](https://github.com/aws-amplify/amplify-cli/issues/6108) [#6112](https://github.com/aws-amplify/amplify-cli/issues/6112) [#6158](https://github.com/aws-amplify/amplify-cli/issues/6158) - -## [4.9.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.9.2...graphql-elasticsearch-transformer@4.9.3) (2020-12-07) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.9.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.9.1...graphql-elasticsearch-transformer@4.9.2) (2020-11-30) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.9.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.8.1...graphql-elasticsearch-transformer@4.9.1) (2020-11-22) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -# [4.9.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.6.6...graphql-elasticsearch-transformer@4.9.0) (2020-11-22) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** allow range on searches ([#3129](https://github.com/aws-amplify/amplify-cli/issues/3129)) ([f81ea32](https://github.com/aws-amplify/amplify-cli/commit/f81ea329f47194fbc19eb966cacee9877e04a389)), closes [#2775](https://github.com/aws-amplify/amplify-cli/issues/2775) -- **graphql-elasticsearch-transformer:** es logging fix ([#2983](https://github.com/aws-amplify/amplify-cli/issues/2983)) ([6a6be16](https://github.com/aws-amplify/amplify-cli/commit/6a6be16493aaceeef57e9dfdde7faddfac061a26)) -- **graphql-elasticsearch-transformer:** fix duplicate records in es lambda ([#3712](https://github.com/aws-amplify/amplify-cli/issues/3712)) ([dd9f7e0](https://github.com/aws-amplify/amplify-cli/commit/dd9f7e0031a0dc68a9027de02f60bbe69d315c3d)), closes [#3602](https://github.com/aws-amplify/amplify-cli/issues/3602) [#3705](https://github.com/aws-amplify/amplify-cli/issues/3705) -- **graphql-elasticsearch-transformer:** fix script to use keyschema ([#5036](https://github.com/aws-amplify/amplify-cli/issues/5036)) ([68a0d1e](https://github.com/aws-amplify/amplify-cli/commit/68a0d1e084d6d51c2ec0140d42a9eb008148c9d9)), closes [#3786](https://github.com/aws-amplify/amplify-cli/issues/3786) -- **graphql-elasticsearch-transformer:** fixed KeyError for unset DEBUG ([#2963](https://github.com/aws-amplify/amplify-cli/issues/2963)) ([ad3e23e](https://github.com/aws-amplify/amplify-cli/commit/ad3e23e5c1a88c1385529f7a6685305cb59c840d)) -- **graphql-elasticsearch-transformer:** support del in sync enabled API ([#4281](https://github.com/aws-amplify/amplify-cli/issues/4281)) ([bae946d](https://github.com/aws-amplify/amplify-cli/commit/bae946dabe4a2e37cfdb87c6fbd88af824f21b69)), closes [#4228](https://github.com/aws-amplify/amplify-cli/issues/4228) [#4228](https://github.com/aws-amplify/amplify-cli/issues/4228) -- **graphql-elasticsearch-transformer:** to support non string key in es ([#5180](https://github.com/aws-amplify/amplify-cli/issues/5180)) ([b119344](https://github.com/aws-amplify/amplify-cli/commit/b1193446ff3503311a043dfc23dd6c30fcaa94ed)), closes [#5140](https://github.com/aws-amplify/amplify-cli/issues/5140) -- use ES external versioning when using DataStore ([#4127](https://github.com/aws-amplify/amplify-cli/issues/4127)) ([cef709b](https://github.com/aws-amplify/amplify-cli/commit/cef709ba2087affe860dd6fb141ccda1e5d58fd1)) -- **graphql-elasticsearch-transformer:** use ddb keys as main id in es ([#3391](https://github.com/aws-amplify/amplify-cli/issues/3391)) ([9aae9a6](https://github.com/aws-amplify/amplify-cli/commit/9aae9a6681c5ff744d908b5292a5b00faa14de4d)), closes [#3359](https://github.com/aws-amplify/amplify-cli/issues/3359) -- add layer based on region ([#2399](https://github.com/aws-amplify/amplify-cli/issues/2399)) ([c6490c5](https://github.com/aws-amplify/amplify-cli/commit/c6490c537299e74c569a80fc06d1999cc92ae774)), closes [#2386](https://github.com/aws-amplify/amplify-cli/issues/2386) -- build break, chore: typescript, lerna update ([#2640](https://github.com/aws-amplify/amplify-cli/issues/2640)) ([29fae36](https://github.com/aws-amplify/amplify-cli/commit/29fae366f4cab054feefa58c7dc733002d19570c)) -- export Typescript definitions and fix resulting type errors ([#2452](https://github.com/aws-amplify/amplify-cli/issues/2452)) ([7de3845](https://github.com/aws-amplify/amplify-cli/commit/7de384594d3b9cbf22cdaa85107fc8df26c141ec)), closes [#2451](https://github.com/aws-amplify/amplify-cli/issues/2451) -- sanitize input in transformer resolver([#3316](https://github.com/aws-amplify/amplify-cli/issues/3316)) ([a3bc0a5](https://github.com/aws-amplify/amplify-cli/commit/a3bc0a5e5d3faa7946d16d0f6595ce8c2f3c11dc)) -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) -- **graphql-elasticsearch-transformer:** changed nonKeyword types ([#2090](https://github.com/aws-amplify/amplify-cli/issues/2090)) ([c2f71eb](https://github.com/aws-amplify/amplify-cli/commit/c2f71eb8614a3d7b3f619da40f681e1397103f60)), closes [#2080](https://github.com/aws-amplify/amplify-cli/issues/2080) [#800](https://github.com/aws-amplify/amplify-cli/issues/800) [#2080](https://github.com/aws-amplify/amplify-cli/issues/2080) [re#800](https://github.com/re/issues/800) -- **graphql-elasticsearch-transformer:** fixed es req template ([311f57d](https://github.com/aws-amplify/amplify-cli/commit/311f57d9938aa78c83c7c695ddd39457b89c8afc)) - -### Features - -- **amplify-category-api:** change default graphql query limit to 100 ([#4124](https://github.com/aws-amplify/amplify-cli/issues/4124)) ([1a68c4d](https://github.com/aws-amplify/amplify-cli/commit/1a68c4d589e2101357dec4e980719fc547964e23)) -- **graphql-dynamodb-transformer:** expose createdAt and updatedAt on model ([#4149](https://github.com/aws-amplify/amplify-cli/issues/4149)) ([8e0662e](https://github.com/aws-amplify/amplify-cli/commit/8e0662eac8c88da9393f32c33457a597acf591ed)), closes [#401](https://github.com/aws-amplify/amplify-cli/issues/401) -- **graphql-elasticsearch-transformer:** add 'from' query parameter ([#5098](https://github.com/aws-amplify/amplify-cli/issues/5098)) ([d52a804](https://github.com/aws-amplify/amplify-cli/commit/d52a804c25df63cd1cee1a72bb99286ecfe54ed5)) -- **graphql-elasticsearch-transformer:** add total in es response ([#2602](https://github.com/aws-amplify/amplify-cli/issues/2602)) ([dbdb000](https://github.com/aws-amplify/amplify-cli/commit/dbdb0002b8e7cd33e37880d3166bc99c5faf1234)), closes [#2600](https://github.com/aws-amplify/amplify-cli/issues/2600) -- **graphql-elasticsearch-transformer:** support sets in es fn ([#2986](https://github.com/aws-amplify/amplify-cli/issues/2986)) ([16419f4](https://github.com/aws-amplify/amplify-cli/commit/16419f4d9e1733ed0ada064f9ced604083ee4703)), closes [#2860](https://github.com/aws-amplify/amplify-cli/issues/2860) -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c1927da10f8c54f38a523021187361131c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe8925a4e73358b03ba927267a2df328b78)) - -## [4.8.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.8.1...graphql-elasticsearch-transformer@4.8.4) (2020-11-20) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.8.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.8.1...graphql-elasticsearch-transformer@4.8.3) (2020-11-20) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.8.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.8.1...graphql-elasticsearch-transformer@4.8.2) (2020-11-19) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.8.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.8.0...graphql-elasticsearch-transformer@4.8.1) (2020-11-08) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -# [4.8.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.18...graphql-elasticsearch-transformer@4.8.0) (2020-10-30) - -### Features - -- **graphql-elasticsearch-transformer:** add 'from' query parameter ([#5098](https://github.com/aws-amplify/amplify-cli/issues/5098)) ([d52a804](https://github.com/aws-amplify/amplify-cli/commit/d52a804c25df63cd1cee1a72bb99286ecfe54ed5)) - -## [4.7.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.17...graphql-elasticsearch-transformer@4.7.18) (2020-10-22) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.7.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.16...graphql-elasticsearch-transformer@4.7.17) (2020-10-17) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.7.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.15...graphql-elasticsearch-transformer@4.7.16) (2020-10-01) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.7.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.14...graphql-elasticsearch-transformer@4.7.15) (2020-09-16) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.7.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.13...graphql-elasticsearch-transformer@4.7.14) (2020-09-02) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.7.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.12...graphql-elasticsearch-transformer@4.7.13) (2020-08-31) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** to support non string key in es ([#5180](https://github.com/aws-amplify/amplify-cli/issues/5180)) ([b119344](https://github.com/aws-amplify/amplify-cli/commit/b1193446ff3503311a043dfc23dd6c30fcaa94ed)), closes [#5140](https://github.com/aws-amplify/amplify-cli/issues/5140) - -## [4.7.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.11...graphql-elasticsearch-transformer@4.7.12) (2020-08-14) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.7.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.10...graphql-elasticsearch-transformer@4.7.11) (2020-08-11) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** fix script to use keyschema ([#5036](https://github.com/aws-amplify/amplify-cli/issues/5036)) ([68a0d1e](https://github.com/aws-amplify/amplify-cli/commit/68a0d1e084d6d51c2ec0140d42a9eb008148c9d9)), closes [#3786](https://github.com/aws-amplify/amplify-cli/issues/3786) - -## [4.7.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.8...graphql-elasticsearch-transformer@4.7.10) (2020-07-29) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.7.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.8...graphql-elasticsearch-transformer@4.7.9) (2020-07-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.7.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.7...graphql-elasticsearch-transformer@4.7.8) (2020-07-18) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.7.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.6...graphql-elasticsearch-transformer@4.7.7) (2020-07-15) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.7.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.5...graphql-elasticsearch-transformer@4.7.6) (2020-06-25) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.7.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.4...graphql-elasticsearch-transformer@4.7.5) (2020-06-18) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.7.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.3...graphql-elasticsearch-transformer@4.7.4) (2020-06-11) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.7.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.2...graphql-elasticsearch-transformer@4.7.3) (2020-06-10) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.7.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.1...graphql-elasticsearch-transformer@4.7.2) (2020-06-02) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.7.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.7.0...graphql-elasticsearch-transformer@4.7.1) (2020-05-26) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** support del in sync enabled API ([#4281](https://github.com/aws-amplify/amplify-cli/issues/4281)) ([f57f824](https://github.com/aws-amplify/amplify-cli/commit/f57f8242f18c79d48b751e29952e3cdd21409f98)), closes [#4228](https://github.com/aws-amplify/amplify-cli/issues/4228) [#4228](https://github.com/aws-amplify/amplify-cli/issues/4228) - -# [4.7.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.6.0...graphql-elasticsearch-transformer@4.7.0) (2020-05-15) - -### Features - -- **graphql-dynamodb-transformer:** expose createdAt and updatedAt on model ([#4149](https://github.com/aws-amplify/amplify-cli/issues/4149)) ([8e0662e](https://github.com/aws-amplify/amplify-cli/commit/8e0662eac8c88da9393f32c33457a597acf591ed)), closes [#401](https://github.com/aws-amplify/amplify-cli/issues/401) - -# [4.6.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.5.3...graphql-elasticsearch-transformer@4.6.0) (2020-05-08) - -### Bug Fixes - -- use ES external versioning when using DataStore ([#4127](https://github.com/aws-amplify/amplify-cli/issues/4127)) ([cef709b](https://github.com/aws-amplify/amplify-cli/commit/cef709ba2087affe860dd6fb141ccda1e5d58fd1)) - -### Features - -- **amplify-category-api:** change default graphql query limit to 100 ([#4124](https://github.com/aws-amplify/amplify-cli/issues/4124)) ([1a68c4d](https://github.com/aws-amplify/amplify-cli/commit/1a68c4d589e2101357dec4e980719fc547964e23)) - -## [4.5.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.5.2...graphql-elasticsearch-transformer@4.5.3) (2020-04-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.5.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.5.1...graphql-elasticsearch-transformer@4.5.2) (2020-03-22) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** fix duplicate records in es lambda ([#3712](https://github.com/aws-amplify/amplify-cli/issues/3712)) ([dd9f7e0](https://github.com/aws-amplify/amplify-cli/commit/dd9f7e0031a0dc68a9027de02f60bbe69d315c3d)), closes [#3602](https://github.com/aws-amplify/amplify-cli/issues/3602) [#3705](https://github.com/aws-amplify/amplify-cli/issues/3705) - -## [4.5.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.3.4...graphql-elasticsearch-transformer@4.5.1) (2020-03-07) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** use ddb keys as main id in es ([#3391](https://github.com/aws-amplify/amplify-cli/issues/3391)) ([9aae9a6](https://github.com/aws-amplify/amplify-cli/commit/9aae9a6681c5ff744d908b5292a5b00faa14de4d)), closes [#3359](https://github.com/aws-amplify/amplify-cli/issues/3359) - -## [4.4.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.3.6-beta.0...graphql-elasticsearch-transformer@4.4.1) (2020-03-05) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.3.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.3.3...graphql-elasticsearch-transformer@4.3.4) (2020-02-18) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.3.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.3.2...graphql-elasticsearch-transformer@4.3.3) (2020-02-13) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.3.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.3.1...graphql-elasticsearch-transformer@4.3.2) (2020-02-07) - -### Bug Fixes - -- sanitize input in transformer resolver([#3316](https://github.com/aws-amplify/amplify-cli/issues/3316)) ([a3bc0a5](https://github.com/aws-amplify/amplify-cli/commit/a3bc0a5e5d3faa7946d16d0f6595ce8c2f3c11dc)) - -## [4.3.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@4.3.0...graphql-elasticsearch-transformer@4.3.1) (2020-01-24) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -# [4.3.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.30.0...graphql-elasticsearch-transformer@4.3.0) (2020-01-23) - -### Bug Fixes - -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) -- **graphql-elasticsearch-transformer:** allow range on searches ([#3129](https://github.com/aws-amplify/amplify-cli/issues/3129)) ([f81ea32](https://github.com/aws-amplify/amplify-cli/commit/f81ea329f47194fbc19eb966cacee9877e04a389)), closes [#2775](https://github.com/aws-amplify/amplify-cli/issues/2775) -- **graphql-elasticsearch-transformer:** es logging fix ([#2983](https://github.com/aws-amplify/amplify-cli/issues/2983)) ([6a6be16](https://github.com/aws-amplify/amplify-cli/commit/6a6be16493aaceeef57e9dfdde7faddfac061a26)) -- **graphql-elasticsearch-transformer:** fixed KeyError for unset DEBUG ([#2963](https://github.com/aws-amplify/amplify-cli/issues/2963)) ([ad3e23e](https://github.com/aws-amplify/amplify-cli/commit/ad3e23e5c1a88c1385529f7a6685305cb59c840d)) - -### Features - -- **graphql-elasticsearch-transformer:** support sets in es fn ([#2986](https://github.com/aws-amplify/amplify-cli/issues/2986)) ([16419f4](https://github.com/aws-amplify/amplify-cli/commit/16419f4d9e1733ed0ada064f9ced604083ee4703)), closes [#2860](https://github.com/aws-amplify/amplify-cli/issues/2860) - -# [4.2.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.30.0...graphql-elasticsearch-transformer@4.2.0) (2020-01-09) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** es logging fix ([#2983](https://github.com/aws-amplify/amplify-cli/issues/2983)) ([6a6be16](https://github.com/aws-amplify/amplify-cli/commit/6a6be16493aaceeef57e9dfdde7faddfac061a26)) -- **graphql-elasticsearch-transformer:** fixed KeyError for unset DEBUG ([#2963](https://github.com/aws-amplify/amplify-cli/issues/2963)) ([ad3e23e](https://github.com/aws-amplify/amplify-cli/commit/ad3e23e5c1a88c1385529f7a6685305cb59c840d)) -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) - -### Features - -- **graphql-elasticsearch-transformer:** support sets in es fn ([#2986](https://github.com/aws-amplify/amplify-cli/issues/2986)) ([16419f4](https://github.com/aws-amplify/amplify-cli/commit/16419f4d9e1733ed0ada064f9ced604083ee4703)), closes [#2860](https://github.com/aws-amplify/amplify-cli/issues/2860) - -## [4.1.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.30.0...graphql-elasticsearch-transformer@4.1.6) (2019-12-31) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** es logging fix ([#2983](https://github.com/aws-amplify/amplify-cli/issues/2983)) ([6a6be16](https://github.com/aws-amplify/amplify-cli/commit/6a6be16493aaceeef57e9dfdde7faddfac061a26)) -- **graphql-elasticsearch-transformer:** fixed KeyError for unset DEBUG ([#2963](https://github.com/aws-amplify/amplify-cli/issues/2963)) ([ad3e23e](https://github.com/aws-amplify/amplify-cli/commit/ad3e23e5c1a88c1385529f7a6685305cb59c840d)) - -## [4.1.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.30.0...graphql-elasticsearch-transformer@4.1.5) (2019-12-28) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** es logging fix ([#2983](https://github.com/aws-amplify/amplify-cli/issues/2983)) ([6a6be16](https://github.com/aws-amplify/amplify-cli/commit/6a6be16493aaceeef57e9dfdde7faddfac061a26)) -- **graphql-elasticsearch-transformer:** fixed KeyError for unset DEBUG ([#2963](https://github.com/aws-amplify/amplify-cli/issues/2963)) ([ad3e23e](https://github.com/aws-amplify/amplify-cli/commit/ad3e23e5c1a88c1385529f7a6685305cb59c840d)) - -## [4.1.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.30.0...graphql-elasticsearch-transformer@4.1.4) (2019-12-26) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** es logging fix ([#2983](https://github.com/aws-amplify/amplify-cli/issues/2983)) ([6a6be16](https://github.com/aws-amplify/amplify-cli/commit/6a6be16493aaceeef57e9dfdde7faddfac061a26)) -- **graphql-elasticsearch-transformer:** fixed KeyError for unset DEBUG ([#2963](https://github.com/aws-amplify/amplify-cli/issues/2963)) ([ad3e23e](https://github.com/aws-amplify/amplify-cli/commit/ad3e23e5c1a88c1385529f7a6685305cb59c840d)) - -## [4.1.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.30.0...graphql-elasticsearch-transformer@4.1.3) (2019-12-25) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** es logging fix ([#2983](https://github.com/aws-amplify/amplify-cli/issues/2983)) ([6a6be16](https://github.com/aws-amplify/amplify-cli/commit/6a6be16493aaceeef57e9dfdde7faddfac061a26)) -- **graphql-elasticsearch-transformer:** fixed KeyError for unset DEBUG ([#2963](https://github.com/aws-amplify/amplify-cli/issues/2963)) ([ad3e23e](https://github.com/aws-amplify/amplify-cli/commit/ad3e23e5c1a88c1385529f7a6685305cb59c840d)) - -## [4.1.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.30.0...graphql-elasticsearch-transformer@4.1.2) (2019-12-20) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** es logging fix ([#2983](https://github.com/aws-amplify/amplify-cli/issues/2983)) ([6a6be16](https://github.com/aws-amplify/amplify-cli/commit/6a6be16493aaceeef57e9dfdde7faddfac061a26)) -- **graphql-elasticsearch-transformer:** fixed KeyError for unset DEBUG ([#2963](https://github.com/aws-amplify/amplify-cli/issues/2963)) ([ad3e23e](https://github.com/aws-amplify/amplify-cli/commit/ad3e23e5c1a88c1385529f7a6685305cb59c840d)) - -## [4.1.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.30.0...graphql-elasticsearch-transformer@4.1.1) (2019-12-10) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.0.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.30.0...graphql-elasticsearch-transformer@4.0.5) (2019-12-03) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.0.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.30.0...graphql-elasticsearch-transformer@4.0.4) (2019-12-01) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.0.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.30.0...graphql-elasticsearch-transformer@4.0.3) (2019-11-27) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [4.0.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.30.0...graphql-elasticsearch-transformer@4.0.1) (2019-11-27) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -# [3.12.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.6.6...graphql-elasticsearch-transformer@3.12.0) (2019-08-30) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** changed nonKeyword types ([#2090](https://github.com/aws-amplify/amplify-cli/issues/2090)) ([c2f71eb](https://github.com/aws-amplify/amplify-cli/commit/c2f71eb)), closes [#2080](https://github.com/aws-amplify/amplify-cli/issues/2080) [#800](https://github.com/aws-amplify/amplify-cli/issues/800) [#2080](https://github.com/aws-amplify/amplify-cli/issues/2080) [re#800](https://github.com/re/issues/800) -- **graphql-elasticsearch-transformer:** fixed es req template ([311f57d](https://github.com/aws-amplify/amplify-cli/commit/311f57d)) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [3.11.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.6.6...graphql-elasticsearch-transformer@3.11.0) (2019-08-28) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** fixed es req template ([311f57d](https://github.com/aws-amplify/amplify-cli/commit/311f57d)) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [3.10.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.6.6...graphql-elasticsearch-transformer@3.10.0) (2019-08-13) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** fixed es req template ([311f57d](https://github.com/aws-amplify/amplify-cli/commit/311f57d)) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [3.9.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.6.6...graphql-elasticsearch-transformer@3.9.0) (2019-08-07) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [3.8.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.6.6...graphql-elasticsearch-transformer@3.8.0) (2019-08-02) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [3.7.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.6.6...graphql-elasticsearch-transformer@3.7.0) (2019-07-31) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -## [3.6.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.6.5...graphql-elasticsearch-transformer@3.6.6) (2019-07-24) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [3.6.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.6.3...graphql-elasticsearch-transformer@3.6.5) (2019-06-30) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [3.6.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.6.2...graphql-elasticsearch-transformer@3.6.3) (2019-06-26) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [3.6.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.6.1...graphql-elasticsearch-transformer@3.6.2) (2019-06-12) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [3.6.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.6.0...graphql-elasticsearch-transformer@3.6.1) (2019-05-29) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -# [3.6.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.5.5...graphql-elasticsearch-transformer@3.6.0) (2019-05-21) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** use Fn::GetAtt for StreamArn ([#1494](https://github.com/aws-amplify/amplify-cli/issues/1494)) ([8c80462](https://github.com/aws-amplify/amplify-cli/commit/8c80462)), closes [/github.com/aws-amplify/amplify-cli/commit/df1712b00427792bcce34adf7027698afd8e6841#diff-22e2a5351fb3f897025bc1e45811acb5R168](https://github.com//github.com/aws-amplify/amplify-cli/commit/df1712b00427792bcce34adf7027698afd8e6841/issues/diff-22e2a5351fb3f897025bc1e45811acb5R168) - -### Features - -- **graphql-dynamodb-transformer:** always output stream arn ([df1712b](https://github.com/aws-amplify/amplify-cli/commit/df1712b)), closes [#980](https://github.com/aws-amplify/amplify-cli/issues/980) - -## [3.5.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.5.4...graphql-elasticsearch-transformer@3.5.5) (2019-05-17) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [3.5.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.5.3...graphql-elasticsearch-transformer@3.5.4) (2019-05-07) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [3.5.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.5.2...graphql-elasticsearch-transformer@3.5.3) (2019-04-30) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [3.5.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.5.1...graphql-elasticsearch-transformer@3.5.2) (2019-04-16) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [3.5.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.4.0...graphql-elasticsearch-transformer@3.5.1) (2019-04-09) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -# [3.4.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.0.9...graphql-elasticsearch-transformer@3.4.0) (2019-04-03) - -### Features - -- **graphql-elasticsearch-transformer:** export domain arn and endpoint ([97b8cad](https://github.com/aws-amplify/amplify-cli/commit/97b8cad)), closes [#1047](https://github.com/aws-amplify/amplify-cli/issues/1047) -- **graphql-elasticsearch-transformer:** output endpoint with https ([a5e7b73](https://github.com/aws-amplify/amplify-cli/commit/a5e7b73)), closes [#1047](https://github.com/aws-amplify/amplify-cli/issues/1047) - -## [3.0.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.0.8...graphql-elasticsearch-transformer@3.0.9) (2019-03-22) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [3.0.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.0.7...graphql-elasticsearch-transformer@3.0.8) (2019-03-05) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [3.0.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.0.6...graphql-elasticsearch-transformer@3.0.7) (2019-02-20) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [3.0.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.0.5...graphql-elasticsearch-transformer@3.0.6) (2019-02-12) - -### Bug Fixes - -- cloudform/type versions ([ec6f99f](https://github.com/aws-amplify/amplify-cli/commit/ec6f99f)) - -## [3.0.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.0.3-beta.0...graphql-elasticsearch-transformer@3.0.5) (2019-02-11) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [3.0.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.0.3-beta.0...graphql-elasticsearch-transformer@3.0.3) (2019-02-11) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - -## [3.0.3-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@3.0.2...graphql-elasticsearch-transformer@3.0.3-beta.0) (2019-02-11) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -# [2.0.0-multienv.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.34-multienv.2...graphql-elasticsearch-transformer@2.0.0-multienv.2) (2018-12-31) - -### Bug Fixes - -- update grahql transformer package versions for multienv ([8b4b2bd](https://github.com/aws-amplify/amplify-cli/commit/8b4b2bd)) - - - -## [1.0.34-multienv.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.34-multienv.1...graphql-elasticsearch-transformer@1.0.34-multienv.2) (2018-12-27) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## [1.0.34-multienv.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.34-multienv.0...graphql-elasticsearch-transformer@1.0.34-multienv.1) (2018-12-19) - -### Bug Fixes - -- **amplify-category-api:** Updating dependsOn for certain resources ([#597](https://github.com/aws-amplify/amplify-cli/issues/597)) ([7a8f5f7](https://github.com/aws-amplify/amplify-cli/commit/7a8f5f7)) - - - -## [1.0.34-multienv.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.33...graphql-elasticsearch-transformer@1.0.34-multienv.0) (2018-11-16) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## [1.0.33](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.33-beta.0...graphql-elasticsearch-transformer@1.0.33) (2018-11-09) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## [1.0.33-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.12...graphql-elasticsearch-transformer@1.0.33-beta.0) (2018-11-09) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** Fix zip command not found on Windows. ([c93a673](https://github.com/aws-amplify/amplify-cli/commit/c93a673)) - - - -## [1.0.32](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.32-beta.0...graphql-elasticsearch-transformer@1.0.32) (2018-11-05) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## [1.0.32-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.12...graphql-elasticsearch-transformer@1.0.32-beta.0) (2018-11-05) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** Fix zip command not found on Windows. ([c93a673](https://github.com/aws-amplify/amplify-cli/commit/c93a673)) - - - -## [1.0.31](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.12...graphql-elasticsearch-transformer@1.0.31) (2018-11-02) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** Fix zip command not found on Windows. ([c93a673](https://github.com/aws-amplify/amplify-cli/commit/c93a673)) - - - -## [1.0.30](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.30-beta.0...graphql-elasticsearch-transformer@1.0.30) (2018-11-02) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## [1.0.30-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.12...graphql-elasticsearch-transformer@1.0.30-beta.0) (2018-11-02) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** Fix zip command not found on Windows. ([c93a673](https://github.com/aws-amplify/amplify-cli/commit/c93a673)) - - - -## [1.0.29](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.29-beta.0...graphql-elasticsearch-transformer@1.0.29) (2018-10-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## [1.0.29-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.12...graphql-elasticsearch-transformer@1.0.29-beta.0) (2018-10-23) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** Fix zip command not found on Windows. ([c93a673](https://github.com/aws-amplify/amplify-cli/commit/c93a673)) - - - -## [1.0.28](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.28-beta.0...graphql-elasticsearch-transformer@1.0.28) (2018-10-18) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## [1.0.28-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.12...graphql-elasticsearch-transformer@1.0.28-beta.0) (2018-10-12) - -### Bug Fixes - -- **graphql-elasticsearch-transformer:** Fix zip command not found on Windows. ([c93a673](https://github.com/aws-amplify/amplify-cli/commit/c93a673)) - - - -## [1.0.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.11...graphql-elasticsearch-transformer@1.0.12) (2018-08-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## [1.0.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.10...graphql-elasticsearch-transformer@1.0.11) (2018-08-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## [1.0.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.9...graphql-elasticsearch-transformer@1.0.10) (2018-08-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## [1.0.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.8...graphql-elasticsearch-transformer@1.0.9) (2018-08-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## [1.0.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.7...graphql-elasticsearch-transformer@1.0.8) (2018-08-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## [1.0.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.6...graphql-elasticsearch-transformer@1.0.7) (2018-08-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## [1.0.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.5...graphql-elasticsearch-transformer@1.0.6) (2018-08-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## [1.0.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-elasticsearch-transformer@1.0.4...graphql-elasticsearch-transformer@1.0.5) (2018-08-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## 1.0.4 (2018-08-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## 1.0.3 (2018-08-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## 1.0.2 (2018-08-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer - - - -## 1.0.1 (2018-08-23) - -**Note:** Version bump only for package graphql-elasticsearch-transformer diff --git a/packages/graphql-elasticsearch-transformer/package.json b/packages/graphql-elasticsearch-transformer/package.json deleted file mode 100644 index e6163442c3..0000000000 --- a/packages/graphql-elasticsearch-transformer/package.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "name": "graphql-elasticsearch-transformer", - "version": "5.2.81", - "description": "An AppSync model transform that creates an ElasticSearch index with the queries to match.", - "repository": { - "type": "git", - "url": "https://github.com/aws-amplify/amplify-category-api.git", - "directory": "packages/graphql-elasticsearch-transformer" - }, - "author": "Amazon Web Services", - "license": "Apache-2.0", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "keywords": [ - "graphql", - "appsync", - "aws" - ], - "scripts": { - "build": "tsc && cd streaming-lambda && bestzip --force node ../lib/streaming-lambda.zip python_streaming_function.py", - "watch": "tsc -w", - "clean": "rimraf ./lib", - "test": "jest", - "extract-api": "ts-node ../../scripts/extract-api.ts" - }, - "dependencies": { - "cloudform-types": "^4.2.0", - "graphql": "^15.5.0", - "graphql-mapping-template": "4.20.16", - "graphql-transformer-common": "4.31.1", - "graphql-transformer-core": "8.2.13" - }, - "devDependencies": { - "@types/node": "^12.12.6", - "bestzip": "^2.1.5", - "graphql-dynamodb-transformer": "7.2.80" - }, - "jest": { - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, - "testURL": "http://localhost", - "testRegex": "(src/__tests__/.*.test.ts)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], - "collectCoverage": true, - "coverageProvider": "v8", - "coverageThreshold": { - "global": { - "branches": 90, - "functions": 90, - "lines": 90 - } - }, - "coverageReporters": [ - "clover", - "text" - ], - "collectCoverageFrom": [ - "src/**/*.ts" - ], - "coveragePathIgnorePatterns": [ - "/__tests__/" - ] - } -} diff --git a/packages/graphql-elasticsearch-transformer/scripts/ddb_to_es.py b/packages/graphql-elasticsearch-transformer/scripts/ddb_to_es.py deleted file mode 100644 index 4abe312f7c..0000000000 --- a/packages/graphql-elasticsearch-transformer/scripts/ddb_to_es.py +++ /dev/null @@ -1,102 +0,0 @@ -import json -import logging -import argparse -import boto3 -import boto3.dynamodb.table -from boto3 import Session - -logging.basicConfig() -client = boto3.client('lambda', region_name='us-east-1') -reports = [] -object_amount = 0 -partSize = 0 - -def main(): - global client - parser = argparse.ArgumentParser(description='Set-up importing to dynamodb') - parser.add_argument('--rn', metavar='R', help='AWS region', required=True) - parser.add_argument('--tn', metavar='T', help='table name', required=True) - parser.add_argument('--lf', metavar='LF', help='lambda function that posts data to es', required=True) - parser.add_argument('--esarn', metavar='ESARN', help='event source ARN', required=True) - parser.add_argument('--ak', metavar='AK', help='aws access key') - parser.add_argument('--sk', metavar='AS', help='aws secret key') - parser.add_argument('--st', metavar='AT', help='aws session token') - args = parser.parse_args() - scan_limit = 300 - - if (args.ak is None or args.sk is None): - credentials = boto3.Session().get_credentials() - args.sk = args.sk or credentials.secret_key - args.ak = args.ak or credentials.access_key - args.st = args.st or credentials.token - - session = Session( - aws_access_key_id=args.ak, - aws_secret_access_key=args.sk, - aws_session_token=args.st, - region_name=args.rn, - ) - client = session.client('lambda', region_name=args.rn) - import_dynamodb_items_to_es(args.tn, args.sk, args.ak, args.st, args.rn, args.esarn, args.lf, scan_limit) - -def import_dynamodb_items_to_es(table_name, aws_secret, aws_access, aws_token, aws_region, event_source_arn, lambda_f, scan_limit): - global reports - global partSize - global object_amount - - logger = logging.getLogger() - logger.setLevel(logging.INFO) - session = Session(aws_access_key_id=aws_access, aws_secret_access_key=aws_secret, aws_session_token=aws_token, region_name=aws_region) - dynamodb = session.resource('dynamodb') - logger.info('dynamodb: %s', dynamodb) - ddb_table_name = table_name - table = dynamodb.Table(ddb_table_name) - logger.info('table: %s', table) - ddb_keys_name = [a['AttributeName'] for a in table.key_schema] - logger.info('ddb_keys_name: %s', ddb_keys_name) - response = None - - while True: - if not response: - response = table.scan(Limit=scan_limit) - else: - response = table.scan(ExclusiveStartKey=response['LastEvaluatedKey'], Limit=scan_limit) - for i in response["Items"]: - ddb_keys = {k: i[k] for k in i if k in ddb_keys_name} - ddb_data = boto3.dynamodb.types.TypeSerializer().serialize(i)["M"] - ddb_keys = boto3.dynamodb.types.TypeSerializer().serialize(ddb_keys)["M"] - record = { - "dynamodb": {"SequenceNumber": "0000", "Keys": ddb_keys, "NewImage": ddb_data}, - "awsRegion": aws_region, - "eventName": "MODIFY", - "eventSourceARN": event_source_arn, - "eventSource": "aws:dynamodb" - } - partSize += 1 - object_amount += 1 - logger.info(object_amount) - reports.append(record) - if partSize >= 100: - send_to_eslambda(reports, lambda_f) - if 'LastEvaluatedKey' not in response: - break - if partSize > 0: - send_to_eslambda(reports, lambda_f) - -def send_to_eslambda(items, lambda_f): - global reports - global partSize - records_data = { - "Records": items - } - records = json.dumps(records_data) - lambda_response = client.invoke( - FunctionName=lambda_f, - Payload=records - ) - reports = [] - partSize = 0 - print(lambda_response) - -if __name__ == "__main__": - main() diff --git a/packages/graphql-elasticsearch-transformer/src/SearchableModelTransformer.ts b/packages/graphql-elasticsearch-transformer/src/SearchableModelTransformer.ts deleted file mode 100644 index 957f17bd47..0000000000 --- a/packages/graphql-elasticsearch-transformer/src/SearchableModelTransformer.ts +++ /dev/null @@ -1,211 +0,0 @@ -import path = require('path'); -import { Transformer, TransformerContext, getDirectiveArguments, InvalidDirectiveError } from 'graphql-transformer-core'; -import { SearchableDirectiveV1 } from '@aws-amplify/graphql-directives'; -import { DirectiveNode, ObjectTypeDefinitionNode, InputObjectTypeDefinitionNode, parse } from 'graphql'; -import { - makeNamedType, - blankObjectExtension, - makeField, - extensionWithFields, - blankObject, - makeListType, - makeInputValueDefinition, - STANDARD_SCALARS, - makeNonNullType, - ResolverResourceIDs, - SearchableResourceIDs, - ModelResourceIDs, - getBaseType, - ResourceConstants, -} from 'graphql-transformer-common'; -import { Expression, str } from 'graphql-mapping-template'; -import { - makeSearchableScalarInputObject, - makeSearchableXFilterInputObject, - makeSearchableSortDirectionEnumObject, - makeSearchableXSortableFieldsEnumObject, - makeSearchableXSortInputObject, -} from './definitions'; -import { ResourceFactory } from './resources'; - -const STACK_NAME = 'SearchableStack'; -const nonKeywordTypes = ['Int', 'Float', 'Boolean', 'AWSTimestamp', 'AWSDate', 'AWSDateTime']; - -interface SearchableQueryMap { - search?: string; -} - -interface SearchableDirectiveArgs { - queries?: SearchableQueryMap; -} - -/** - * Handles the @searchable directive on OBJECT types. - */ -export class SearchableModelTransformer extends Transformer { - resources: ResourceFactory; - - constructor() { - super(`SearchableModelTransformer`, parse(SearchableDirectiveV1.definition)); - this.resources = new ResourceFactory(); - } - - public before = (ctx: TransformerContext): void => { - const template = this.resources.initTemplate(ctx.isProjectUsingDataStore()); - ctx.mergeResources(template.Resources); - ctx.mergeParameters(template.Parameters); - ctx.mergeOutputs(template.Outputs); - ctx.mergeMappings(template.Mappings); - ctx.metadata.set( - ResourceConstants.RESOURCES.ElasticsearchStreamingLambdaFunctionLogicalID, - path.resolve(`${__dirname}/../lib/streaming-lambda.zip`), - ); - for (const resourceId of Object.keys(template.Resources)) { - ctx.mapResourceToStack(STACK_NAME, resourceId); - } - for (const outputId of Object.keys(template.Outputs)) { - ctx.mapResourceToStack(STACK_NAME, outputId); - } - for (const mappingId of Object.keys(template.Mappings)) { - ctx.mapResourceToStack(STACK_NAME, mappingId); - } - }; - - /** - * Given the initial input and context manipulate the context to handle this object directive. - * @param initial The input passed to the transform. - * @param ctx The accumulated context for the transform. - */ - public object = (def: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext): void => { - const modelDirective = def.directives.find((dir) => dir.name.value === 'model'); - if (!modelDirective) { - throw new InvalidDirectiveError('Types annotated with @searchable must also be annotated with @model.'); - } - const directiveArguments: SearchableDirectiveArgs = getDirectiveArguments(directive); - let shouldMakeSearch = true; - let searchFieldNameOverride = undefined; - - // Figure out which queries to make and if they have name overrides. - if (directiveArguments.queries) { - if (!directiveArguments.queries.search) { - shouldMakeSearch = false; - } else { - searchFieldNameOverride = directiveArguments.queries.search; - } - } - - const typeName = def.name.value; - ctx.setResource( - SearchableResourceIDs.SearchableEventSourceMappingID(typeName), - this.resources.makeDynamoDBStreamEventSourceMapping(typeName), - ); - ctx.mapResourceToStack(STACK_NAME, SearchableResourceIDs.SearchableEventSourceMappingID(typeName)); - - // SearchablePostSortableFields - const queryFields = []; - const nonKeywordFields: Expression[] = []; - def.fields.forEach((field) => { - if (nonKeywordTypes.includes(getBaseType(field.type))) { - nonKeywordFields.push(str(field.name.value)); - } - }); - - // Get primary key to use as the default sort field - const primaryKey = this.getPrimaryKey(ctx, typeName); - - // Create list - if (shouldMakeSearch) { - this.generateSearchableInputs(ctx, def); - this.generateSearchableXConnectionType(ctx, def); - - const searchResolver = this.resources.makeSearchResolver( - def.name.value, - nonKeywordFields, - primaryKey, - ctx.getQueryTypeName(), - ctx.featureFlags.getBoolean('improvePluralization'), - searchFieldNameOverride, - ctx.isProjectUsingDataStore(), - ); - ctx.setResource(ResolverResourceIDs.ElasticsearchSearchResolverResourceID(def.name.value), searchResolver); - ctx.mapResourceToStack(STACK_NAME, ResolverResourceIDs.ElasticsearchSearchResolverResourceID(def.name.value)); - queryFields.push( - makeField( - searchResolver.Properties.FieldName.toString(), - [ - makeInputValueDefinition('filter', makeNamedType(`Searchable${def.name.value}FilterInput`)), - makeInputValueDefinition('sort', makeNamedType(`Searchable${def.name.value}SortInput`)), - makeInputValueDefinition('limit', makeNamedType('Int')), - makeInputValueDefinition('nextToken', makeNamedType('String')), - makeInputValueDefinition('from', makeNamedType('Int')), - ], - makeNamedType(`Searchable${def.name.value}Connection`), - ), - ); - } - - ctx.addQueryFields(queryFields); - }; - - private generateSearchableXConnectionType(ctx: TransformerContext, def: ObjectTypeDefinitionNode): void { - const searchableXConnectionName = `Searchable${def.name.value}Connection`; - if (this.typeExist(searchableXConnectionName, ctx)) { - return; - } - - // Create the TableXConnection - const connectionType = blankObject(searchableXConnectionName); - ctx.addObject(connectionType); - - // Create TableXConnection type with items and nextToken - let connectionTypeExtension = blankObjectExtension(searchableXConnectionName); - connectionTypeExtension = extensionWithFields(connectionTypeExtension, [ - makeField('items', [], makeNonNullType(makeListType(makeNamedType(def.name.value)))), - ]); - connectionTypeExtension = extensionWithFields(connectionTypeExtension, [ - makeField('nextToken', [], makeNamedType('String')), - makeField('total', [], makeNamedType('Int')), - ]); - ctx.addObjectExtension(connectionTypeExtension); - } - - private typeExist(type: string, ctx: TransformerContext): boolean { - return Boolean(type in ctx.nodeMap); - } - - private generateSearchableInputs(ctx: TransformerContext, def: ObjectTypeDefinitionNode): void { - // Create the Scalar filter inputs - const inputs: string[] = Object.keys(STANDARD_SCALARS); - inputs - .filter((input: string) => !this.typeExist(`Searchable${input}FilterInput`, ctx)) - .map((input: string) => makeSearchableScalarInputObject(input)) - .forEach((node: InputObjectTypeDefinitionNode) => ctx.addInput(node)); - - const searchableXQueryFilterInput = makeSearchableXFilterInputObject(def); - if (!this.typeExist(searchableXQueryFilterInput.name.value, ctx)) { - ctx.addInput(searchableXQueryFilterInput); - } - - if (!this.typeExist('SearchableSortDirection', ctx)) { - const searchableSortDirection = makeSearchableSortDirectionEnumObject(); - ctx.addEnum(searchableSortDirection); - } - - if (!this.typeExist(`Searchable${def.name.value}SortableFields`, ctx)) { - const searchableXSortableFieldsDirection = makeSearchableXSortableFieldsEnumObject(def); - ctx.addEnum(searchableXSortableFieldsDirection); - } - - if (!this.typeExist(`Searchable${def.name.value}SortInput`, ctx)) { - const searchableXSortableInputDirection = makeSearchableXSortInputObject(def); - ctx.addInput(searchableXSortableInputDirection); - } - } - - private getPrimaryKey(ctx: TransformerContext, typeName: string): string { - const tableResourceID = ModelResourceIDs.ModelTableResourceID(typeName); - const tableResource = ctx.getResource(tableResourceID); - const primaryKeySchemaElement = tableResource.Properties.KeySchema.find((keyElement: any) => keyElement.KeyType === 'HASH'); - return primaryKeySchemaElement.AttributeName; - } -} diff --git a/packages/graphql-elasticsearch-transformer/src/__tests__/SearchableModelTransformer.test.ts b/packages/graphql-elasticsearch-transformer/src/__tests__/SearchableModelTransformer.test.ts deleted file mode 100644 index 12d2234070..0000000000 --- a/packages/graphql-elasticsearch-transformer/src/__tests__/SearchableModelTransformer.test.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { GraphQLTransform, TRANSFORM_CURRENT_VERSION, ConflictHandlerType } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { SearchableModelTransformer } from '../SearchableModelTransformer'; - -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -test('SearchableModelTransformer validation happy case', () => { - const validSchema = ` - type Post @model @searchable { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new SearchableModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.schema).toBeDefined(); - expect(out.schema).toMatchSnapshot(); -}); - -test('SearchableModelTransformer with query overrides', () => { - const validSchema = `type Post @model @searchable(queries: { search: "customSearchPost" }) { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new SearchableModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.schema).toBeDefined(); - expect(out.schema).toMatchSnapshot(); -}); - -test('SearchableModelTransformer with only create mutations', () => { - const validSchema = `type Post @model(mutations: { create: "customCreatePost" }) @searchable { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new SearchableModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.schema).toBeDefined(); - expect(out.schema).toMatchSnapshot(); -}); - -test('SearchableModelTransformer with multiple model searchable directives', () => { - const validSchema = ` - type Post @model @searchable { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - - type User @model @searchable { - id: ID! - name: String! - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new SearchableModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.schema).toBeDefined(); - expect(out.schema).toMatchSnapshot(); -}); - -test('SearchableModelTransformer with sort fields', () => { - const validSchema = ` - type Post @model @searchable { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new SearchableModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.schema).toBeDefined(); - expect(out.schema).toMatchSnapshot(); -}); - -test('SearchableModelTransformer with external versioning', () => { - const expectedSearchResolverBase = 'Query.searchPosts.'; - const expectedSearchRequestResolver = expectedSearchResolverBase + 'req.vtl'; - const expectedSearchResponseResolver = expectedSearchResolverBase + 'res.vtl'; - const validSchema = ` - type Post @model @searchable { - id: ID! - title: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new SearchableModelTransformer()], - featureFlags, - transformConfig: { - Version: TRANSFORM_CURRENT_VERSION, - ResolverConfig: { - project: { - ConflictDetection: 'VERSION', - ConflictHandler: ConflictHandlerType.AUTOMERGE, - }, - models: undefined, - }, - }, - }); - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.resolvers).toBeDefined(); - expect(out.resolvers[expectedSearchRequestResolver]).toBeDefined(); - expect(out.resolvers[expectedSearchRequestResolver]).toMatchSnapshot(); - expect(out.resolvers[expectedSearchResponseResolver]).toBeDefined(); - expect(out.resolvers[expectedSearchResponseResolver]).toMatchSnapshot(); -}); diff --git a/packages/graphql-elasticsearch-transformer/src/__tests__/__snapshots__/SearchableModelTransformer.test.ts.snap b/packages/graphql-elasticsearch-transformer/src/__tests__/__snapshots__/SearchableModelTransformer.test.ts.snap deleted file mode 100644 index 050a91d8f3..0000000000 --- a/packages/graphql-elasticsearch-transformer/src/__tests__/__snapshots__/SearchableModelTransformer.test.ts.snap +++ /dev/null @@ -1,1153 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`SearchableModelTransformer validation happy case 1`] = ` -"type Post { - id: ID! - title: String! - createdAt: String - updatedAt: String -} - -enum ModelSortDirection { - ASC - DESC -} - -type ModelPostConnection { - items: [Post]! - nextToken: String -} - -input ModelStringFilterInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String -} - -input ModelIDFilterInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID -} - -input ModelIntFilterInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelFloatFilterInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] -} - -input ModelBooleanFilterInput { - ne: Boolean - eq: Boolean -} - -input ModelPostFilterInput { - id: ModelIDFilterInput - title: ModelStringFilterInput - createdAt: ModelStringFilterInput - updatedAt: ModelStringFilterInput - and: [ModelPostFilterInput] - or: [ModelPostFilterInput] - not: ModelPostFilterInput -} - -type Query { - getPost(id: ID!): Post - listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection - searchPosts(filter: SearchablePostFilterInput, sort: SearchablePostSortInput, limit: Int, nextToken: String, from: Int): SearchablePostConnection -} - -input CreatePostInput { - id: ID - title: String! - createdAt: String - updatedAt: String -} - -input UpdatePostInput { - id: ID! - title: String - createdAt: String - updatedAt: String -} - -input DeletePostInput { - id: ID! -} - -type Mutation { - createPost(input: CreatePostInput!): Post - updatePost(input: UpdatePostInput!): Post - deletePost(input: DeletePostInput!): Post -} - -type Subscription { - onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) - onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) - onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) -} - -input SearchableStringFilterInput { - ne: String - gt: String - lt: String - gte: String - lte: String - eq: String - match: String - matchPhrase: String - matchPhrasePrefix: String - multiMatch: String - exists: Boolean - wildcard: String - regexp: String - range: [String] -} - -input SearchableIntFilterInput { - ne: Int - gt: Int - lt: Int - gte: Int - lte: Int - eq: Int - range: [Int] -} - -input SearchableFloatFilterInput { - ne: Float - gt: Float - lt: Float - gte: Float - lte: Float - eq: Float - range: [Float] -} - -input SearchableBooleanFilterInput { - eq: Boolean - ne: Boolean -} - -input SearchableIDFilterInput { - ne: ID - gt: ID - lt: ID - gte: ID - lte: ID - eq: ID - match: ID - matchPhrase: ID - matchPhrasePrefix: ID - multiMatch: ID - exists: Boolean - wildcard: ID - regexp: ID - range: [ID] -} - -input SearchablePostFilterInput { - id: SearchableIDFilterInput - title: SearchableStringFilterInput - createdAt: SearchableStringFilterInput - updatedAt: SearchableStringFilterInput - and: [SearchablePostFilterInput] - or: [SearchablePostFilterInput] - not: SearchablePostFilterInput -} - -enum SearchableSortDirection { - asc - desc -} - -enum SearchablePostSortableFields { - id - title - createdAt - updatedAt -} - -input SearchablePostSortInput { - field: SearchablePostSortableFields - direction: SearchableSortDirection -} - -type SearchablePostConnection { - items: [Post]! - nextToken: String - total: Int -} -" -`; - -exports[`SearchableModelTransformer with external versioning 1`] = ` -"#set( $indexPath = \\"/post/doc/_search\\" ) -#set( $nonKeywordFields = [] ) -#if( $util.isNullOrEmpty($context.args.sort) ) - #set( $sortDirection = \\"desc\\" ) - #set( $sortField = \\"id\\" ) -#else - #set( $sortDirection = $util.defaultIfNull($context.args.sort.direction, \\"desc\\") ) - #set( $sortField = $util.defaultIfNull($context.args.sort.field, \\"id\\") ) -#end -#if( $nonKeywordFields.contains($sortField) ) - #set( $sortField0 = $util.toJson($sortField) ) -#else - #set( $sortField0 = $util.toJson(\\"\${sortField}.keyword\\") ) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GET\\", - \\"path\\": \\"$indexPath\\", - \\"params\\": { - \\"body\\": { - #if( $context.args.nextToken )\\"search_after\\": [$util.toJson($context.args.nextToken)], #end - #if( $context.args.from )\\"from\\": $context.args.from, #end - \\"size\\": #if( $context.args.limit ) $context.args.limit #else 100 #end, - \\"sort\\": [{$sortField0: { \\"order\\" : $util.toJson($sortDirection) }}], - \\"version\\": true, - \\"query\\": #if( $context.args.filter ) -$util.transform.toElasticsearchQueryDSL($ctx.args.filter) -#else -{ - \\"match_all\\": {} - } -#end - } - } -}" -`; - -exports[`SearchableModelTransformer with external versioning 2`] = ` -"#set( $es_items = [] ) -#foreach( $entry in $context.result.hits.hits ) - #if( !$foreach.hasNext ) - #set( $nextToken = $entry.sort.get(0) ) - #end - #set( $row = $entry.get(\\"_source\\") ) - $util.qr($row.put(\\"_version\\", $entry.get(\\"_version\\"))) - $util.qr($es_items.add($row)) -#end -$util.toJson({ - \\"items\\": $es_items, - \\"total\\": $ctx.result.hits.total, - \\"nextToken\\": $nextToken -})" -`; - -exports[`SearchableModelTransformer with multiple model searchable directives 1`] = ` -"type Post { - id: ID! - title: String! - createdAt: String - updatedAt: String -} - -type User { - id: ID! - name: String! - createdAt: AWSDateTime! - updatedAt: AWSDateTime! -} - -enum ModelSortDirection { - ASC - DESC -} - -type ModelPostConnection { - items: [Post]! - nextToken: String -} - -input ModelStringFilterInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String -} - -input ModelIDFilterInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID -} - -input ModelIntFilterInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelFloatFilterInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] -} - -input ModelBooleanFilterInput { - ne: Boolean - eq: Boolean -} - -input ModelPostFilterInput { - id: ModelIDFilterInput - title: ModelStringFilterInput - createdAt: ModelStringFilterInput - updatedAt: ModelStringFilterInput - and: [ModelPostFilterInput] - or: [ModelPostFilterInput] - not: ModelPostFilterInput -} - -type Query { - getPost(id: ID!): Post - listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection - getUser(id: ID!): User - listUsers(filter: ModelUserFilterInput, limit: Int, nextToken: String): ModelUserConnection - searchPosts(filter: SearchablePostFilterInput, sort: SearchablePostSortInput, limit: Int, nextToken: String, from: Int): SearchablePostConnection - searchUsers(filter: SearchableUserFilterInput, sort: SearchableUserSortInput, limit: Int, nextToken: String, from: Int): SearchableUserConnection -} - -input CreatePostInput { - id: ID - title: String! - createdAt: String - updatedAt: String -} - -input UpdatePostInput { - id: ID! - title: String - createdAt: String - updatedAt: String -} - -input DeletePostInput { - id: ID! -} - -type Mutation { - createPost(input: CreatePostInput!): Post - updatePost(input: UpdatePostInput!): Post - deletePost(input: DeletePostInput!): Post - createUser(input: CreateUserInput!): User - updateUser(input: UpdateUserInput!): User - deleteUser(input: DeleteUserInput!): User -} - -type Subscription { - onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) - onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) - onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) - onCreateUser: User @aws_subscribe(mutations: [\\"createUser\\"]) - onUpdateUser: User @aws_subscribe(mutations: [\\"updateUser\\"]) - onDeleteUser: User @aws_subscribe(mutations: [\\"deleteUser\\"]) -} - -type ModelUserConnection { - items: [User]! - nextToken: String -} - -input ModelUserFilterInput { - id: ModelIDFilterInput - name: ModelStringFilterInput - and: [ModelUserFilterInput] - or: [ModelUserFilterInput] - not: ModelUserFilterInput -} - -input CreateUserInput { - id: ID - name: String! -} - -input UpdateUserInput { - id: ID! - name: String -} - -input DeleteUserInput { - id: ID! -} - -input SearchableStringFilterInput { - ne: String - gt: String - lt: String - gte: String - lte: String - eq: String - match: String - matchPhrase: String - matchPhrasePrefix: String - multiMatch: String - exists: Boolean - wildcard: String - regexp: String - range: [String] -} - -input SearchableIntFilterInput { - ne: Int - gt: Int - lt: Int - gte: Int - lte: Int - eq: Int - range: [Int] -} - -input SearchableFloatFilterInput { - ne: Float - gt: Float - lt: Float - gte: Float - lte: Float - eq: Float - range: [Float] -} - -input SearchableBooleanFilterInput { - eq: Boolean - ne: Boolean -} - -input SearchableIDFilterInput { - ne: ID - gt: ID - lt: ID - gte: ID - lte: ID - eq: ID - match: ID - matchPhrase: ID - matchPhrasePrefix: ID - multiMatch: ID - exists: Boolean - wildcard: ID - regexp: ID - range: [ID] -} - -input SearchablePostFilterInput { - id: SearchableIDFilterInput - title: SearchableStringFilterInput - createdAt: SearchableStringFilterInput - updatedAt: SearchableStringFilterInput - and: [SearchablePostFilterInput] - or: [SearchablePostFilterInput] - not: SearchablePostFilterInput -} - -enum SearchableSortDirection { - asc - desc -} - -enum SearchablePostSortableFields { - id - title - createdAt - updatedAt -} - -input SearchablePostSortInput { - field: SearchablePostSortableFields - direction: SearchableSortDirection -} - -type SearchablePostConnection { - items: [Post]! - nextToken: String - total: Int -} - -input SearchableUserFilterInput { - id: SearchableIDFilterInput - name: SearchableStringFilterInput - and: [SearchableUserFilterInput] - or: [SearchableUserFilterInput] - not: SearchableUserFilterInput -} - -enum SearchableUserSortableFields { - id - name -} - -input SearchableUserSortInput { - field: SearchableUserSortableFields - direction: SearchableSortDirection -} - -type SearchableUserConnection { - items: [User]! - nextToken: String - total: Int -} -" -`; - -exports[`SearchableModelTransformer with only create mutations 1`] = ` -"type Post { - id: ID! - title: String! - createdAt: String - updatedAt: String -} - -enum ModelSortDirection { - ASC - DESC -} - -type ModelPostConnection { - items: [Post]! - nextToken: String -} - -input ModelStringFilterInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String -} - -input ModelIDFilterInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID -} - -input ModelIntFilterInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelFloatFilterInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] -} - -input ModelBooleanFilterInput { - ne: Boolean - eq: Boolean -} - -input ModelPostFilterInput { - id: ModelIDFilterInput - title: ModelStringFilterInput - createdAt: ModelStringFilterInput - updatedAt: ModelStringFilterInput - and: [ModelPostFilterInput] - or: [ModelPostFilterInput] - not: ModelPostFilterInput -} - -type Query { - getPost(id: ID!): Post - listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection - searchPosts(filter: SearchablePostFilterInput, sort: SearchablePostSortInput, limit: Int, nextToken: String, from: Int): SearchablePostConnection -} - -input CreatePostInput { - id: ID - title: String! - createdAt: String - updatedAt: String -} - -type Mutation { - customCreatePost(input: CreatePostInput!): Post -} - -type Subscription { - onCreatePost: Post @aws_subscribe(mutations: [\\"customCreatePost\\"]) -} - -input SearchableStringFilterInput { - ne: String - gt: String - lt: String - gte: String - lte: String - eq: String - match: String - matchPhrase: String - matchPhrasePrefix: String - multiMatch: String - exists: Boolean - wildcard: String - regexp: String - range: [String] -} - -input SearchableIntFilterInput { - ne: Int - gt: Int - lt: Int - gte: Int - lte: Int - eq: Int - range: [Int] -} - -input SearchableFloatFilterInput { - ne: Float - gt: Float - lt: Float - gte: Float - lte: Float - eq: Float - range: [Float] -} - -input SearchableBooleanFilterInput { - eq: Boolean - ne: Boolean -} - -input SearchableIDFilterInput { - ne: ID - gt: ID - lt: ID - gte: ID - lte: ID - eq: ID - match: ID - matchPhrase: ID - matchPhrasePrefix: ID - multiMatch: ID - exists: Boolean - wildcard: ID - regexp: ID - range: [ID] -} - -input SearchablePostFilterInput { - id: SearchableIDFilterInput - title: SearchableStringFilterInput - createdAt: SearchableStringFilterInput - updatedAt: SearchableStringFilterInput - and: [SearchablePostFilterInput] - or: [SearchablePostFilterInput] - not: SearchablePostFilterInput -} - -enum SearchableSortDirection { - asc - desc -} - -enum SearchablePostSortableFields { - id - title - createdAt - updatedAt -} - -input SearchablePostSortInput { - field: SearchablePostSortableFields - direction: SearchableSortDirection -} - -type SearchablePostConnection { - items: [Post]! - nextToken: String - total: Int -} -" -`; - -exports[`SearchableModelTransformer with query overrides 1`] = ` -"type Post { - id: ID! - title: String! - createdAt: String - updatedAt: String -} - -enum ModelSortDirection { - ASC - DESC -} - -type ModelPostConnection { - items: [Post]! - nextToken: String -} - -input ModelStringFilterInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String -} - -input ModelIDFilterInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID -} - -input ModelIntFilterInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelFloatFilterInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] -} - -input ModelBooleanFilterInput { - ne: Boolean - eq: Boolean -} - -input ModelPostFilterInput { - id: ModelIDFilterInput - title: ModelStringFilterInput - createdAt: ModelStringFilterInput - updatedAt: ModelStringFilterInput - and: [ModelPostFilterInput] - or: [ModelPostFilterInput] - not: ModelPostFilterInput -} - -type Query { - getPost(id: ID!): Post - listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection - customSearchPost(filter: SearchablePostFilterInput, sort: SearchablePostSortInput, limit: Int, nextToken: String, from: Int): SearchablePostConnection -} - -input CreatePostInput { - id: ID - title: String! - createdAt: String - updatedAt: String -} - -input UpdatePostInput { - id: ID! - title: String - createdAt: String - updatedAt: String -} - -input DeletePostInput { - id: ID! -} - -type Mutation { - createPost(input: CreatePostInput!): Post - updatePost(input: UpdatePostInput!): Post - deletePost(input: DeletePostInput!): Post -} - -type Subscription { - onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) - onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) - onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) -} - -input SearchableStringFilterInput { - ne: String - gt: String - lt: String - gte: String - lte: String - eq: String - match: String - matchPhrase: String - matchPhrasePrefix: String - multiMatch: String - exists: Boolean - wildcard: String - regexp: String - range: [String] -} - -input SearchableIntFilterInput { - ne: Int - gt: Int - lt: Int - gte: Int - lte: Int - eq: Int - range: [Int] -} - -input SearchableFloatFilterInput { - ne: Float - gt: Float - lt: Float - gte: Float - lte: Float - eq: Float - range: [Float] -} - -input SearchableBooleanFilterInput { - eq: Boolean - ne: Boolean -} - -input SearchableIDFilterInput { - ne: ID - gt: ID - lt: ID - gte: ID - lte: ID - eq: ID - match: ID - matchPhrase: ID - matchPhrasePrefix: ID - multiMatch: ID - exists: Boolean - wildcard: ID - regexp: ID - range: [ID] -} - -input SearchablePostFilterInput { - id: SearchableIDFilterInput - title: SearchableStringFilterInput - createdAt: SearchableStringFilterInput - updatedAt: SearchableStringFilterInput - and: [SearchablePostFilterInput] - or: [SearchablePostFilterInput] - not: SearchablePostFilterInput -} - -enum SearchableSortDirection { - asc - desc -} - -enum SearchablePostSortableFields { - id - title - createdAt - updatedAt -} - -input SearchablePostSortInput { - field: SearchablePostSortableFields - direction: SearchableSortDirection -} - -type SearchablePostConnection { - items: [Post]! - nextToken: String - total: Int -} -" -`; - -exports[`SearchableModelTransformer with sort fields 1`] = ` -"type Post { - id: ID! - title: String! - createdAt: String - updatedAt: String -} - -enum ModelSortDirection { - ASC - DESC -} - -type ModelPostConnection { - items: [Post]! - nextToken: String -} - -input ModelStringFilterInput { - ne: String - eq: String - le: String - lt: String - ge: String - gt: String - contains: String - notContains: String - between: [String] - beginsWith: String -} - -input ModelIDFilterInput { - ne: ID - eq: ID - le: ID - lt: ID - ge: ID - gt: ID - contains: ID - notContains: ID - between: [ID] - beginsWith: ID -} - -input ModelIntFilterInput { - ne: Int - eq: Int - le: Int - lt: Int - ge: Int - gt: Int - between: [Int] -} - -input ModelFloatFilterInput { - ne: Float - eq: Float - le: Float - lt: Float - ge: Float - gt: Float - between: [Float] -} - -input ModelBooleanFilterInput { - ne: Boolean - eq: Boolean -} - -input ModelPostFilterInput { - id: ModelIDFilterInput - title: ModelStringFilterInput - createdAt: ModelStringFilterInput - updatedAt: ModelStringFilterInput - and: [ModelPostFilterInput] - or: [ModelPostFilterInput] - not: ModelPostFilterInput -} - -type Query { - getPost(id: ID!): Post - listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection - searchPosts(filter: SearchablePostFilterInput, sort: SearchablePostSortInput, limit: Int, nextToken: String, from: Int): SearchablePostConnection -} - -input CreatePostInput { - id: ID - title: String! - createdAt: String - updatedAt: String -} - -input UpdatePostInput { - id: ID! - title: String - createdAt: String - updatedAt: String -} - -input DeletePostInput { - id: ID! -} - -type Mutation { - createPost(input: CreatePostInput!): Post - updatePost(input: UpdatePostInput!): Post - deletePost(input: DeletePostInput!): Post -} - -type Subscription { - onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) - onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) - onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) -} - -input SearchableStringFilterInput { - ne: String - gt: String - lt: String - gte: String - lte: String - eq: String - match: String - matchPhrase: String - matchPhrasePrefix: String - multiMatch: String - exists: Boolean - wildcard: String - regexp: String - range: [String] -} - -input SearchableIntFilterInput { - ne: Int - gt: Int - lt: Int - gte: Int - lte: Int - eq: Int - range: [Int] -} - -input SearchableFloatFilterInput { - ne: Float - gt: Float - lt: Float - gte: Float - lte: Float - eq: Float - range: [Float] -} - -input SearchableBooleanFilterInput { - eq: Boolean - ne: Boolean -} - -input SearchableIDFilterInput { - ne: ID - gt: ID - lt: ID - gte: ID - lte: ID - eq: ID - match: ID - matchPhrase: ID - matchPhrasePrefix: ID - multiMatch: ID - exists: Boolean - wildcard: ID - regexp: ID - range: [ID] -} - -input SearchablePostFilterInput { - id: SearchableIDFilterInput - title: SearchableStringFilterInput - createdAt: SearchableStringFilterInput - updatedAt: SearchableStringFilterInput - and: [SearchablePostFilterInput] - or: [SearchablePostFilterInput] - not: SearchablePostFilterInput -} - -enum SearchableSortDirection { - asc - desc -} - -enum SearchablePostSortableFields { - id - title - createdAt - updatedAt -} - -input SearchablePostSortInput { - field: SearchablePostSortableFields - direction: SearchableSortDirection -} - -type SearchablePostConnection { - items: [Post]! - nextToken: String - total: Int -} -" -`; diff --git a/packages/graphql-elasticsearch-transformer/src/definitions.ts b/packages/graphql-elasticsearch-transformer/src/definitions.ts deleted file mode 100644 index f391b3ceff..0000000000 --- a/packages/graphql-elasticsearch-transformer/src/definitions.ts +++ /dev/null @@ -1,232 +0,0 @@ -import { - ObjectTypeDefinitionNode, - InputValueDefinitionNode, - InputObjectTypeDefinitionNode, - FieldDefinitionNode, - Kind, - TypeNode, - EnumTypeDefinitionNode, - EnumValueDefinitionNode, -} from 'graphql'; -import { graphqlName, makeNamedType, isScalar, makeListType, getBaseType, SearchableResourceIDs } from 'graphql-transformer-common'; - -const ID_CONDITIONS = [ - 'ne', - 'gt', - 'lt', - 'gte', - 'lte', - 'eq', - 'match', - 'matchPhrase', - 'matchPhrasePrefix', - 'multiMatch', - 'exists', - 'wildcard', - 'regexp', - 'range', -]; -const STRING_CONDITIONS = ID_CONDITIONS; -const INT_CONDITIONS = ['ne', 'gt', 'lt', 'gte', 'lte', 'eq', 'range']; -const FLOAT_CONDITIONS = ['ne', 'gt', 'lt', 'gte', 'lte', 'eq', 'range']; -const BOOLEAN_CONDITIONS = ['eq', 'ne']; - -export function makeSearchableScalarInputObject(type: string): InputObjectTypeDefinitionNode { - const name = SearchableResourceIDs.SearchableFilterInputTypeName(type); - const conditions = getScalarConditions(type); - const fields: InputValueDefinitionNode[] = conditions.map((condition: string) => ({ - kind: Kind.INPUT_VALUE_DEFINITION, - name: { kind: 'Name' as const, value: condition }, - type: getScalarFilterInputType(condition, type, name), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - })); - return { - kind: Kind.INPUT_OBJECT_TYPE_DEFINITION, - // TODO: Service does not support new style descriptions so wait. - // description: { - // kind: 'StringValue', - // value: `Input type for ${obj.name.value} mutations` - // }, - name: { - kind: 'Name', - value: name, - }, - fields, - directives: [], - }; -} - -export function makeSearchableXFilterInputObject(obj: ObjectTypeDefinitionNode): InputObjectTypeDefinitionNode { - const name = SearchableResourceIDs.SearchableFilterInputTypeName(obj.name.value); - const fields: InputValueDefinitionNode[] = obj.fields - .filter((field: FieldDefinitionNode) => isScalar(field.type) === true) - .map((field: FieldDefinitionNode) => ({ - kind: Kind.INPUT_VALUE_DEFINITION, - name: field.name, - type: makeNamedType(SearchableResourceIDs.SearchableFilterInputTypeName(getBaseType(field.type))), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - })); - - fields.push( - { - kind: Kind.INPUT_VALUE_DEFINITION, - name: { - kind: 'Name', - value: 'and', - }, - type: makeListType(makeNamedType(name)), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - }, - { - kind: Kind.INPUT_VALUE_DEFINITION, - name: { - kind: 'Name', - value: 'or', - }, - type: makeListType(makeNamedType(name)), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - }, - { - kind: Kind.INPUT_VALUE_DEFINITION, - name: { - kind: 'Name', - value: 'not', - }, - type: makeNamedType(name), - // TODO: Service does not support new style descriptions so wait. - // description: field.description, - directives: [], - }, - ); - return { - kind: Kind.INPUT_OBJECT_TYPE_DEFINITION, - name: { - kind: 'Name', - value: name, - }, - fields, - directives: [], - }; -} - -export function makeSearchableSortDirectionEnumObject(): EnumTypeDefinitionNode { - const name = graphqlName(`SearchableSortDirection`); - return { - kind: Kind.ENUM_TYPE_DEFINITION, - name: { - kind: 'Name', - value: name, - }, - values: [ - { - kind: Kind.ENUM_VALUE_DEFINITION, - name: { kind: 'Name', value: 'asc' }, - directives: [], - }, - { - kind: Kind.ENUM_VALUE_DEFINITION, - name: { kind: 'Name', value: 'desc' }, - directives: [], - }, - ], - directives: [], - }; -} - -export function makeSearchableXSortableFieldsEnumObject(obj: ObjectTypeDefinitionNode): EnumTypeDefinitionNode { - const name = graphqlName(`Searchable${obj.name.value}SortableFields`); - const values: EnumValueDefinitionNode[] = obj.fields - .filter((field: FieldDefinitionNode) => isScalar(field.type) === true) - .map((field: FieldDefinitionNode) => ({ - kind: Kind.ENUM_VALUE_DEFINITION, - name: field.name, - directives: [], - })); - - return { - kind: Kind.ENUM_TYPE_DEFINITION, - name: { - kind: 'Name', - value: name, - }, - values, - directives: [], - }; -} - -export function makeSearchableXSortInputObject(obj: ObjectTypeDefinitionNode): InputObjectTypeDefinitionNode { - const name = graphqlName(`Searchable${obj.name.value}SortInput`); - return { - kind: Kind.INPUT_OBJECT_TYPE_DEFINITION, - // TODO: Service does not support new style descriptions so wait. - // description: { - // kind: 'StringValue', - // value: `Input type for ${obj.name.value} delete mutations` - // }, - name: { - kind: 'Name', - value: name, - }, - fields: [ - { - kind: Kind.INPUT_VALUE_DEFINITION, - name: { kind: 'Name', value: 'field' }, - type: makeNamedType(`Searchable${obj.name.value}SortableFields`), - // TODO: Service does not support new style descriptions so wait. - // description: { - // kind: 'StringValue', - // value: `The id of the ${obj.name.value} to delete.` - // }, - directives: [], - }, - { - kind: Kind.INPUT_VALUE_DEFINITION, - name: { kind: 'Name', value: 'direction' }, - type: makeNamedType('SearchableSortDirection'), - // TODO: Service does not support new style descriptions so wait. - // description: { - // kind: 'StringValue', - // value: `The id of the ${obj.name.value} to delete.` - // }, - directives: [], - }, - ], - directives: [], - }; -} - -function getScalarFilterInputType(condition: string, type: string, filterInputName: string): TypeNode { - switch (condition) { - case 'range': - return makeListType(makeNamedType(type)); - case 'exists': - return makeNamedType('Boolean'); - default: - return makeNamedType(type); - } -} - -function getScalarConditions(type: string): string[] { - switch (type) { - case 'String': - return STRING_CONDITIONS; - case 'ID': - return ID_CONDITIONS; - case 'Int': - return INT_CONDITIONS; - case 'Float': - return FLOAT_CONDITIONS; - case 'Boolean': - return BOOLEAN_CONDITIONS; - default: - throw 'Valid types are String, ID, Int, Float, Boolean'; - } -} diff --git a/packages/graphql-elasticsearch-transformer/src/index.ts b/packages/graphql-elasticsearch-transformer/src/index.ts deleted file mode 100644 index 50380e7855..0000000000 --- a/packages/graphql-elasticsearch-transformer/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './SearchableModelTransformer'; -// No-op change to trigger re-publish diff --git a/packages/graphql-elasticsearch-transformer/src/resources.ts b/packages/graphql-elasticsearch-transformer/src/resources.ts deleted file mode 100644 index 97d018cbc3..0000000000 --- a/packages/graphql-elasticsearch-transformer/src/resources.ts +++ /dev/null @@ -1,622 +0,0 @@ -import Output from 'cloudform-types/types/output'; -import AppSync from 'cloudform-types/types/appSync'; -import IAM from 'cloudform-types/types/iam'; -import Template from 'cloudform-types/types/template'; -import { Fn, StringParameter, NumberParameter, Lambda, Elasticsearch, Refs } from 'cloudform-types'; -import { - ElasticsearchMappingTemplate, - print, - str, - ref, - obj, - set, - iff, - list, - raw, - forEach, - compoundExpression, - qref, - toJson, - ifElse, - int, - Expression, - bool, - methodCall, -} from 'graphql-mapping-template'; -import { toUpper, plurality, graphqlName, ResourceConstants, ModelResourceIDs } from 'graphql-transformer-common'; -import { MappingParameters } from 'graphql-transformer-core'; - -/** - * ResourceFactory - */ -export class ResourceFactory { - /** - * Generate CFN Parameters section - */ - public makeParams() { - return { - [ResourceConstants.PARAMETERS.ElasticsearchAccessIAMRoleName]: new StringParameter({ - Description: 'The name of the IAM role assumed by AppSync for Elasticsearch.', - Default: 'AppSyncElasticsearchRole', - }), - [ResourceConstants.PARAMETERS.ElasticsearchStreamingLambdaHandlerName]: new StringParameter({ - Description: 'The name of the lambda handler.', - Default: 'python_streaming_function.lambda_handler', - }), - [ResourceConstants.PARAMETERS.ElasticsearchStreamingLambdaRuntime]: new StringParameter({ - Description: - 'The lambda runtime \ - (https://docs.aws.amazon.com/lambda/latest/dg/API_CreateFunction.html#SSS-CreateFunction-request-Runtime)', - Default: 'python3.9', - }), - [ResourceConstants.PARAMETERS.ElasticsearchStreamingFunctionName]: new StringParameter({ - Description: 'The name of the streaming lambda function.', - Default: 'DdbToEsFn', - }), - [ResourceConstants.PARAMETERS.ElasticsearchStreamingIAMRoleName]: new StringParameter({ - Description: 'The name of the streaming lambda function IAM role.', - Default: 'SearchableLambdaIAMRole', - }), - [ResourceConstants.PARAMETERS.ElasticsearchDebugStreamingLambda]: new NumberParameter({ - Description: 'Enable debug logs for the Dynamo -> ES streaming lambda.', - Default: 1, - AllowedValues: [0, 1], - }), - [ResourceConstants.PARAMETERS.ElasticsearchInstanceCount]: new NumberParameter({ - Description: 'The number of instances to launch into the Elasticsearch domain.', - Default: 1, - }), - [ResourceConstants.PARAMETERS.ElasticsearchInstanceType]: new StringParameter({ - Description: 'The type of instance to launch into the Elasticsearch domain.', - Default: 't2.small.elasticsearch', - AllowedValues: [ - 't2.small.elasticsearch', - 't2.medium.elasticsearch', - 'c4.large.elasticsearch', - 'c4.xlarge.elasticsearch', - 'c4.2xlarge.elasticsearch', - 'c4.4xlarge.elasticsearch', - 'c4.8xlarge.elasticsearch', - 'm3.medium.elasticsearch', - 'm3.large.elasticsearch', - 'm3.xlarge.elasticsearch', - 'm3.2xlarge.elasticsearch', - 'm4.large.elasticsearch', - 'm4.xlarge.elasticsearch', - 'm4.2xlarge.elasticsearch', - 'm4.4xlarge.elasticsearch', - 'm4.10xlarge.elasticsearch', - 'r3.large.elasticsearch', - 'r3.xlarge.elasticsearch', - 'r3.2xlarge.elasticsearch', - 'r3.4xlarge.elasticsearch', - 'r3.8xlarge.elasticsearch', - 'r4.large.elasticsearch', - 'r4.xlarge.elasticsearch', - 'r4.2xlarge.elasticsearch', - 'r4.4xlarge.elasticsearch', - 'r4.8xlarge.elasticsearch', - 'r4.16xlarge.elasticsearch', - 'i2.xlarge.elasticsearch', - 'i2.2xlarge.elasticsearch', - 'i3.large.elasticsearch', - 'i3.xlarge.elasticsearch', - 'i3.2xlarge.elasticsearch', - 'i3.4xlarge.elasticsearch', - 'i3.8xlarge.elasticsearch', - 'i3.16xlarge.elasticsearch', - 'r6gd.12xlarge.elasticsearch', - 'ultrawarm1.xlarge.elasticsearch', - 'm5.4xlarge.elasticsearch', - 't3.xlarge.elasticsearch', - 'm6g.xlarge.elasticsearch', - 'm6g.12xlarge.elasticsearch', - 't2.micro.elasticsearch', - 'r6gd.16xlarge.elasticsearch', - 'd2.2xlarge.elasticsearch', - 't3.micro.elasticsearch', - 'm5.large.elasticsearch', - 'd2.4xlarge.elasticsearch', - 't3.small.elasticsearch', - 'c5.2xlarge.elasticsearch', - 'c6g.2xlarge.elasticsearch', - 'd2.8xlarge.elasticsearch', - 'c5.4xlarge.elasticsearch', - 't4g.medium.elasticsearch', - 'c6g.4xlarge.elasticsearch', - 'c6g.xlarge.elasticsearch', - 'c6g.12xlarge.elasticsearch', - 'c5.xlarge.elasticsearch', - 'c5.large.elasticsearch', - 't4g.small.elasticsearch', - 'c5.9xlarge.elasticsearch', - 'c6g.8xlarge.elasticsearch', - 'c6g.large.elasticsearch', - 'd2.xlarge.elasticsearch', - 'ultrawarm1.medium.elasticsearch', - 't3.nano.elasticsearch', - 't3.medium.elasticsearch', - 'm6g.2xlarge.elasticsearch', - 't3.2xlarge.elasticsearch', - 'c5.18xlarge.elasticsearch', - 'm6g.4xlarge.elasticsearch', - 'r6gd.2xlarge.elasticsearch', - 'm5.xlarge.elasticsearch', - 'r6gd.4xlarge.elasticsearch', - 'r6g.2xlarge.elasticsearch', - 'r5.2xlarge.elasticsearch', - 'm5.12xlarge.elasticsearch', - 'm6g.8xlarge.elasticsearch', - 'm6g.large.elasticsearch', - 'm5.24xlarge.elasticsearch', - 'r6g.4xlarge.elasticsearch', - 't3.large.elasticsearch', - 'r5.4xlarge.elasticsearch', - 'ultrawarm1.large.elasticsearch', - 'r6gd.8xlarge.elasticsearch', - 'r6gd.large.elasticsearch', - 'r6g.xlarge.elasticsearch', - 'r5.xlarge.elasticsearch', - 'r6g.12xlarge.elasticsearch', - 'r5.12xlarge.elasticsearch', - 'm5.2xlarge.elasticsearch', - 'r6gd.xlarge.elasticsearch', - 'r6g.8xlarge.elasticsearch', - 'r6g.large.elasticsearch', - 'r5.24xlarge.elasticsearch', - 'r5.large.elasticsearch', - ], - }), - [ResourceConstants.PARAMETERS.ElasticsearchEBSVolumeGB]: new NumberParameter({ - Description: 'The size in GB of the EBS volumes that contain our data.', - Default: 10, - }), - }; - } - - /** - * Creates the barebones template for an application. - */ - public initTemplate(isProjectUsingDataStore = false): Template { - return { - Parameters: this.makeParams(), - Resources: { - [ResourceConstants.RESOURCES.ElasticsearchAccessIAMRoleLogicalID]: this.makeElasticsearchAccessIAMRole(), - [ResourceConstants.RESOURCES.ElasticsearchDataSourceLogicalID]: this.makeElasticsearchDataSource(), - [ResourceConstants.RESOURCES.ElasticsearchDomainLogicalID]: this.makeElasticsearchDomain(), - [ResourceConstants.RESOURCES.ElasticsearchStreamingLambdaIAMRoleLogicalID]: this.makeStreamingLambdaIAMRole(), - [ResourceConstants.RESOURCES.ElasticsearchStreamingLambdaFunctionLogicalID]: - this.makeDynamoDBStreamingFunction(isProjectUsingDataStore), - }, - Mappings: this.getLayerMapping(), - Outputs: { - [ResourceConstants.OUTPUTS.ElasticsearchDomainArn]: this.makeDomainArnOutput(), - [ResourceConstants.OUTPUTS.ElasticsearchDomainEndpoint]: this.makeDomainEndpointOutput(), - }, - }; - } - - /** - * Given the name of a data source and optional logical id return a CF - * spec for a data source pointing to the elasticsearch domain. - * @param name The name for the data source. If a logicalId is not provided the name is used. - * @param logicalId The logicalId of the domain if it is different than the name of the data source. - */ - public makeElasticsearchDataSource() { - const logicalName = ResourceConstants.RESOURCES.ElasticsearchDomainLogicalID; - return new AppSync.DataSource({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - Name: logicalName, - Type: 'AMAZON_ELASTICSEARCH', - ServiceRoleArn: Fn.GetAtt(ResourceConstants.RESOURCES.ElasticsearchAccessIAMRoleLogicalID, 'Arn'), - ElasticsearchConfig: { - AwsRegion: Fn.Select(3, Fn.Split(':', Fn.GetAtt(logicalName, 'DomainArn'))), - Endpoint: Fn.Join('', ['https://', Fn.GetAtt(logicalName, 'DomainEndpoint')]), - }, - }).dependsOn(ResourceConstants.RESOURCES.ElasticsearchDomainLogicalID); - } - - /** - * - */ - public getLayerMapping(): MappingParameters { - return { - LayerResourceMapping: { - 'ap-northeast-1': { - layerRegion: 'arn:aws:lambda:ap-northeast-1:249908578461:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'us-east-1': { - layerRegion: 'arn:aws:lambda:us-east-1:668099181075:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'ap-southeast-1': { - layerRegion: 'arn:aws:lambda:ap-southeast-1:468957933125:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'eu-west-1': { - layerRegion: 'arn:aws:lambda:eu-west-1:399891621064:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'us-west-1': { - layerRegion: 'arn:aws:lambda:us-west-1:325793726646:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'ap-east-1': { - layerRegion: 'arn:aws:lambda:ap-east-1:118857876118:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'ap-northeast-2': { - layerRegion: 'arn:aws:lambda:ap-northeast-2:296580773974:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'ap-northeast-3': { - layerRegion: 'arn:aws:lambda:ap-northeast-3:961244031340:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'ap-south-1': { - layerRegion: 'arn:aws:lambda:ap-south-1:631267018583:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'ap-southeast-2': { - layerRegion: 'arn:aws:lambda:ap-southeast-2:817496625479:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'ca-central-1': { - layerRegion: 'arn:aws:lambda:ca-central-1:778625758767:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'eu-central-1': { - layerRegion: 'arn:aws:lambda:eu-central-1:292169987271:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'eu-north-1': { - layerRegion: 'arn:aws:lambda:eu-north-1:642425348156:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'eu-south-1': { - layerRegion: 'arn:aws:lambda:eu-south-1:426215560912:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'eu-west-2': { - layerRegion: 'arn:aws:lambda:eu-west-2:142628438157:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'eu-west-3': { - layerRegion: 'arn:aws:lambda:eu-west-3:959311844005:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'sa-east-1': { - layerRegion: 'arn:aws:lambda:sa-east-1:640010853179:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'us-east-2': { - layerRegion: 'arn:aws:lambda:us-east-2:259788987135:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'us-west-2': { - layerRegion: 'arn:aws:lambda:us-west-2:420165488524:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'cn-north-1': { - layerRegion: 'arn:aws-cn:lambda:cn-north-1:683298794825:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'cn-northwest-1': { - layerRegion: 'arn:aws-cn:lambda:cn-northwest-1:382066503313:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'us-gov-west-1': { - layerRegion: 'arn:aws-us-gov:lambda:us-gov-west-1:556739011827:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'us-gov-east-1': { - layerRegion: 'arn:aws-us-gov:lambda:us-gov-east-1:138526772879:layer:AWSLambda-Python-AWS-SDK:1', - }, - 'me-south-1': { - layerRegion: 'arn:aws:lambda:me-south-1:507411403535:layer:AWSLambda-Python-AWS-SDK:1', - }, - }, - }; - } - - /** - * Deploy a lambda function that will stream data from our DynamoDB table - * to our elasticsearch index. - */ - public makeDynamoDBStreamingFunction(isProjectUsingDataStore = false) { - return new Lambda.Function({ - Code: { - S3Bucket: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentBucket), - S3Key: Fn.Join('/', [ - Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentRootKey), - 'functions', - Fn.Join('.', [ResourceConstants.RESOURCES.ElasticsearchStreamingLambdaFunctionLogicalID, 'zip']), - ]), - }, - FunctionName: this.joinWithEnv('-', [ - Fn.Ref(ResourceConstants.PARAMETERS.ElasticsearchStreamingFunctionName), - Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - ]), - Handler: Fn.Ref(ResourceConstants.PARAMETERS.ElasticsearchStreamingLambdaHandlerName), - Role: Fn.GetAtt(ResourceConstants.RESOURCES.ElasticsearchStreamingLambdaIAMRoleLogicalID, 'Arn'), - Runtime: Fn.Ref(ResourceConstants.PARAMETERS.ElasticsearchStreamingLambdaRuntime), - Layers: [Fn.FindInMap('LayerResourceMapping', Fn.Ref('AWS::Region'), 'layerRegion')], - Environment: { - Variables: { - ES_ENDPOINT: Fn.Join('', ['https://', Fn.GetAtt(ResourceConstants.RESOURCES.ElasticsearchDomainLogicalID, 'DomainEndpoint')]), - ES_REGION: Fn.Select(3, Fn.Split(':', Fn.GetAtt(ResourceConstants.RESOURCES.ElasticsearchDomainLogicalID, 'DomainArn'))), - DEBUG: Fn.Ref(ResourceConstants.PARAMETERS.ElasticsearchDebugStreamingLambda), - ES_USE_EXTERNAL_VERSIONING: isProjectUsingDataStore.toString(), - }, - }, - }).dependsOn([ - ResourceConstants.RESOURCES.ElasticsearchStreamingLambdaIAMRoleLogicalID, - ResourceConstants.RESOURCES.ElasticsearchDomainLogicalID, - ]); - } - - /** - * - */ - public makeDynamoDBStreamEventSourceMapping(typeName: string) { - return new Lambda.EventSourceMapping({ - BatchSize: 1, - Enabled: true, - EventSourceArn: Fn.GetAtt(ModelResourceIDs.ModelTableResourceID(typeName), 'StreamArn'), - FunctionName: Fn.GetAtt(ResourceConstants.RESOURCES.ElasticsearchStreamingLambdaFunctionLogicalID, 'Arn'), - StartingPosition: 'LATEST', - }).dependsOn([ResourceConstants.RESOURCES.ElasticsearchStreamingLambdaFunctionLogicalID]); - } - - private joinWithEnv(separator: string, listToJoin: any[]) { - return Fn.If( - ResourceConstants.CONDITIONS.HasEnvironmentParameter, - Fn.Join(separator, [...listToJoin, Fn.Ref(ResourceConstants.PARAMETERS.Env)]), - Fn.Join(separator, listToJoin), - ); - } - - /** - * Create a single role that has access to all the resources created by the - * transform. - * @param name The name of the IAM role to create. - */ - public makeElasticsearchAccessIAMRole() { - return new IAM.Role({ - RoleName: this.joinWithEnv('-', [ - Fn.Ref(ResourceConstants.PARAMETERS.ElasticsearchAccessIAMRoleName), - Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - ]), - AssumeRolePolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Principal: { - Service: 'appsync.amazonaws.com', - }, - Action: 'sts:AssumeRole', - }, - ], - }, - Policies: [ - new IAM.Role.Policy({ - PolicyName: 'ElasticsearchAccess', - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Action: ['es:ESHttpPost', 'es:ESHttpDelete', 'es:ESHttpHead', 'es:ESHttpGet', 'es:ESHttpPost', 'es:ESHttpPut'], - Effect: 'Allow', - Resource: Fn.Join('', [this.domainArn(), '/*']), - }, - ], - }, - }), - ], - }); - } - - /** - * Create a single role that has access to all the resources created by the - * transform. - * @param name The name of the IAM role to create. - */ - public makeStreamingLambdaIAMRole() { - return new IAM.Role({ - RoleName: this.joinWithEnv('-', [ - Fn.Ref(ResourceConstants.PARAMETERS.ElasticsearchStreamingIAMRoleName), - Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - ]), - AssumeRolePolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Principal: { - Service: 'lambda.amazonaws.com', - }, - Action: 'sts:AssumeRole', - }, - ], - }, - Policies: [ - new IAM.Role.Policy({ - PolicyName: 'ElasticsearchAccess', - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Action: ['es:ESHttpPost', 'es:ESHttpDelete', 'es:ESHttpHead', 'es:ESHttpGet', 'es:ESHttpPost', 'es:ESHttpPut'], - Effect: 'Allow', - Resource: Fn.Join('', [this.domainArn(), '/*']), - }, - ], - }, - }), - new IAM.Role.Policy({ - PolicyName: 'DynamoDBStreamAccess', - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Action: ['dynamodb:DescribeStream', 'dynamodb:GetRecords', 'dynamodb:GetShardIterator', 'dynamodb:ListStreams'], - Effect: 'Allow', - Resource: [ - '*', - // TODO: Scope this to each table individually. - // Fn.Join( - // '/', - // [Fn.GetAtt(ResourceConstants.RESOURCES.DynamoDBModelTableLogicalID, 'Arn'), '*'] - // ) - ], - }, - ], - }, - }), - new IAM.Role.Policy({ - PolicyName: 'CloudWatchLogsAccess', - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Action: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'], - Resource: 'arn:aws:logs:*:*:*', - }, - ], - }, - }), - ], - }); - // .dependsOn(ResourceConstants.RESOURCES.DynamoDBModelTableLogicalID) - } - - /** - * If there is an env, allow ES to create the domain name so we don't go - * over 28 characters. If there is no env, fallback to original behavior. - */ - private domainName() { - return Fn.If( - ResourceConstants.CONDITIONS.HasEnvironmentParameter, - Refs.NoValue, - Fn.Join('-', ['d', Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId')]), - ); - } - - private domainArn() { - return Fn.GetAtt(ResourceConstants.RESOURCES.ElasticsearchDomainLogicalID, 'DomainArn'); - } - - /** - * Create the elasticsearch domain. - */ - public makeElasticsearchDomain() { - return new Elasticsearch.Domain({ - DomainName: this.domainName(), - ElasticsearchVersion: '6.2', - ElasticsearchClusterConfig: { - ZoneAwarenessEnabled: false, - InstanceCount: Fn.Ref(ResourceConstants.PARAMETERS.ElasticsearchInstanceCount), - InstanceType: Fn.Ref(ResourceConstants.PARAMETERS.ElasticsearchInstanceType), - }, - EBSOptions: { - EBSEnabled: true, - VolumeType: 'gp2', - VolumeSize: Fn.Ref(ResourceConstants.PARAMETERS.ElasticsearchEBSVolumeGB), - }, - }); - } - - /** - * Create the Elasticsearch search resolver. - */ - public makeSearchResolver( - type: string, - nonKeywordFields: Expression[], - primaryKey: string, - queryTypeName: string, - improvePluralization: boolean, - nameOverride?: string, - includeVersion = false, - ) { - const fieldName = nameOverride || graphqlName(`search${plurality(toUpper(type), improvePluralization)}`); - return new AppSync.Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(ResourceConstants.RESOURCES.ElasticsearchDataSourceLogicalID, 'Name'), - FieldName: fieldName, - TypeName: queryTypeName, - RequestMappingTemplate: print( - compoundExpression([ - set(ref('indexPath'), str(`/${type.toLowerCase()}/doc/_search`)), - set(ref('nonKeywordFields'), list(nonKeywordFields)), - ifElse( - ref('util.isNullOrEmpty($context.args.sort)'), - compoundExpression([set(ref('sortDirection'), str('desc')), set(ref('sortField'), str(primaryKey))]), - compoundExpression([ - set(ref('sortDirection'), ref('util.defaultIfNull($context.args.sort.direction, "desc")')), - set(ref('sortField'), ref(`util.defaultIfNull($context.args.sort.field, "${primaryKey}")`)), - ]), - ), - ifElse( - ref('nonKeywordFields.contains($sortField)'), - compoundExpression([set(ref('sortField0'), ref('util.toJson($sortField)'))]), - compoundExpression([set(ref('sortField0'), ref('util.toJson("${sortField}.keyword")'))]), - ), - ElasticsearchMappingTemplate.searchItem({ - path: str('$indexPath'), - size: ifElse(ref('context.args.limit'), ref('context.args.limit'), int(ResourceConstants.DEFAULT_SEARCHABLE_PAGE_LIMIT), true), - search_after: list([ref('util.toJson($context.args.nextToken)')]), - from: ref('context.args.from'), - version: bool(includeVersion), - query: ifElse( - ref('context.args.filter'), - ref('util.transform.toElasticsearchQueryDSL($ctx.args.filter)'), - obj({ - match_all: obj({}), - }), - ), - sort: list([raw('{$sortField0: { "order" : $util.toJson($sortDirection) }}')]), - }), - ]), - ), - ResponseMappingTemplate: print( - compoundExpression([ - set(ref('es_items'), list([])), - forEach(ref('entry'), ref('context.result.hits.hits'), [ - iff(raw('!$foreach.hasNext'), set(ref('nextToken'), ref('entry.sort.get(0)'))), - ...this.getSourceMapper(includeVersion), - ]), - toJson( - obj({ - items: ref('es_items'), - total: ref('ctx.result.hits.total'), - nextToken: ref('nextToken'), - }), - ), - ]), - ), - }).dependsOn([ResourceConstants.RESOURCES.ElasticsearchDataSourceLogicalID]); - } - - private getSourceMapper = (includeVersion: boolean) => { - if (includeVersion) { - return [ - set(ref('row'), methodCall(ref('entry.get'), str('_source'))), - qref('$row.put("_version", $entry.get("_version"))'), - qref('$es_items.add($row)'), - ]; - } - return [qref('$es_items.add($entry.get("_source"))')]; - }; - - /** - * OUTPUTS - */ - /** - * Create output to export the Elasticsearch DomainArn - * @returns Output - */ - public makeDomainArnOutput(): Output { - return { - Description: 'Elasticsearch instance Domain ARN.', - Value: Fn.GetAtt(ResourceConstants.RESOURCES.ElasticsearchDomainLogicalID, 'DomainArn'), - Export: { - Name: Fn.Join(':', [Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), 'GetAtt', 'Elasticsearch', 'DomainArn']), - }, - }; - } - - /** - * Create output to export the Elasticsearch DomainEndpoint - * @returns Output - */ - public makeDomainEndpointOutput(): Output { - return { - Description: 'Elasticsearch instance Domain Endpoint.', - Value: Fn.Join('', ['https://', Fn.GetAtt(ResourceConstants.RESOURCES.ElasticsearchDomainLogicalID, 'DomainEndpoint')]), - Export: { - Name: Fn.Join(':', [Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), 'GetAtt', 'Elasticsearch', 'DomainEndpoint']), - }, - }; - } -} diff --git a/packages/graphql-elasticsearch-transformer/streaming-lambda/python_streaming_function.py b/packages/graphql-elasticsearch-transformer/streaming-lambda/python_streaming_function.py deleted file mode 100644 index c365d31236..0000000000 --- a/packages/graphql-elasticsearch-transformer/streaming-lambda/python_streaming_function.py +++ /dev/null @@ -1,263 +0,0 @@ -import base64 -import datetime -import json -import logging -import os -import time -import traceback -from urllib.parse import urlparse, quote - -from botocore.auth import SigV4Auth -from botocore.awsrequest import AWSRequest -from botocore.credentials import get_credentials -from botocore.endpoint import BotocoreHTTPSession -from botocore.session import Session -from boto3.dynamodb.types import TypeDeserializer - - -# The following parameters are required to configure the ES cluster -ES_ENDPOINT = os.environ['ES_ENDPOINT'] -ES_REGION = os.environ['ES_REGION'] -DEBUG = True if os.environ['DEBUG'] == "1" else False -ES_USE_EXTERNAL_VERSIONING = True if os.environ['ES_USE_EXTERNAL_VERSIONING'] == "true" else False - -# ElasticSearch 6 deprecated having multiple mapping types in an index. Default to doc. -DOC_TYPE = 'doc' -ES_MAX_RETRIES = 3 # Max number of retries for exponential backoff - -logger = logging.getLogger() -logger.setLevel(logging.DEBUG if DEBUG else logging.INFO) -logger.info("Streaming to ElasticSearch") - -# custom encoder changes -# - sets to lists -class DDBTypesEncoder(json.JSONEncoder): - def default(self, obj): - if isinstance(obj, set): - return list(obj) - return json.JSONEncoder.default(self, obj) - -# Subclass of boto's TypeDeserializer for DynamoDB to adjust for DynamoDB Stream format. -class StreamTypeDeserializer(TypeDeserializer): - def _deserialize_n(self, value): - val = float(value) - if (val.is_integer()): - return int(value) - else: - return val - - def _deserialize_b(self, value): - return value # Already in Base64 - - -class ES_Exception(Exception): - '''Capture status_code from request''' - status_code = 0 - payload = '' - - def __init__(self, status_code, payload): - self.status_code = status_code - self.payload = payload - Exception.__init__( - self, 'ES_Exception: status_code={}, payload={}'.format(status_code, payload)) - - -# Low-level POST data to Amazon Elasticsearch Service generating a Sigv4 signed request -def post_data_to_es(payload, region, creds, host, path, method='POST', proto='https://'): - '''Post data to ES endpoint with SigV4 signed http headers''' - req = AWSRequest(method=method, url=proto + host + - quote(path), data=payload, headers={'Host': host, 'Content-Type': 'application/json'}) - SigV4Auth(creds, 'es', region).add_auth(req) - http_session = BotocoreHTTPSession() - res = http_session.send(req.prepare()) - if res.status_code >= 200 and res.status_code <= 299: - return res._content - else: - raise ES_Exception(res.status_code, res._content) - - -# High-level POST data to Amazon Elasticsearch Service with exponential backoff -# according to suggested algorithm: http://docs.aws.amazon.com/general/latest/gr/api-retries.html -def post_to_es(payload): - '''Post data to ES cluster with exponential backoff''' - - # Get aws_region and credentials to post signed URL to ES - es_region = ES_REGION or os.environ['AWS_REGION'] - session = Session({'region': es_region}) - creds = get_credentials(session) - es_url = urlparse(ES_ENDPOINT) - # Extract the domain name in ES_ENDPOINT - es_endpoint = es_url.netloc or es_url.path - - # Post data with exponential backoff - retries = 0 - while retries < ES_MAX_RETRIES: - if retries > 0: - seconds = (2 ** retries) * .1 - logger.debug('Waiting for %.1f seconds', seconds) - time.sleep(seconds) - - try: - es_ret_str = post_data_to_es( - payload, es_region, creds, es_endpoint, '/_bulk') - logger.debug('Return from ES: %s', es_ret_str) - es_ret = json.loads(es_ret_str) - - if es_ret['errors']: - logger.error( - 'ES post unsuccessful, errors present, took=%sms', es_ret['took']) - # Filter errors - es_errors = [item for item in es_ret['items'] - if item.get('index', {}).get('error')] - logger.error('List of items with errors: %s', - json.dumps(es_errors)) - else: - logger.info('ES post successful, took=%sms', es_ret['took']) - break # Sending to ES was ok, break retry loop - except ES_Exception as e: - if (e.status_code >= 500) and (e.status_code <= 599): - retries += 1 # Candidate for retry - else: - raise # Stop retrying, re-raise exception - - -# Extracts the DynamoDB table from an ARN -# ex: arn:aws:dynamodb:eu-west-1:123456789012:table/table-name/stream/2015-11-13T09:23:17.104 should return 'table-name' -def get_table_name_from_arn(arn): - return arn.split(':')[5].split('/')[1] - - -# Compute a compound doc index from the key(s) of the object in lexicographic order: "k1=key_val1|k2=key_val2" -def compute_doc_index(keys_raw, deserializer, formatIndex=False): - index = [] - for key in sorted(keys_raw): - if formatIndex: - index.append('{}={}'.format( - key, deserializer.deserialize(keys_raw[key]))) - else: - index.append(deserializer.deserialize(keys_raw[key])) - return '|'.join(map(str,index)) - -def _lambda_handler(event, context): - logger.debug('Event: %s', event) - records = event['Records'] - now = datetime.datetime.utcnow() - - ddb_deserializer = StreamTypeDeserializer() - es_actions = [] # Items to be added/updated/removed from ES - for bulk API - cnt_insert = cnt_modify = cnt_remove = 0 - - for record in records: - # Handle both native DynamoDB Streams or Streams data from Kinesis (for manual replay) - logger.debug('Record: %s', record) - if record.get('eventSource') == 'aws:dynamodb': - ddb = record['dynamodb'] - ddb_table_name = get_table_name_from_arn(record['eventSourceARN']) - doc_seq = ddb['SequenceNumber'] - elif record.get('eventSource') == 'aws:kinesis': - ddb = json.loads(base64.b64decode(record['kinesis']['data'])) - ddb_table_name = ddb['SourceTable'] - doc_seq = record['kinesis']['sequenceNumber'] - else: - logger.error('Ignoring non-DynamoDB event sources: %s', - record.get('eventSource')) - continue - - # Compute DynamoDB table, type and index for item - doc_table = ddb_table_name.lower() - doc_type = DOC_TYPE - doc_table_parts = doc_table.split('-') - doc_es_index_name = doc_table_parts[0] if len(doc_table_parts) > 0 else doc_table - - # Dispatch according to event TYPE - event_name = record['eventName'].upper() # INSERT, MODIFY, REMOVE - logger.debug('doc_table=%s, event_name=%s, seq=%s', - doc_table, event_name, doc_seq) - - # Treat events from a Kinesis stream as INSERTs - if event_name == 'AWS:KINESIS:RECORD': - event_name = 'INSERT' - - is_ddb_insert_or_update = (event_name == 'INSERT') or (event_name == 'MODIFY') - is_ddb_delete = event_name == 'REMOVE' - image_name = 'NewImage' if is_ddb_insert_or_update else 'OldImage' - - if image_name not in ddb: - logger.warning( - 'Cannot process stream if it does not contain ' + image_name) - continue - logger.debug(image_name + ': %s', ddb[image_name]) - # Deserialize DynamoDB type to Python types - doc_fields = ddb_deserializer.deserialize({'M': ddb[image_name]}) - - # Sync enabled APIs do soft delete. We need to delete the record in ES if _deleted field is set - if ES_USE_EXTERNAL_VERSIONING and event_name == 'MODIFY' and '_deleted' in doc_fields and doc_fields['_deleted']: - is_ddb_insert_or_update = False - is_ddb_delete = True - - # Update counters - if event_name == 'INSERT': - cnt_insert += 1 - elif event_name == 'MODIFY': - cnt_modify += 1 - elif event_name == 'REMOVE': - cnt_remove += 1 - else: - logger.warning('Unsupported event_name: %s', event_name) - - logger.debug('Deserialized doc_fields: %s', doc_fields) - - if ('Keys' in ddb): - doc_id = compute_doc_index(ddb['Keys'], ddb_deserializer) - else: - logger.error('Cannot find keys in ddb record') - - # If DynamoDB INSERT or MODIFY, send 'index' to ES - if is_ddb_insert_or_update: - # Generate ES payload for item - action = {'index': {'_index': doc_es_index_name, - '_type': doc_type, - '_id': doc_id}} - # Add external versioning if necessary - if ES_USE_EXTERNAL_VERSIONING and '_version' in doc_fields: - action['index'].update([ - ('version_type', 'external'), - ('_version', doc_fields['_version']) - ]) - doc_fields.pop('_ttl', None) - doc_fields.pop('_version', None) - # Append ES Action line with 'index' directive - es_actions.append(json.dumps(action)) - # Append JSON payload - es_actions.append(json.dumps(doc_fields, cls=DDBTypesEncoder)) - # migration step remove old key if it exists - if ('id' in doc_fields) and (event_name == 'MODIFY') : - action = {'delete': {'_index': doc_es_index_name, '_type': doc_type, - '_id': compute_doc_index(ddb['Keys'], ddb_deserializer, True)}} - es_actions.append(json.dumps(action)) - # If DynamoDB REMOVE, send 'delete' to ES - elif is_ddb_delete: - action = {'delete': {'_index': doc_es_index_name, - '_type': doc_type, '_id': doc_id}} - if ES_USE_EXTERNAL_VERSIONING and '_version' in doc_fields: - action['delete'].update([ - ('version_type', 'external'), - ('_version', doc_fields['_version']) - ]) - # Action line with 'delete' directive - es_actions.append(json.dumps(action)) - - # Prepare bulk payload - es_actions.append('') # Add one empty line to force final \n - es_payload = '\n'.join(es_actions) - logger.info('Posting to ES: inserts=%s updates=%s deletes=%s, total_lines=%s, bytes_total=%s', - cnt_insert, cnt_modify, cnt_remove, len(es_actions) - 1, len(es_payload)) - post_to_es(es_payload) # Post to ES with exponential backoff - - -# Global lambda handler - catches all exceptions to avoid dead letter in the DynamoDB Stream -def lambda_handler(event, context): - try: - return _lambda_handler(event, context) - except Exception: - logger.error(traceback.format_exc()) diff --git a/packages/graphql-elasticsearch-transformer/tsconfig.json b/packages/graphql-elasticsearch-transformer/tsconfig.json deleted file mode 100644 index 1814a1ef9f..0000000000 --- a/packages/graphql-elasticsearch-transformer/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "strict": false, // TODO enable - "rootDir": "src", - "outDir": "lib" - }, - "references": [ - { "path": "../amplify-graphql-directives" }, - { "path": "../graphql-dynamodb-transformer" }, - { "path": "../graphql-mapping-template" }, - { "path": "../graphql-transformer-common" }, - { "path": "../graphql-transformer-core" } - ] -} diff --git a/packages/graphql-function-transformer/.npmignore b/packages/graphql-function-transformer/.npmignore deleted file mode 100644 index 3ee5d55b0b..0000000000 --- a/packages/graphql-function-transformer/.npmignore +++ /dev/null @@ -1,5 +0,0 @@ -**/__mocks__/** -**/__tests__/** -src -tsconfig.json -tsconfig.tsbuildinfo diff --git a/packages/graphql-function-transformer/API.md b/packages/graphql-function-transformer/API.md deleted file mode 100644 index 474afa2e90..0000000000 --- a/packages/graphql-function-transformer/API.md +++ /dev/null @@ -1,32 +0,0 @@ -## API Report File for "graphql-function-transformer" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { DirectiveNode } from 'graphql'; -import { FieldDefinitionNode } from 'graphql'; -import { ObjectTypeDefinitionNode } from 'graphql'; -import { Transformer as Transformer_2 } from 'graphql-transformer-core'; -import { TransformerContext } from 'graphql-transformer-core'; - -// @public (undocumented) -export class FunctionTransformer extends Transformer_2 { - constructor(); - // (undocumented) - appendFunctionToResolver(resolver: any, functionId: string): any; - // (undocumented) - datasource: (name: string, region: string) => any; - // (undocumented) - field: (parent: ObjectTypeDefinitionNode, definition: FieldDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => void; - // (undocumented) - function: (name: string, region: string) => any; - // (undocumented) - resolver: (type: string, field: string, name: string, region?: string) => any; - // (undocumented) - role: (name: string, region: string) => any; -} - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/graphql-function-transformer/CHANGELOG.md b/packages/graphql-function-transformer/CHANGELOG.md deleted file mode 100644 index 0706f42a27..0000000000 --- a/packages/graphql-function-transformer/CHANGELOG.md +++ /dev/null @@ -1,741 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [3.3.71](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.70...graphql-function-transformer@3.3.71) (2024-07-15) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.70](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.69...graphql-function-transformer@3.3.70) (2024-07-02) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.69](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.68...graphql-function-transformer@3.3.69) (2024-06-25) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.68](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.67...graphql-function-transformer@3.3.68) (2024-04-26) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.67](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.66...graphql-function-transformer@3.3.67) (2024-04-11) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.66](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.65...graphql-function-transformer@3.3.66) (2024-03-28) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.65](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.64...graphql-function-transformer@3.3.65) (2024-02-28) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.64](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.63...graphql-function-transformer@3.3.64) (2024-02-05) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.63](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.62...graphql-function-transformer@3.3.63) (2024-01-22) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.62](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.61...graphql-function-transformer@3.3.62) (2023-12-18) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.61](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.60...graphql-function-transformer@3.3.61) (2023-12-06) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.60](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.59...graphql-function-transformer@3.3.60) (2023-11-18) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.59](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.58...graphql-function-transformer@3.3.59) (2023-11-16) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.58](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.57...graphql-function-transformer@3.3.58) (2023-11-15) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.57](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.56...graphql-function-transformer@3.3.57) (2023-10-21) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.56](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.55...graphql-function-transformer@3.3.56) (2023-08-30) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.55](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.54...graphql-function-transformer@3.3.55) (2023-08-28) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.54](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.53...graphql-function-transformer@3.3.54) (2023-08-09) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.53](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.52...graphql-function-transformer@3.3.53) (2023-07-21) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.52](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.51...graphql-function-transformer@3.3.52) (2023-07-17) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.51](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.50...graphql-function-transformer@3.3.51) (2023-07-07) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.50](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.49...graphql-function-transformer@3.3.50) (2023-07-07) - -### Bug Fixes - -- trigger republish of dependencies that failed in https://app.circleci.com/pipelines/github/aws-amplify/amplify-category-api/7981/workflows/e7366f04-6f0a-4ee4-9cc2-1772089e8005/jobs/163571 ([f2c7151](https://github.com/aws-amplify/amplify-category-api/commit/f2c7151005e4a9fd29d91ac1af1f3e482a06a5cc)) - -## [3.3.49](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.48...graphql-function-transformer@3.3.49) (2023-07-07) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.48](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.47...graphql-function-transformer@3.3.48) (2023-06-29) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.47](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.46...graphql-function-transformer@3.3.47) (2023-06-20) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.46](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.45...graphql-function-transformer@3.3.46) (2023-06-05) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.45](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.44...graphql-function-transformer@3.3.45) (2023-05-23) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.44](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.43...graphql-function-transformer@3.3.44) (2023-05-17) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.43](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.42...graphql-function-transformer@3.3.43) (2023-04-25) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.42](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.41...graphql-function-transformer@3.3.42) (2023-03-30) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.41](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.40...graphql-function-transformer@3.3.41) (2023-03-15) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.40](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.39...graphql-function-transformer@3.3.40) (2023-03-01) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.39](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.38...graphql-function-transformer@3.3.39) (2023-02-27) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.38](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.37...graphql-function-transformer@3.3.38) (2023-01-26) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.37](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.36...graphql-function-transformer@3.3.37) (2023-01-12) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.36](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.35...graphql-function-transformer@3.3.36) (2023-01-12) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.35](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.34...graphql-function-transformer@3.3.35) (2022-12-03) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.34](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.33...graphql-function-transformer@3.3.34) (2022-09-14) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.33](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.31...graphql-function-transformer@3.3.33) (2022-07-20) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.32](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.31...graphql-function-transformer@3.3.32) (2022-07-14) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.31](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.30...graphql-function-transformer@3.3.31) (2022-07-01) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.30](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.29...graphql-function-transformer@3.3.30) (2022-06-23) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.29](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.28...graphql-function-transformer@3.3.29) (2022-06-13) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.28](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.27...graphql-function-transformer@3.3.28) (2022-06-10) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.27](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.26...graphql-function-transformer@3.3.27) (2022-06-10) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.26](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.23...graphql-function-transformer@3.3.26) (2022-06-07) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.25](https://github.com/aws-amplify/amplify-category-api/compare/graphql-function-transformer@3.3.23...graphql-function-transformer@3.3.25) (2022-05-31) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.23...graphql-function-transformer@3.3.24) (2022-05-02) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.22...graphql-function-transformer@3.3.23) (2022-04-29) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.21...graphql-function-transformer@3.3.22) (2022-04-27) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.21](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.20...graphql-function-transformer@3.3.21) (2022-04-11) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.20](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.19...graphql-function-transformer@3.3.20) (2022-04-07) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.19](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.18...graphql-function-transformer@3.3.19) (2022-03-23) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.17...graphql-function-transformer@3.3.18) (2022-03-17) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.16...graphql-function-transformer@3.3.17) (2022-03-14) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.15...graphql-function-transformer@3.3.16) (2022-03-07) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.14...graphql-function-transformer@3.3.15) (2022-02-25) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.13...graphql-function-transformer@3.3.14) (2022-02-15) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.9...graphql-function-transformer@3.3.13) (2022-02-10) - -## 7.6.19 (2022-02-08) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.8...graphql-function-transformer@3.3.9) (2022-02-03) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.7...graphql-function-transformer@3.3.8) (2022-01-31) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.6...graphql-function-transformer@3.3.7) (2022-01-27) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.5...graphql-function-transformer@3.3.6) (2022-01-23) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.4...graphql-function-transformer@3.3.5) (2022-01-13) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.2...graphql-function-transformer@3.3.4) (2022-01-10) - -## 7.6.7 (2022-01-10) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.1...graphql-function-transformer@3.3.2) (2021-12-21) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.3.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.3.0...graphql-function-transformer@3.3.1) (2021-12-17) - -**Note:** Version bump only for package graphql-function-transformer - -# [3.3.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.2.8...graphql-function-transformer@3.3.0) (2021-12-03) - -### Features - -- provide helpful error message when GQL schema validation fails ([#9159](https://github.com/aws-amplify/amplify-cli/issues/9159)) ([308706c](https://github.com/aws-amplify/amplify-cli/commit/308706c8a67712d7625f11a625e258101790d4c7)) - -## [3.2.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.2.7...graphql-function-transformer@3.2.8) (2021-12-02) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.2.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.2.6...graphql-function-transformer@3.2.7) (2021-12-01) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.2.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.2.5...graphql-function-transformer@3.2.6) (2021-11-26) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.2.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.2.4...graphql-function-transformer@3.2.5) (2021-11-23) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.2.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.2.3...graphql-function-transformer@3.2.4) (2021-11-21) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.2.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.2.2...graphql-function-transformer@3.2.3) (2021-11-20) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.2.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@3.2.1...graphql-function-transformer@3.2.2) (2021-11-17) - -**Note:** Version bump only for package graphql-function-transformer - -## [3.2.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.25...graphql-function-transformer@3.2.1) (2021-11-15) - -**Note:** Version bump only for package graphql-function-transformer - -# [3.0.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.25...graphql-function-transformer@3.0.0) (2021-11-13) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.24...graphql-function-transformer@2.5.25) (2021-11-11) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.23...graphql-function-transformer@2.5.24) (2021-10-10) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.22...graphql-function-transformer@2.5.23) (2021-10-06) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.21...graphql-function-transformer@2.5.22) (2021-09-27) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.21](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.20...graphql-function-transformer@2.5.21) (2021-09-18) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.20](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.19...graphql-function-transformer@2.5.20) (2021-09-14) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.19](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.18...graphql-function-transformer@2.5.19) (2021-09-09) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.17...graphql-function-transformer@2.5.18) (2021-09-02) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.16...graphql-function-transformer@2.5.17) (2021-08-24) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.15...graphql-function-transformer@2.5.16) (2021-08-06) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.14...graphql-function-transformer@2.5.15) (2021-07-30) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.13...graphql-function-transformer@2.5.14) (2021-07-27) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.12...graphql-function-transformer@2.5.13) (2021-07-16) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.11...graphql-function-transformer@2.5.12) (2021-06-30) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.10...graphql-function-transformer@2.5.11) (2021-06-24) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.9...graphql-function-transformer@2.5.10) (2021-06-15) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.8...graphql-function-transformer@2.5.9) (2021-05-26) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.7...graphql-function-transformer@2.5.8) (2021-05-18) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.6...graphql-function-transformer@2.5.7) (2021-05-14) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.4...graphql-function-transformer@2.5.6) (2021-05-03) - -## 4.50.1 (2021-05-03) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.4...graphql-function-transformer@2.5.5) (2021-05-03) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.3...graphql-function-transformer@2.5.4) (2021-04-27) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.2...graphql-function-transformer@2.5.3) (2021-04-19) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.5.1...graphql-function-transformer@2.5.2) (2021-04-14) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.5.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.4.12...graphql-function-transformer@2.5.1) (2021-04-09) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.4.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.4.11...graphql-function-transformer@2.4.12) (2021-03-23) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.4.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.4.10...graphql-function-transformer@2.4.11) (2021-03-11) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.4.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.4.9...graphql-function-transformer@2.4.10) (2021-03-05) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.4.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.4.8...graphql-function-transformer@2.4.9) (2021-02-26) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.4.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.4.7...graphql-function-transformer@2.4.8) (2021-02-24) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.4.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.4.6...graphql-function-transformer@2.4.7) (2021-02-17) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.4.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.4.5...graphql-function-transformer@2.4.6) (2021-02-11) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.4.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.4.4...graphql-function-transformer@2.4.5) (2021-02-10) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.4.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.4.3...graphql-function-transformer@2.4.4) (2020-12-16) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.4.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.4.2...graphql-function-transformer@2.4.3) (2020-12-07) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.4.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.4.1...graphql-function-transformer@2.4.2) (2020-11-30) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.4.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.24...graphql-function-transformer@2.4.1) (2020-11-22) - -**Note:** Version bump only for package graphql-function-transformer - -# [2.4.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.1.5...graphql-function-transformer@2.4.0) (2020-11-22) - -### Bug Fixes - -- **graphql-function-transformer:** add hash to function iam role name ([#3030](https://github.com/aws-amplify/amplify-cli/issues/3030)) ([e3c4a32](https://github.com/aws-amplify/amplify-cli/commit/e3c4a32135f3df6ffb06308d5250433aaf2c1ce9)), closes [#2468](https://github.com/aws-amplify/amplify-cli/issues/2468) -- build break, chore: typescript, lerna update ([#2640](https://github.com/aws-amplify/amplify-cli/issues/2640)) ([29fae36](https://github.com/aws-amplify/amplify-cli/commit/29fae366f4cab054feefa58c7dc733002d19570c)) -- export Typescript definitions and fix resulting type errors ([#2452](https://github.com/aws-amplify/amplify-cli/issues/2452)) ([7de3845](https://github.com/aws-amplify/amplify-cli/commit/7de384594d3b9cbf22cdaa85107fc8df26c141ec)), closes [#2451](https://github.com/aws-amplify/amplify-cli/issues/2451) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c1927da10f8c54f38a523021187361131c)) -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e5346ee1f27a2e9bee25fbbdcb19417f5230f)) - -## [2.3.27](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.24...graphql-function-transformer@2.3.27) (2020-11-20) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.26](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.24...graphql-function-transformer@2.3.26) (2020-11-20) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.24...graphql-function-transformer@2.3.25) (2020-11-19) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.23...graphql-function-transformer@2.3.24) (2020-11-08) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.22...graphql-function-transformer@2.3.23) (2020-10-30) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.21...graphql-function-transformer@2.3.22) (2020-10-22) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.21](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.20...graphql-function-transformer@2.3.21) (2020-10-17) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.20](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.19...graphql-function-transformer@2.3.20) (2020-10-01) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.19](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.18...graphql-function-transformer@2.3.19) (2020-09-16) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.17...graphql-function-transformer@2.3.18) (2020-08-31) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.16...graphql-function-transformer@2.3.17) (2020-08-14) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.15...graphql-function-transformer@2.3.16) (2020-08-11) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.13...graphql-function-transformer@2.3.15) (2020-07-29) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.13...graphql-function-transformer@2.3.14) (2020-07-23) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.12...graphql-function-transformer@2.3.13) (2020-07-18) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.11...graphql-function-transformer@2.3.12) (2020-07-15) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.10...graphql-function-transformer@2.3.11) (2020-06-25) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.9...graphql-function-transformer@2.3.10) (2020-06-18) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.8...graphql-function-transformer@2.3.9) (2020-06-11) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.7...graphql-function-transformer@2.3.8) (2020-06-10) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.6...graphql-function-transformer@2.3.7) (2020-06-02) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.5...graphql-function-transformer@2.3.6) (2020-05-26) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.4...graphql-function-transformer@2.3.5) (2020-05-15) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.3...graphql-function-transformer@2.3.4) (2020-05-08) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.2...graphql-function-transformer@2.3.3) (2020-04-23) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.3.1...graphql-function-transformer@2.3.2) (2020-03-22) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.3.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.1.11...graphql-function-transformer@2.3.1) (2020-03-07) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.2.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.1.13-beta.0...graphql-function-transformer@2.2.1) (2020-03-05) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.1.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.1.10...graphql-function-transformer@2.1.11) (2020-02-13) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.1.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.1.9...graphql-function-transformer@2.1.10) (2020-02-07) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.1.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@2.1.8...graphql-function-transformer@2.1.9) (2020-01-24) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.1.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.25.0...graphql-function-transformer@2.1.8) (2020-01-23) - -### Bug Fixes - -- **graphql-function-transformer:** add hash to function iam role name ([#3030](https://github.com/aws-amplify/amplify-cli/issues/3030)) ([e3c4a32](https://github.com/aws-amplify/amplify-cli/commit/e3c4a32135f3df6ffb06308d5250433aaf2c1ce9)), closes [#2468](https://github.com/aws-amplify/amplify-cli/issues/2468) - -## [2.1.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.25.0...graphql-function-transformer@2.1.7) (2020-01-09) - -### Bug Fixes - -- **graphql-function-transformer:** add hash to function iam role name ([#3030](https://github.com/aws-amplify/amplify-cli/issues/3030)) ([e3c4a32](https://github.com/aws-amplify/amplify-cli/commit/e3c4a32135f3df6ffb06308d5250433aaf2c1ce9)), closes [#2468](https://github.com/aws-amplify/amplify-cli/issues/2468) - -## [2.1.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.25.0...graphql-function-transformer@2.1.6) (2019-12-31) - -### Bug Fixes - -- **graphql-function-transformer:** add hash to function iam role name ([#3030](https://github.com/aws-amplify/amplify-cli/issues/3030)) ([e3c4a32](https://github.com/aws-amplify/amplify-cli/commit/e3c4a32135f3df6ffb06308d5250433aaf2c1ce9)), closes [#2468](https://github.com/aws-amplify/amplify-cli/issues/2468) - -## [2.1.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.25.0...graphql-function-transformer@2.1.5) (2019-12-28) - -### Bug Fixes - -- **graphql-function-transformer:** add hash to function iam role name ([#3030](https://github.com/aws-amplify/amplify-cli/issues/3030)) ([e3c4a32](https://github.com/aws-amplify/amplify-cli/commit/e3c4a32135f3df6ffb06308d5250433aaf2c1ce9)), closes [#2468](https://github.com/aws-amplify/amplify-cli/issues/2468) - -## [2.1.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.25.0...graphql-function-transformer@2.1.4) (2019-12-26) - -### Bug Fixes - -- **graphql-function-transformer:** add hash to function iam role name ([#3030](https://github.com/aws-amplify/amplify-cli/issues/3030)) ([e3c4a32](https://github.com/aws-amplify/amplify-cli/commit/e3c4a32135f3df6ffb06308d5250433aaf2c1ce9)), closes [#2468](https://github.com/aws-amplify/amplify-cli/issues/2468) - -## [2.1.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.25.0...graphql-function-transformer@2.1.3) (2019-12-25) - -### Bug Fixes - -- **graphql-function-transformer:** add hash to function iam role name ([#3030](https://github.com/aws-amplify/amplify-cli/issues/3030)) ([e3c4a32](https://github.com/aws-amplify/amplify-cli/commit/e3c4a32135f3df6ffb06308d5250433aaf2c1ce9)), closes [#2468](https://github.com/aws-amplify/amplify-cli/issues/2468) - -## [2.1.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.25.0...graphql-function-transformer@2.1.2) (2019-12-20) - -### Bug Fixes - -- **graphql-function-transformer:** add hash to function iam role name ([#3030](https://github.com/aws-amplify/amplify-cli/issues/3030)) ([e3c4a32](https://github.com/aws-amplify/amplify-cli/commit/e3c4a32135f3df6ffb06308d5250433aaf2c1ce9)), closes [#2468](https://github.com/aws-amplify/amplify-cli/issues/2468) - -## [2.1.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.25.0...graphql-function-transformer@2.1.1) (2019-12-10) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.0.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.25.0...graphql-function-transformer@2.0.5) (2019-12-03) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.0.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.25.0...graphql-function-transformer@2.0.4) (2019-12-01) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.0.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.25.0...graphql-function-transformer@2.0.3) (2019-11-27) - -**Note:** Version bump only for package graphql-function-transformer - -## [2.0.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.25.0...graphql-function-transformer@2.0.1) (2019-11-27) - -**Note:** Version bump only for package graphql-function-transformer - -# [1.7.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.1.5...graphql-function-transformer@1.7.0) (2019-08-30) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e534)) - -# [1.6.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.1.5...graphql-function-transformer@1.6.0) (2019-08-28) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e534)) - -# [1.5.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.1.5...graphql-function-transformer@1.5.0) (2019-08-13) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e534)) - -# [1.4.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.1.5...graphql-function-transformer@1.4.0) (2019-08-07) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e534)) - -# [1.3.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.1.5...graphql-function-transformer@1.3.0) (2019-08-02) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [1.2.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.1.5...graphql-function-transformer@1.2.0) (2019-07-31) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -## [1.1.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.1.4...graphql-function-transformer@1.1.5) (2019-07-24) - -**Note:** Version bump only for package graphql-function-transformer - -## [1.1.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.1.2...graphql-function-transformer@1.1.4) (2019-06-30) - -**Note:** Version bump only for package graphql-function-transformer - -## [1.1.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.1.1...graphql-function-transformer@1.1.2) (2019-06-26) - -**Note:** Version bump only for package graphql-function-transformer - -## [1.1.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.1.0...graphql-function-transformer@1.1.1) (2019-06-12) - -**Note:** Version bump only for package graphql-function-transformer - -# [1.1.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.0.2...graphql-function-transformer@1.1.0) (2019-05-29) - -### Features - -- feature/[@key](https://github.com/key) ([#1463](https://github.com/aws-amplify/amplify-cli/issues/1463)) ([00ed819](https://github.com/aws-amplify/amplify-cli/commit/00ed819)) - -## [1.0.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-function-transformer@1.0.1...graphql-function-transformer@1.0.2) (2019-05-21) - -### Bug Fixes - -- **graphql-function-transformer:** handle NONE env in [@function](https://github.com/function) ([#1491](https://github.com/aws-amplify/amplify-cli/issues/1491)) ([c742d7d](https://github.com/aws-amplify/amplify-cli/commit/c742d7d)) - -## 1.0.1 (2019-05-17) - -**Note:** Version bump only for package graphql-function-transformer diff --git a/packages/graphql-function-transformer/package.json b/packages/graphql-function-transformer/package.json deleted file mode 100644 index e9e5fbcbaf..0000000000 --- a/packages/graphql-function-transformer/package.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "name": "graphql-function-transformer", - "version": "3.3.71", - "description": "Implements the @function directive.", - "repository": { - "type": "git", - "url": "https://github.com/aws-amplify/amplify-category-api.git", - "directory": "packages/graphql-function-transformer" - }, - "author": "Amazon Web Services", - "license": "Apache-2.0", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "keywords": [ - "graphql", - "appsync", - "aws" - ], - "scripts": { - "test": "jest", - "build": "tsc", - "watch": "tsc -w", - "clean": "rimraf ./lib", - "extract-api": "ts-node ../../scripts/extract-api.ts" - }, - "dependencies": { - "cloudform-types": "^4.2.0", - "graphql": "^15.5.0", - "graphql-mapping-template": "4.20.16", - "graphql-transformer-common": "4.31.1", - "graphql-transformer-core": "8.2.13" - }, - "jest": { - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, - "testURL": "http://localhost", - "testRegex": "(src/__tests__/.*.test.*)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], - "collectCoverage": true, - "coverageProvider": "v8", - "coverageThreshold": { - "global": { - "branches": 85, - "functions": 90, - "lines": 90 - } - }, - "coverageReporters": [ - "clover", - "text" - ], - "collectCoverageFrom": [ - "src/**/*.ts" - ], - "coveragePathIgnorePatterns": [ - "/__tests__/" - ] - } -} diff --git a/packages/graphql-function-transformer/src/FunctionTransformer.ts b/packages/graphql-function-transformer/src/FunctionTransformer.ts deleted file mode 100644 index 069866dd66..0000000000 --- a/packages/graphql-function-transformer/src/FunctionTransformer.ts +++ /dev/null @@ -1,190 +0,0 @@ -import { Transformer, TransformerContext, getDirectiveArguments, TransformerContractError } from 'graphql-transformer-core'; -import { FunctionDirectiveV1 } from '@aws-amplify/graphql-directives'; -import { obj, str, ref, printBlock, compoundExpression, qref, raw, iff } from 'graphql-mapping-template'; -import { ResolverResourceIDs, FunctionResourceIDs, ResourceConstants } from 'graphql-transformer-common'; -import { ObjectTypeDefinitionNode, FieldDefinitionNode, DirectiveNode, parse } from 'graphql'; -import { AppSync, IAM, Fn } from 'cloudform-types'; -import { lambdaArnResource } from './lambdaArns'; - -const FUNCTION_DIRECTIVE_STACK = 'FunctionDirectiveStack'; - -export class FunctionTransformer extends Transformer { - constructor() { - // prettier-ignore - super( - 'FunctionTransformer', - parse(FunctionDirectiveV1.definition), - ); - } - - /** - * Add the required resources to invoke a lambda function for this field. - */ - field = (parent: ObjectTypeDefinitionNode, definition: FieldDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => { - const { name, region } = getDirectiveArguments(directive); - if (!name) { - throw new TransformerContractError(`Must supply a 'name' to @${FunctionDirectiveV1.name}.`); - } - - // Add the iam role if it does not exist. - const iamRoleKey = FunctionResourceIDs.FunctionIAMRoleID(name, region); - if (!ctx.getResource(iamRoleKey)) { - ctx.setResource(iamRoleKey, this.role(name, region)); - ctx.mapResourceToStack(FUNCTION_DIRECTIVE_STACK, iamRoleKey); - } - - // Add the data source if it does not exist. - const lambdaDataSourceKey = FunctionResourceIDs.FunctionDataSourceID(name, region); - if (!ctx.getResource(lambdaDataSourceKey)) { - ctx.setResource(lambdaDataSourceKey, this.datasource(name, region)); - ctx.mapResourceToStack(FUNCTION_DIRECTIVE_STACK, lambdaDataSourceKey); - } - - // Add function that invokes the lambda function - const functionConfigurationKey = FunctionResourceIDs.FunctionAppSyncFunctionConfigurationID(name, region); - if (!ctx.getResource(functionConfigurationKey)) { - ctx.setResource(functionConfigurationKey, this.function(name, region)); - ctx.mapResourceToStack(FUNCTION_DIRECTIVE_STACK, functionConfigurationKey); - } - - // Add resolver that invokes our function - const typeName = parent.name.value; - const fieldName = definition.name.value; - const resolverKey = ResolverResourceIDs.ResolverResourceID(typeName, fieldName); - const resolver = ctx.getResource(resolverKey); - if (!resolver) { - ctx.setResource(resolverKey, this.resolver(typeName, fieldName, name, region)); - ctx.mapResourceToStack(FUNCTION_DIRECTIVE_STACK, resolverKey); - } else if (resolver.Properties.Kind === 'PIPELINE') { - ctx.setResource( - resolverKey, - this.appendFunctionToResolver(resolver, FunctionResourceIDs.FunctionAppSyncFunctionConfigurationID(name, region)), - ); - } - }; - - /** - * Create a role that allows our AppSync API to talk to our Lambda function. - */ - role = (name: string, region: string): any => { - return new IAM.Role({ - RoleName: Fn.If( - ResourceConstants.CONDITIONS.HasEnvironmentParameter, - Fn.Join('-', [ - FunctionResourceIDs.FunctionIAMRoleName(name, true), // max of 64. 64-10-26-28 = 0 - Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), // 26 - Fn.Ref(ResourceConstants.PARAMETERS.Env), // 10 - ]), - Fn.Join('-', [ - FunctionResourceIDs.FunctionIAMRoleName(name, false), // max of 64. 64-26-38 = 0 - Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), // 26 - ]), - ), - AssumeRolePolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Principal: { - Service: 'appsync.amazonaws.com', - }, - Action: 'sts:AssumeRole', - }, - ], - }, - Policies: [ - { - PolicyName: 'InvokeLambdaFunction', - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Action: ['lambda:InvokeFunction'], - Resource: lambdaArnResource(name, region), - }, - ], - }, - }, - ], - }); - }; - - /** - * Creates a lambda data source that registers the lambda function and associated role. - */ - datasource = (name: string, region: string): any => { - return new AppSync.DataSource({ - ApiId: Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), - Name: FunctionResourceIDs.FunctionDataSourceID(name, region), - Type: 'AWS_LAMBDA', - ServiceRoleArn: Fn.GetAtt(FunctionResourceIDs.FunctionIAMRoleID(name, region), 'Arn'), - LambdaConfig: { - LambdaFunctionArn: lambdaArnResource(name, region), - }, - }).dependsOn(FunctionResourceIDs.FunctionIAMRoleID(name, region)); - }; - - /** - * Create a new pipeline function that calls out to the lambda function and returns the value. - */ - function = (name: string, region: string): any => { - return new AppSync.FunctionConfiguration({ - ApiId: Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), - Name: FunctionResourceIDs.FunctionAppSyncFunctionConfigurationID(name, region), - DataSourceName: FunctionResourceIDs.FunctionDataSourceID(name, region), - FunctionVersion: '2018-05-29', - RequestMappingTemplate: printBlock(`Invoke AWS Lambda data source: ${FunctionResourceIDs.FunctionDataSourceID(name, region)}`)( - obj({ - version: str('2018-05-29'), - operation: str('Invoke'), - payload: obj({ - typeName: str('$ctx.stash.get("typeName")'), - fieldName: str('$ctx.stash.get("fieldName")'), - arguments: ref('util.toJson($ctx.arguments)'), - identity: ref('util.toJson($ctx.identity)'), - source: ref('util.toJson($ctx.source)'), - request: ref('util.toJson($ctx.request)'), - prev: ref('util.toJson($ctx.prev)'), - }), - }), - ), - ResponseMappingTemplate: printBlock('Handle error or return result')( - compoundExpression([ - iff(ref('ctx.error'), raw('$util.error($ctx.error.message, $ctx.error.type)')), - raw('$util.toJson($ctx.result)'), - ]), - ), - }).dependsOn(FunctionResourceIDs.FunctionDataSourceID(name, region)); - }; - - /** - * Create a resolver of one that calls the "function" function. - */ - resolver = (type: string, field: string, name: string, region?: string): any => { - return new AppSync.Resolver({ - ApiId: Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), - TypeName: type, - FieldName: field, - Kind: 'PIPELINE', - PipelineConfig: { - Functions: [Fn.GetAtt(FunctionResourceIDs.FunctionAppSyncFunctionConfigurationID(name, region), 'FunctionId')], - }, - RequestMappingTemplate: printBlock('Stash resolver specific context.')( - compoundExpression([qref(`$ctx.stash.put("typeName", "${type}")`), qref(`$ctx.stash.put("fieldName", "${field}")`), obj({})]), - ), - ResponseMappingTemplate: '$util.toJson($ctx.prev.result)', - }).dependsOn(FunctionResourceIDs.FunctionAppSyncFunctionConfigurationID(name, region)); - }; - - appendFunctionToResolver(resolver: any, functionId: string) { - if ( - resolver.Properties.PipelineConfig && - resolver.Properties.PipelineConfig.Functions && - Array.isArray(resolver.Properties.PipelineConfig.Functions) - ) { - resolver.Properties.PipelineConfig.Functions.push(Fn.GetAtt(functionId, 'FunctionId')); - } - return resolver; - } -} diff --git a/packages/graphql-function-transformer/src/__tests__/FunctionTransformer.test.ts b/packages/graphql-function-transformer/src/__tests__/FunctionTransformer.test.ts deleted file mode 100644 index 4a2d5d25b1..0000000000 --- a/packages/graphql-function-transformer/src/__tests__/FunctionTransformer.test.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { GraphQLTransform } from 'graphql-transformer-core'; -import { FunctionTransformer } from '../FunctionTransformer'; - -test('FunctionTransformer should add a datasource, IAM role and a resolver resources', () => { - const validSchema = ` - type Query { - echo(msg: String): String @function(name: "echofunction-\${env}") - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new FunctionTransformer()], - }); - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // EchofunctionLambdaDataSource, EchofunctionLambdaDataSourceRole, QueryEchoResolver, GraphQLSchema - expect(Object.keys(out.stacks.FunctionDirectiveStack.Resources).length).toEqual(4); - - let expectedLambdaArn = 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:echofunction-${env}'; - // datasource - let datasourceResource = out.stacks.FunctionDirectiveStack.Resources.EchofunctionLambdaDataSource; - expect(datasourceResource).toBeDefined(); - expect(datasourceResource.Properties.LambdaConfig.LambdaFunctionArn['Fn::If'][1]['Fn::Sub'][0]).toEqual(expectedLambdaArn); - - // IAM role - let iamRoleResource = out.stacks.FunctionDirectiveStack.Resources.EchofunctionLambdaDataSourceRole; - expect(iamRoleResource).toBeDefined(); - expect(iamRoleResource.Properties.AssumeRolePolicyDocument.Statement[0].Principal.Service).toEqual('appsync.amazonaws.com'); - expect(iamRoleResource.Properties.AssumeRolePolicyDocument.Statement[0].Action).toEqual('sts:AssumeRole'); - expect(iamRoleResource.Properties.Policies[0].PolicyDocument.Statement[0].Action[0]).toEqual('lambda:InvokeFunction'); - expect(iamRoleResource.Properties.Policies[0].PolicyDocument.Statement[0].Resource['Fn::If'][1]['Fn::Sub'][0]).toEqual(expectedLambdaArn); - - // Resolver - let resolverResource = out.stacks.FunctionDirectiveStack.Resources.QueryechoResolver; - expect(resolverResource).toBeDefined(); - expect(resolverResource.Properties.FieldName).toEqual('echo'); - expect(resolverResource.Properties.TypeName).toEqual('Query'); - expect(resolverResource.Properties.Kind).toEqual('PIPELINE'); - expect(resolverResource.Properties.PipelineConfig.Functions.length).toEqual(1); -}); - -test('two @function directives for the same lambda should produce a single datasource, single role and two resolvers', () => { - const validSchema = ` - type Query { - echo(msg: String): String @function(name: "echofunction-\${env}") - magic(msg: String): String @function(name: "echofunction-\${env}") - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new FunctionTransformer()], - }); - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(Object.keys(out.stacks.FunctionDirectiveStack.Resources).length).toEqual(5); - expect(out.stacks.FunctionDirectiveStack.Resources.EchofunctionLambdaDataSource).toBeDefined(); - expect(out.stacks.FunctionDirectiveStack.Resources.EchofunctionLambdaDataSourceRole).toBeDefined(); - expect(out.stacks.FunctionDirectiveStack.Resources.QueryechoResolver).toBeDefined(); - expect(out.stacks.FunctionDirectiveStack.Resources.QuerymagicResolver).toBeDefined(); -}); - -test('two @function directives for the same field should be valid', () => { - const validSchema = ` - type Query { - echo(msg: String): String @function(name: "echofunction-\${env}") @function(name: "otherfunction") - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new FunctionTransformer()], - }); - const out = transformer.transform(validSchema); - let resolverResource = out.stacks.FunctionDirectiveStack.Resources.QueryechoResolver; - expect(resolverResource).toBeDefined(); - expect(resolverResource.Properties.FieldName).toEqual('echo'); - expect(resolverResource.Properties.TypeName).toEqual('Query'); - expect(resolverResource.Properties.PipelineConfig.Functions.length).toEqual(2); - const otherFunctionIamResource = out.stacks.FunctionDirectiveStack.Resources.OtherfunctionLambdaDataSourceRole; - expect(otherFunctionIamResource.Properties.Policies[0].PolicyDocument.Statement[0].Resource['Fn::If'][1]['Fn::Sub'][0]).toEqual( - 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:otherfunction', - ); - const echoFunctionIamResource = out.stacks.FunctionDirectiveStack.Resources.EchofunctionLambdaDataSourceRole; - expect(echoFunctionIamResource.Properties.Policies[0].PolicyDocument.Statement[0].Resource['Fn::If'][1]['Fn::Sub'][0]).toEqual( - 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:echofunction-${env}', - ); - expect(echoFunctionIamResource.Properties.Policies[0].PolicyDocument.Statement[0].Resource['Fn::If'][1]['Fn::Sub'][1].env.Ref).toEqual( - 'env', - ); -}); - -test('@function directive applied to Object should throw Error', () => { - const invalidSchema = ` - type Query @function(name: "echofunction-\${env}") { - echo(msg: String): String @function(name: "echofunction-\${env}") - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new FunctionTransformer()], - }); - expect(() => transformer.transform(invalidSchema)).toThrowError(/Directive "@function" may not be used on OBJECT/); -}); diff --git a/packages/graphql-function-transformer/src/index.ts b/packages/graphql-function-transformer/src/index.ts deleted file mode 100644 index e287ae79b9..0000000000 --- a/packages/graphql-function-transformer/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './FunctionTransformer'; -// No-op change to trigger re-publish diff --git a/packages/graphql-function-transformer/src/lambdaArns.ts b/packages/graphql-function-transformer/src/lambdaArns.ts deleted file mode 100644 index 11de0542d3..0000000000 --- a/packages/graphql-function-transformer/src/lambdaArns.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Fn, Refs } from 'cloudform-types'; -import { ResourceConstants } from 'graphql-transformer-common'; - -export function lambdaArnResource(name: string, region?: string) { - const substitutions = {}; - if (referencesEnv(name)) { - substitutions['env'] = Fn.Ref(ResourceConstants.PARAMETERS.Env); - } - return Fn.If( - ResourceConstants.CONDITIONS.HasEnvironmentParameter, - Fn.Sub(lambdaArnKey(name, region), substitutions), - Fn.Sub(lambdaArnKey(removeEnvReference(name), region), {}), - ); -} - -export function lambdaArnKey(name: string, region?: string) { - return region - ? `arn:aws:lambda:${region}:\${AWS::AccountId}:function:${name}` - : `arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${name}`; -} - -function referencesEnv(value: string) { - return value.match(/(\${env})/) !== null; -} - -function removeEnvReference(value: string) { - return value.replace(/(-\${env})/, ''); -} diff --git a/packages/graphql-function-transformer/tsconfig.json b/packages/graphql-function-transformer/tsconfig.json deleted file mode 100644 index f3fc268a32..0000000000 --- a/packages/graphql-function-transformer/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "strict": false, // TODO enable - "rootDir": "src", - "outDir": "lib" - }, - "references": [ - { "path": "../amplify-graphql-directives" }, - { "path": "../graphql-mapping-template" }, - { "path": "../graphql-transformer-common" }, - { "path": "../graphql-transformer-core" } - ] -} diff --git a/packages/graphql-http-transformer/.npmignore b/packages/graphql-http-transformer/.npmignore deleted file mode 100644 index 3ee5d55b0b..0000000000 --- a/packages/graphql-http-transformer/.npmignore +++ /dev/null @@ -1,5 +0,0 @@ -**/__mocks__/** -**/__tests__/** -src -tsconfig.json -tsconfig.tsbuildinfo diff --git a/packages/graphql-http-transformer/API.md b/packages/graphql-http-transformer/API.md deleted file mode 100644 index 65ac28526e..0000000000 --- a/packages/graphql-http-transformer/API.md +++ /dev/null @@ -1,42 +0,0 @@ -## API Report File for "graphql-http-transformer" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { default as default_2 } from 'cloudform-types/types/appSync/dataSource'; -import { default as default_3 } from 'cloudform-types/types/appSync/resolver'; -import { DirectiveNode } from 'graphql'; -import { FieldDefinitionNode } from 'graphql'; -import { InterfaceTypeDefinitionNode } from 'graphql'; -import { ObjectTypeDefinitionNode } from 'graphql'; -import Template from 'cloudform-types/types/template'; -import { Transformer as Transformer_2 } from 'graphql-transformer-core'; -import { TransformerContext } from 'graphql-transformer-core'; - -// @public (undocumented) -export interface HttpHeader { - // (undocumented) - key: String; - // (undocumented) - value: String; -} - -// @public (undocumented) -export class HttpTransformer extends Transformer_2 { - constructor(); - // (undocumented) - before: (ctx: TransformerContext) => void; - // (undocumented) - field: (parent: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, field: FieldDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => void; - // Warning: (ae-forgotten-export) The symbol "ResourceFactory" needs to be exported by the entry point index.d.ts - // - // (undocumented) - resources: ResourceFactory; - // (undocumented) - static urlRegex: RegExp; -} - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/graphql-http-transformer/CHANGELOG.md b/packages/graphql-http-transformer/CHANGELOG.md deleted file mode 100644 index 7b61816075..0000000000 --- a/packages/graphql-http-transformer/CHANGELOG.md +++ /dev/null @@ -1,944 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [5.2.80](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.79...graphql-http-transformer@5.2.80) (2024-07-15) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.79](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.78...graphql-http-transformer@5.2.79) (2024-07-02) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.78](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.77...graphql-http-transformer@5.2.78) (2024-06-25) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.77](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.76...graphql-http-transformer@5.2.77) (2024-04-26) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.76](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.75...graphql-http-transformer@5.2.76) (2024-04-11) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.75](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.74...graphql-http-transformer@5.2.75) (2024-03-28) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.74](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.73...graphql-http-transformer@5.2.74) (2024-02-28) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.73](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.72...graphql-http-transformer@5.2.73) (2024-02-05) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.72](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.71...graphql-http-transformer@5.2.72) (2024-01-22) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.71](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.70...graphql-http-transformer@5.2.71) (2023-12-18) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.70](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.69...graphql-http-transformer@5.2.70) (2023-12-06) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.69](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.68...graphql-http-transformer@5.2.69) (2023-11-18) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.68](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.67...graphql-http-transformer@5.2.68) (2023-11-16) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.67](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.66...graphql-http-transformer@5.2.67) (2023-11-15) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.66](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.65...graphql-http-transformer@5.2.66) (2023-10-21) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.65](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.64...graphql-http-transformer@5.2.65) (2023-08-30) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.64](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.63...graphql-http-transformer@5.2.64) (2023-08-28) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.63](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.62...graphql-http-transformer@5.2.63) (2023-08-09) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.62](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.61...graphql-http-transformer@5.2.62) (2023-07-21) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.61](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.60...graphql-http-transformer@5.2.61) (2023-07-17) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.60](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.59...graphql-http-transformer@5.2.60) (2023-07-07) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.59](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.58...graphql-http-transformer@5.2.59) (2023-07-07) - -### Bug Fixes - -- trigger republish of dependencies that failed in https://app.circleci.com/pipelines/github/aws-amplify/amplify-category-api/7981/workflows/e7366f04-6f0a-4ee4-9cc2-1772089e8005/jobs/163571 ([f2c7151](https://github.com/aws-amplify/amplify-category-api/commit/f2c7151005e4a9fd29d91ac1af1f3e482a06a5cc)) - -## [5.2.58](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.57...graphql-http-transformer@5.2.58) (2023-07-07) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.57](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.56...graphql-http-transformer@5.2.57) (2023-06-29) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.56](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.55...graphql-http-transformer@5.2.56) (2023-06-20) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.55](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.54...graphql-http-transformer@5.2.55) (2023-06-05) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.54](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.53...graphql-http-transformer@5.2.54) (2023-05-23) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.53](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.52...graphql-http-transformer@5.2.53) (2023-05-17) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.52](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.51...graphql-http-transformer@5.2.52) (2023-04-25) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.51](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.50...graphql-http-transformer@5.2.51) (2023-03-30) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.50](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.49...graphql-http-transformer@5.2.50) (2023-03-15) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.49](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.48...graphql-http-transformer@5.2.49) (2023-03-01) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.48](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.47...graphql-http-transformer@5.2.48) (2023-02-27) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.47](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.46...graphql-http-transformer@5.2.47) (2023-01-26) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.46](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.45...graphql-http-transformer@5.2.46) (2023-01-12) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.45](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.44...graphql-http-transformer@5.2.45) (2023-01-12) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.44](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.43...graphql-http-transformer@5.2.44) (2022-12-03) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.43](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.42...graphql-http-transformer@5.2.43) (2022-09-14) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.42](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.40...graphql-http-transformer@5.2.42) (2022-07-20) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.41](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.40...graphql-http-transformer@5.2.41) (2022-07-14) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.40](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.39...graphql-http-transformer@5.2.40) (2022-07-01) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.39](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.38...graphql-http-transformer@5.2.39) (2022-06-23) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.38](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.37...graphql-http-transformer@5.2.38) (2022-06-13) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.37](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.36...graphql-http-transformer@5.2.37) (2022-06-10) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.36](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.35...graphql-http-transformer@5.2.36) (2022-06-10) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.35](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.32...graphql-http-transformer@5.2.35) (2022-06-07) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.34](https://github.com/aws-amplify/amplify-category-api/compare/graphql-http-transformer@5.2.32...graphql-http-transformer@5.2.34) (2022-05-31) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.33](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.32...graphql-http-transformer@5.2.33) (2022-05-02) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.32](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.31...graphql-http-transformer@5.2.32) (2022-04-29) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.31](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.30...graphql-http-transformer@5.2.31) (2022-04-27) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.30](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.29...graphql-http-transformer@5.2.30) (2022-04-11) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.29](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.28...graphql-http-transformer@5.2.29) (2022-04-07) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.28](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.27...graphql-http-transformer@5.2.28) (2022-03-23) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.27](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.26...graphql-http-transformer@5.2.27) (2022-03-17) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.26](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.25...graphql-http-transformer@5.2.26) (2022-03-14) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.24...graphql-http-transformer@5.2.25) (2022-03-07) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.23...graphql-http-transformer@5.2.24) (2022-02-25) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.22...graphql-http-transformer@5.2.23) (2022-02-15) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.18...graphql-http-transformer@5.2.22) (2022-02-10) - -## 7.6.19 (2022-02-08) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.17...graphql-http-transformer@5.2.18) (2022-02-03) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.16...graphql-http-transformer@5.2.17) (2022-01-31) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.15...graphql-http-transformer@5.2.16) (2022-01-27) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.14...graphql-http-transformer@5.2.15) (2022-01-23) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.13...graphql-http-transformer@5.2.14) (2022-01-13) - -### Bug Fixes - -- clean up missing and unused GraphQL v1 dependencies ([#9496](https://github.com/aws-amplify/amplify-cli/issues/9496)) ([fe8201b](https://github.com/aws-amplify/amplify-cli/commit/fe8201be17f42db233fce0bb366ff4d0c8358ec0)) - -## [5.2.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.11...graphql-http-transformer@5.2.13) (2022-01-10) - -## 7.6.7 (2022-01-10) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.10...graphql-http-transformer@5.2.11) (2021-12-21) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.9...graphql-http-transformer@5.2.10) (2021-12-17) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.8...graphql-http-transformer@5.2.9) (2021-12-03) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.7...graphql-http-transformer@5.2.8) (2021-12-02) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.6...graphql-http-transformer@5.2.7) (2021-12-01) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.5...graphql-http-transformer@5.2.6) (2021-11-26) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.4...graphql-http-transformer@5.2.5) (2021-11-23) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.3...graphql-http-transformer@5.2.4) (2021-11-21) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.2...graphql-http-transformer@5.2.3) (2021-11-20) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@5.2.1...graphql-http-transformer@5.2.2) (2021-11-17) - -**Note:** Version bump only for package graphql-http-transformer - -## [5.2.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.18.13...graphql-http-transformer@5.2.1) (2021-11-15) - -**Note:** Version bump only for package graphql-http-transformer - -# [5.0.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.18.13...graphql-http-transformer@5.0.0) (2021-11-13) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.18.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.18.12...graphql-http-transformer@4.18.13) (2021-11-11) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.18.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.18.11...graphql-http-transformer@4.18.12) (2021-10-10) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.18.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.18.10...graphql-http-transformer@4.18.11) (2021-10-06) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.18.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.18.9...graphql-http-transformer@4.18.10) (2021-09-27) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.18.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.18.8...graphql-http-transformer@4.18.9) (2021-09-18) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.18.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.18.7...graphql-http-transformer@4.18.8) (2021-09-14) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.18.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.18.6...graphql-http-transformer@4.18.7) (2021-09-09) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.18.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.18.5...graphql-http-transformer@4.18.6) (2021-09-02) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.18.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.18.4...graphql-http-transformer@4.18.5) (2021-08-24) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.18.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.18.3...graphql-http-transformer@4.18.4) (2021-08-06) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.18.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.18.2...graphql-http-transformer@4.18.3) (2021-07-30) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.18.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.18.1...graphql-http-transformer@4.18.2) (2021-07-27) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.18.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.18.0...graphql-http-transformer@4.18.1) (2021-07-16) - -**Note:** Version bump only for package graphql-http-transformer - -# [4.18.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.17.11...graphql-http-transformer@4.18.0) (2021-06-30) - -### Features - -- **graphql-http-transformer:** support \${aws_region} template in [@http](https://github.com/http) url ([#7277](https://github.com/aws-amplify/amplify-cli/issues/7277)) ([7a740c3](https://github.com/aws-amplify/amplify-cli/commit/7a740c306f117d4566e86a94cd3632e785b1a420)) - -## [4.17.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.17.10...graphql-http-transformer@4.17.11) (2021-06-24) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.17.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.17.9...graphql-http-transformer@4.17.10) (2021-06-15) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.17.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.17.8...graphql-http-transformer@4.17.9) (2021-05-26) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.17.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.17.7...graphql-http-transformer@4.17.8) (2021-05-18) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.17.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.17.6...graphql-http-transformer@4.17.7) (2021-05-14) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.17.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.17.4...graphql-http-transformer@4.17.6) (2021-05-03) - -## 4.50.1 (2021-05-03) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.17.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.17.4...graphql-http-transformer@4.17.5) (2021-05-03) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.17.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.17.3...graphql-http-transformer@4.17.4) (2021-04-27) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.17.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.17.2...graphql-http-transformer@4.17.3) (2021-04-19) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.17.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.17.1...graphql-http-transformer@4.17.2) (2021-04-14) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.17.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.16.12...graphql-http-transformer@4.17.1) (2021-04-09) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.16.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.16.11...graphql-http-transformer@4.16.12) (2021-03-23) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.16.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.16.10...graphql-http-transformer@4.16.11) (2021-03-11) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.16.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.16.9...graphql-http-transformer@4.16.10) (2021-03-05) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.16.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.16.8...graphql-http-transformer@4.16.9) (2021-02-26) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.16.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.16.7...graphql-http-transformer@4.16.8) (2021-02-24) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.16.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.16.6...graphql-http-transformer@4.16.7) (2021-02-17) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.16.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.16.5...graphql-http-transformer@4.16.6) (2021-02-11) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.16.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.16.4...graphql-http-transformer@4.16.5) (2021-02-10) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.16.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.16.3...graphql-http-transformer@4.16.4) (2020-12-16) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.16.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.16.2...graphql-http-transformer@4.16.3) (2020-12-07) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.16.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.16.1...graphql-http-transformer@4.16.2) (2020-11-30) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.16.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.24...graphql-http-transformer@4.16.1) (2020-11-22) - -**Note:** Version bump only for package graphql-http-transformer - -# [4.16.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.4.12...graphql-http-transformer@4.16.0) (2020-11-22) - -### Bug Fixes - -- [#2296](https://github.com/aws-amplify/amplify-cli/issues/2296) [#2304](https://github.com/aws-amplify/amplify-cli/issues/2304) [#2100](https://github.com/aws-amplify/amplify-cli/issues/2100) ([#2439](https://github.com/aws-amplify/amplify-cli/issues/2439)) ([82762d6](https://github.com/aws-amplify/amplify-cli/commit/82762d6187eb2102ebd134b181622188c5632d1d)) -- build break, chore: typescript, lerna update ([#2640](https://github.com/aws-amplify/amplify-cli/issues/2640)) ([29fae36](https://github.com/aws-amplify/amplify-cli/commit/29fae366f4cab054feefa58c7dc733002d19570c)) -- export Typescript definitions and fix resulting type errors ([#2452](https://github.com/aws-amplify/amplify-cli/issues/2452)) ([7de3845](https://github.com/aws-amplify/amplify-cli/commit/7de384594d3b9cbf22cdaa85107fc8df26c141ec)), closes [#2451](https://github.com/aws-amplify/amplify-cli/issues/2451) -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c1927da10f8c54f38a523021187361131c)) - -## [4.15.27](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.24...graphql-http-transformer@4.15.27) (2020-11-20) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.26](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.24...graphql-http-transformer@4.15.26) (2020-11-20) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.24...graphql-http-transformer@4.15.25) (2020-11-19) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.23...graphql-http-transformer@4.15.24) (2020-11-08) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.22...graphql-http-transformer@4.15.23) (2020-10-30) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.21...graphql-http-transformer@4.15.22) (2020-10-22) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.21](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.20...graphql-http-transformer@4.15.21) (2020-10-17) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.20](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.19...graphql-http-transformer@4.15.20) (2020-10-01) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.19](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.18...graphql-http-transformer@4.15.19) (2020-09-16) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.17...graphql-http-transformer@4.15.18) (2020-08-31) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.16...graphql-http-transformer@4.15.17) (2020-08-14) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.15...graphql-http-transformer@4.15.16) (2020-08-11) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.13...graphql-http-transformer@4.15.15) (2020-07-29) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.13...graphql-http-transformer@4.15.14) (2020-07-23) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.12...graphql-http-transformer@4.15.13) (2020-07-18) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.11...graphql-http-transformer@4.15.12) (2020-07-15) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.10...graphql-http-transformer@4.15.11) (2020-06-25) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.9...graphql-http-transformer@4.15.10) (2020-06-18) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.8...graphql-http-transformer@4.15.9) (2020-06-11) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.7...graphql-http-transformer@4.15.8) (2020-06-10) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.6...graphql-http-transformer@4.15.7) (2020-06-02) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.5...graphql-http-transformer@4.15.6) (2020-05-26) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.4...graphql-http-transformer@4.15.5) (2020-05-15) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.3...graphql-http-transformer@4.15.4) (2020-05-08) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.2...graphql-http-transformer@4.15.3) (2020-04-23) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.15.1...graphql-http-transformer@4.15.2) (2020-03-22) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.15.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.13.3...graphql-http-transformer@4.15.1) (2020-03-07) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.14.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.13.5-beta.0...graphql-http-transformer@4.14.1) (2020-03-05) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.13.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.13.2...graphql-http-transformer@4.13.3) (2020-02-13) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.13.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.13.1...graphql-http-transformer@4.13.2) (2020-02-07) - -**Note:** Version bump only for package graphql-http-transformer - -## [4.13.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@4.13.0...graphql-http-transformer@4.13.1) (2020-01-24) - -**Note:** Version bump only for package graphql-http-transformer - -# [4.13.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.28.0...graphql-http-transformer@4.13.0) (2020-01-23) - -### Bug Fixes - -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.12.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.28.0...graphql-http-transformer@4.12.0) (2020-01-09) - -### Bug Fixes - -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.11.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.28.0...graphql-http-transformer@4.11.0) (2019-12-31) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.10.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.28.0...graphql-http-transformer@4.10.0) (2019-12-28) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.9.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.28.0...graphql-http-transformer@4.9.0) (2019-12-26) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.8.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.28.0...graphql-http-transformer@4.8.0) (2019-12-25) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.7.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.28.0...graphql-http-transformer@4.7.0) (2019-12-20) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.6.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.28.0...graphql-http-transformer@4.6.0) (2019-12-10) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.4.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.28.0...graphql-http-transformer@4.4.0) (2019-12-03) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.3.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.28.0...graphql-http-transformer@4.3.0) (2019-12-01) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.2.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.28.0...graphql-http-transformer@4.2.0) (2019-11-27) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.1.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.28.0...graphql-http-transformer@4.1.0) (2019-11-27) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [3.10.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.4.12...graphql-http-transformer@3.10.0) (2019-08-30) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.9.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.4.12...graphql-http-transformer@3.9.0) (2019-08-28) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.8.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.4.12...graphql-http-transformer@3.8.0) (2019-08-13) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.7.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.4.12...graphql-http-transformer@3.7.0) (2019-08-07) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.6.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.4.12...graphql-http-transformer@3.6.0) (2019-08-02) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.5.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.4.12...graphql-http-transformer@3.5.0) (2019-07-31) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -## [3.4.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.4.11...graphql-http-transformer@3.4.12) (2019-07-24) - -**Note:** Version bump only for package graphql-http-transformer - -## [3.4.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.4.9...graphql-http-transformer@3.4.11) (2019-06-30) - -**Note:** Version bump only for package graphql-http-transformer - -## [3.4.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.4.8...graphql-http-transformer@3.4.9) (2019-06-26) - -**Note:** Version bump only for package graphql-http-transformer - -## [3.4.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.4.7...graphql-http-transformer@3.4.8) (2019-06-12) - -**Note:** Version bump only for package graphql-http-transformer - -## [3.4.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.4.6...graphql-http-transformer@3.4.7) (2019-05-29) - -**Note:** Version bump only for package graphql-http-transformer - -## [3.4.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.4.5...graphql-http-transformer@3.4.6) (2019-05-21) - -**Note:** Version bump only for package graphql-http-transformer - -## [3.4.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.4.4...graphql-http-transformer@3.4.5) (2019-05-17) - -**Note:** Version bump only for package graphql-http-transformer - -## [3.4.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.4.2...graphql-http-transformer@3.4.4) (2019-05-07) - -**Note:** Version bump only for package graphql-http-transformer - -## [3.4.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.4.2...graphql-http-transformer@3.4.3) (2019-05-06) - -**Note:** Version bump only for package graphql-http-transformer - -## [3.4.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.4.1...graphql-http-transformer@3.4.2) (2019-04-16) - -**Note:** Version bump only for package graphql-http-transformer - -## [3.4.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.3.1...graphql-http-transformer@3.4.1) (2019-04-09) - -**Note:** Version bump only for package graphql-http-transformer - -## [3.3.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.0.9...graphql-http-transformer@3.3.1) (2019-04-03) - -**Note:** Version bump only for package graphql-http-transformer - -## [3.0.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.0.8...graphql-http-transformer@3.0.9) (2019-03-22) - -**Note:** Version bump only for package graphql-http-transformer - -## [3.0.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.0.7...graphql-http-transformer@3.0.8) (2019-03-05) - -**Note:** Version bump only for package graphql-http-transformer - -## [3.0.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.0.6...graphql-http-transformer@3.0.7) (2019-02-20) - -**Note:** Version bump only for package graphql-http-transformer - -## [3.0.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.0.5...graphql-http-transformer@3.0.6) (2019-02-12) - -### Bug Fixes - -- cloudform/type versions ([ec6f99f](https://github.com/aws-amplify/amplify-cli/commit/ec6f99f)) - -## [3.0.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.0.3-beta.0...graphql-http-transformer@3.0.5) (2019-02-11) - -**Note:** Version bump only for package graphql-http-transformer - -## [3.0.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.0.3-beta.0...graphql-http-transformer@3.0.3) (2019-02-11) - -**Note:** Version bump only for package graphql-http-transformer - -## [3.0.3-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@3.0.2...graphql-http-transformer@3.0.3-beta.0) (2019-02-11) - -**Note:** Version bump only for package graphql-http-transformer - - - -# [2.0.0-multienv.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@1.0.18-multienv.0...graphql-http-transformer@2.0.0-multienv.1) (2018-12-31) - -### Bug Fixes - -- update grahql transformer package versions for multienv ([8b4b2bd](https://github.com/aws-amplify/amplify-cli/commit/8b4b2bd)) - - - -## [1.0.18-multienv.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@1.0.17...graphql-http-transformer@1.0.18-multienv.0) (2018-11-16) - -**Note:** Version bump only for package graphql-http-transformer - - - -## [1.0.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@1.0.17-beta.0...graphql-http-transformer@1.0.17) (2018-11-09) - -**Note:** Version bump only for package graphql-http-transformer - - - -## 1.0.17-beta.0 (2018-11-09) - -**Note:** Version bump only for package graphql-http-transformer - - - -## [1.0.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@1.0.16-beta.0...graphql-http-transformer@1.0.16) (2018-11-05) - -**Note:** Version bump only for package graphql-http-transformer - - - -## 1.0.16-beta.0 (2018-11-05) - -**Note:** Version bump only for package graphql-http-transformer - - - -## 1.0.15 (2018-11-02) - -**Note:** Version bump only for package graphql-http-transformer - - - -## [1.0.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@1.0.14-beta.0...graphql-http-transformer@1.0.14) (2018-11-02) - -**Note:** Version bump only for package graphql-http-transformer - - - -## 1.0.14-beta.0 (2018-11-02) - -**Note:** Version bump only for package graphql-http-transformer - - - -## [1.0.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-http-transformer@1.0.13-beta.0...graphql-http-transformer@1.0.13) (2018-10-23) - -**Note:** Version bump only for package graphql-http-transformer - - - -## 1.0.13-beta.0 (2018-10-23) - -**Note:** Version bump only for package graphql-http-transformer - - - -## [1.0.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.11...graphql-connection-transformer@1.0.12) (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.10...graphql-connection-transformer@1.0.11) (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.9...graphql-connection-transformer@1.0.10) (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.8...graphql-connection-transformer@1.0.9) (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.7...graphql-connection-transformer@1.0.8) (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.6...graphql-connection-transformer@1.0.7) (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.5...graphql-connection-transformer@1.0.6) (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## [1.0.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-connection-transformer@1.0.4...graphql-connection-transformer@1.0.5) (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## 1.0.4 (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## 1.0.3 (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## 1.0.2 (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer - - - -## 1.0.1 (2018-08-23) - -**Note:** Version bump only for package graphql-connection-transformer diff --git a/packages/graphql-http-transformer/package.json b/packages/graphql-http-transformer/package.json deleted file mode 100644 index e4a4a85e8c..0000000000 --- a/packages/graphql-http-transformer/package.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "name": "graphql-http-transformer", - "version": "5.2.80", - "description": "An AppSync model transform for HTTP resolvers.", - "repository": { - "type": "git", - "url": "https://github.com/aws-amplify/amplify-category-api.git", - "directory": "packages/graphql-http-transformer" - }, - "author": "Amazon Web Services", - "license": "Apache-2.0", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "keywords": [ - "graphql", - "appsync", - "aws" - ], - "scripts": { - "test": "jest", - "build": "tsc", - "clean": "rimraf ./lib", - "extract-api": "ts-node ../../scripts/extract-api.ts" - }, - "dependencies": { - "cloudform-types": "^4.2.0", - "graphql": "^15.5.0", - "graphql-mapping-template": "4.20.16", - "graphql-transformer-common": "4.31.1", - "graphql-transformer-core": "8.2.13" - }, - "jest": { - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, - "testURL": "http://localhost/", - "testRegex": "(src/__tests__/.*.test.*)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], - "collectCoverage": true, - "coverageProvider": "v8", - "coverageThreshold": { - "global": { - "branches": 90, - "functions": 80, - "lines": 90 - } - }, - "coverageReporters": [ - "clover", - "text" - ], - "collectCoverageFrom": [ - "src/**/*.ts" - ], - "coveragePathIgnorePatterns": [ - "/__tests__/" - ] - } -} diff --git a/packages/graphql-http-transformer/src/HttpTransformer.ts b/packages/graphql-http-transformer/src/HttpTransformer.ts deleted file mode 100644 index d20854bb48..0000000000 --- a/packages/graphql-http-transformer/src/HttpTransformer.ts +++ /dev/null @@ -1,238 +0,0 @@ -import { Transformer, TransformerContext, TransformerContractError } from 'graphql-transformer-core'; -import { HttpDirectiveV1 } from '@aws-amplify/graphql-directives'; -import { - DirectiveNode, - ObjectTypeDefinitionNode, - Kind, - FieldDefinitionNode, - InterfaceTypeDefinitionNode, - InputValueDefinitionNode, - print, - parse, -} from 'graphql'; -import { getDirectiveArgument, isScalar, ResolverResourceIDs, HttpResourceIDs } from 'graphql-transformer-common'; -import { ResourceFactory } from './resources'; -import { makeUrlParamInputObject, makeHttpArgument, makeHttpQueryInputObject, makeHttpBodyInputObject } from './definitions'; - -const HTTP_STACK_NAME = 'HttpStack'; - -type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; - -export interface HttpHeader { - key: String; - value: String; -} - -interface HttpDirectiveArgs { - method?: HttpMethod; - url: String; - headers: HttpHeader[]; -} - -/** - * The @http transform - * - * This transform attaches http resolvers to any fields with the @http directive. - * Works with GET, POST, PUT, DELETE requests. - */ -export class HttpTransformer extends Transformer { - resources: ResourceFactory; - - static urlRegex = /(http(s)?:\/\/)|(\/.*)/g; - - constructor() { - super('HttpTransformer', parse(HttpDirectiveV1.definition)); - this.resources = new ResourceFactory(); - } - - public before = (ctx: TransformerContext): void => { - let directiveList: DirectiveNode[] = []; - - // gather all the http directives - for (const def of ctx.inputDocument.definitions) { - if (def.kind === Kind.OBJECT_TYPE_DEFINITION) { - for (const field of def.fields) { - const httpDirective = field.directives.find((dir) => dir.name.value === 'http'); - if (httpDirective) { - directiveList.push(httpDirective); - } - } - } - } - - // create all the datasources we will need for this schema - directiveList.forEach((value: DirectiveNode) => { - const url = getDirectiveArgument(value, 'url'); - // require a protocol in the url - const protocolMatcher = /^http(s)?:\/\//; - if (!protocolMatcher.test(url)) { - throw new TransformerContractError( - `@http directive at location ${value.loc.start} ` + `requires a url parameter that begins with http:// or https://.`, - ); - } - // extract just the base url with protocol - const baseURL = url.replace(HttpTransformer.urlRegex, '$1'); - const dataSourceID = HttpResourceIDs.HttpDataSourceID(baseURL); - // only create one DataSource per base URL - if (!ctx.getResource(dataSourceID)) { - ctx.mapResourceToStack(HTTP_STACK_NAME, dataSourceID); - ctx.setResource(dataSourceID, this.resources.makeHttpDataSource(baseURL)); - } - }); - }; - - /** - * Create and configure the HTTP resolver for this field - */ - public field = ( - parent: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, - field: FieldDefinitionNode, - directive: DirectiveNode, - ctx: TransformerContext, - ): void => { - ctx.mapResourceToStack(HTTP_STACK_NAME, ResolverResourceIDs.ResolverResourceID(parent.name.value, field.name.value)); - const url: string = getDirectiveArgument(directive, 'url'); - const baseURL: string = url.replace(HttpTransformer.urlRegex, '$1'); - // split the url into pieces, and get the path part off the end - let path: string = url.split(/(http(s)?:\/\/|www\.)|(\/.*)/g).slice(-2, -1)[0]; - - // extract any URL parameters from the path - let urlParams: string[] = path.match(/:\w+/g); - let queryBodyArgsArray: InputValueDefinitionNode[] = field.arguments as InputValueDefinitionNode[]; - let newFieldArgsArray: InputValueDefinitionNode[] = []; - - if (urlParams) { - urlParams = urlParams.map((p) => p.replace(':', '')); - - // if there are URL parameters, remove them from the array we'll use - // to create the query and body types - queryBodyArgsArray = field.arguments.filter((e) => isScalar(e.type) && !urlParams.includes(e.name.value)); - - // replace each URL parameter with $ctx.args.params.parameter_name for use in resolver template - path = path.replace(/:\w+/g, (str: string) => { - return `\$\{ctx.args.params.${str.replace(':', '')}\}`; - }); - - const urlParamInputObject = makeUrlParamInputObject(parent, field, urlParams); - ctx.addInput(urlParamInputObject); - - newFieldArgsArray.push(makeHttpArgument('params', urlParamInputObject, true)); - } - - let method: HttpMethod = getDirectiveArgument(directive, 'method'); - if (!method) { - method = 'GET'; - } - - let headers: HttpHeader[] = getDirectiveArgument(directive, 'headers'); - - if (!headers || !Array.isArray(headers)) { - headers = []; - } - - if (queryBodyArgsArray.length > 0) { - // for GET requests, leave the nullability of the query parameters unchanged - - // but for PUT, POST and PATCH, unwrap any non-nulls - const queryInputObject = makeHttpQueryInputObject(parent, field, queryBodyArgsArray, method !== 'GET'); - const bodyInputObject = makeHttpBodyInputObject(parent, field, queryBodyArgsArray, true); - - // if any of the arguments for the query are non-null, - // make the newly generated type wrapper non-null too (only really applies for GET requests) - const makeNonNull = queryInputObject.fields.filter((a) => a.type.kind === Kind.NON_NULL_TYPE).length > 0; - - ctx.addInput(queryInputObject); - newFieldArgsArray.push(makeHttpArgument('query', queryInputObject, makeNonNull)); - - if (method !== 'GET' && method !== 'DELETE') { - ctx.addInput(bodyInputObject); - newFieldArgsArray.push(makeHttpArgument('body', bodyInputObject, makeNonNull)); - } - } - - // build the payload - switch (method) { - case 'GET': { - const getResourceID = ResolverResourceIDs.ResolverResourceID(parent.name.value, field.name.value); - if (!ctx.getResource(getResourceID)) { - const getResolver = this.resources.makeGetResolver(baseURL, path, parent.name.value, field.name.value, headers); - ctx.setResource(getResourceID, getResolver); - } - break; - } - case 'POST': { - const postResourceID = ResolverResourceIDs.ResolverResourceID(parent.name.value, field.name.value); - if (!ctx.getResource(postResourceID)) { - const postResolver = this.resources.makePostResolver( - baseURL, - path, - parent.name.value, - field.name.value, - queryBodyArgsArray.filter((a) => a.type.kind === Kind.NON_NULL_TYPE).map((a) => a.name.value), - headers, - ); - ctx.setResource(postResourceID, postResolver); - } - break; - } - case 'PUT': { - const putResourceID = ResolverResourceIDs.ResolverResourceID(parent.name.value, field.name.value); - if (!ctx.getResource(putResourceID)) { - const putResolver = this.resources.makePutResolver( - baseURL, - path, - parent.name.value, - field.name.value, - queryBodyArgsArray.filter((a) => a.type.kind === Kind.NON_NULL_TYPE).map((a) => a.name.value), - headers, - ); - ctx.setResource(putResourceID, putResolver); - } - break; - } - case 'DELETE': { - const deleteResourceID = ResolverResourceIDs.ResolverResourceID(parent.name.value, field.name.value); - if (!ctx.getResource(deleteResourceID)) { - const deleteResolver = this.resources.makeDeleteResolver(baseURL, path, parent.name.value, field.name.value, headers); - ctx.setResource(deleteResourceID, deleteResolver); - } - break; - } - case 'PATCH': { - const patchResourceID = ResolverResourceIDs.ResolverResourceID(parent.name.value, field.name.value); - if (!ctx.getResource(patchResourceID)) { - const patchResolver = this.resources.makePatchResolver( - baseURL, - path, - parent.name.value, - field.name.value, - queryBodyArgsArray.filter((a) => a.type.kind === Kind.NON_NULL_TYPE).map((a) => a.name.value), - headers, - ); - ctx.setResource(patchResourceID, patchResolver); - } - break; - } - default: - // nothing - } - - // now update the field if necessary with the new arguments - if (newFieldArgsArray.length > 0) { - const updatedField = { - ...field, - arguments: newFieldArgsArray, - }; - - const mostRecentParent = ctx.getType(parent.name.value) as ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode; - let updatedFieldsInParent = mostRecentParent.fields.filter((f) => f.name.value !== field.name.value); - updatedFieldsInParent.push(updatedField); - - const updatedParentType = { - ...mostRecentParent, - fields: updatedFieldsInParent, - }; - - ctx.putType(updatedParentType); - } - }; -} diff --git a/packages/graphql-http-transformer/src/__tests__/HttpTransformer.test.ts b/packages/graphql-http-transformer/src/__tests__/HttpTransformer.test.ts deleted file mode 100644 index 411bf68c2f..0000000000 --- a/packages/graphql-http-transformer/src/__tests__/HttpTransformer.test.ts +++ /dev/null @@ -1,385 +0,0 @@ -import { parse } from 'graphql'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { ResolverResourceIDs } from 'graphql-transformer-common'; -import { HttpTransformer } from '../HttpTransformer'; - -test('HttpTransformer with four basic requests', () => { - const validSchema = ` - type Comment { - id: ID! - content: String @http(method: POST, url: "http://www.api.com/ping") - content2: String @http(method: PUT, url: "http://www.api.com/ping") - more: String @http(url: "http://api.com/ping/me/2") - evenMore: String @http(method: DELETE, url: "http://www.google.com/query/id") - stillMore: String @http(method: PATCH, url: "https://www.api.com/ping/id") - } - `; - const transformer = new GraphQLTransform({ - transformers: [new HttpTransformer()], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // expect(out.Resources[ResolverResourceIDs.ResolverResourceID('Post', 'comments')]).toBeTruthy() - const schemaDoc = parse(out.schema); - expect(out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'content')]).toBeTruthy(); - expect(out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'content2')]).toBeTruthy(); - expect(out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'more')]).toBeTruthy(); - expect(out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'evenMore')]).toBeTruthy(); - expect(out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'stillMore')]).toBeTruthy(); -}); - -test('HttpTransformer with URL params happy case', () => { - const validSchema = ` - type Comment { - id: ID! - title: String - complex: CompObj @http(method: GET, url: "https://jsonplaceholder.typicode.com/posts/1") - complexAgain: CompObj @http(url: "https://jsonplaceholder.typicode.com/posts/2") - complexPost( - id: Int, - title: String, - body: String, - userId: Int - ): CompObj @http(method: POST, url: "https://jsonplaceholder.typicode.com/posts") - complexPut( - id: Int!, - title: String!, - body: String, - userId: Int! - ): CompObj @http(method: PUT, url: "https://jsonplaceholder.typicode.com/posts/:title/:id") - deleter: String @http(method: DELETE, url: "https://jsonplaceholder.typicode.com/posts/3") - complexGet( - id: Int! - ): CompObj @http(url: "https://jsonplaceholder.typicode.com/posts/:id") - complexGet2 ( - id: Int!, - title: String!, - userId: Int! - ): CompObj @http(url: "https://jsonplaceholder.typicode.com/posts/:title/:id") - } - type CompObj { - userId: Int - id: Int - title: String - body: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new HttpTransformer()], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // expect(out.Resources[ResolverResourceIDs.ResolverResourceID('Post', 'comments')]).toBeTruthy() - const schemaDoc = parse(out.schema); - expect(out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'complex')]).toBeTruthy(); - expect(out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'complexAgain')]).toBeTruthy(); - expect(out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'complexPost')]).toBeTruthy(); - expect(out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'complexPut')]).toBeTruthy(); - expect(out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'deleter')]).toBeTruthy(); -}); - -test('that HttpTransformer throws an error when missing protocol in URL argument', () => { - const validSchema = ` - type Comment { - id: ID! - content: String @http(method: POST, url: "www.api.com/ping") - } - `; - try { - const transformer = new GraphQLTransform({ - transformers: [new HttpTransformer()], - }); - const out = transformer.transform(validSchema); - } catch (e) { - expect(e.name).toEqual('TransformerContractError'); - } -}); - -test('HttpTransformer with URL and headers params happy case', () => { - const validSchema = ` - type Comment { - id: ID! - content: String @http(url: "https://www.api.com/ping", headers: [{key: "X-Header", value: "X-Header-Value"}]) - contentDelete: String @http(method: DELETE, url: "https://www.api.com/ping", headers: [{key: "X-Header", value: "X-Header-ValueDelete"}]) - contentPatch: String @http(method: PATCH, url: "https://www.api.com/ping", headers: [{key: "X-Header", value: "X-Header-ValuePatch"}]) - contentPost: String @http(method: POST, url: "https://www.api.com/ping", headers: [{key: "X-Header", value: "X-Header-ValuePost"}]) - complexPut( - id: Int!, - title: String!, - body: String, - userId: Int! - ): String @http(method: PUT, url: "https://jsonplaceholder.typicode.com/posts/:title/:id", headers: [{key: "X-Header", value: "X-Header-ValuePut"}]) - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new HttpTransformer()], - }); - const out = transformer.transform(validSchema); - - expect(out).toBeDefined(); - // expect(out.Resources[ResolverResourceIDs.ResolverResourceID('Post', 'comments')]).toBeTruthy() - const schemaDoc = parse(out.schema); - expect(out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'content')]).toBeTruthy(); - expect(out.resolvers['Comment.content.req.vtl']).toContain('$util.qr($headers.put("X-Header", "X-Header-Value"))'); - expect(out.resolvers['Comment.contentDelete.req.vtl']).toContain('$util.qr($headers.put("X-Header", "X-Header-ValueDelete"))'); - expect(out.resolvers['Comment.contentPatch.req.vtl']).toContain('$util.qr($headers.put("X-Header", "X-Header-ValuePatch"))'); - expect(out.resolvers['Comment.contentPost.req.vtl']).toContain('$util.qr($headers.put("X-Header", "X-Header-ValuePost"))'); - expect(out.resolvers['Comment.complexPut.req.vtl']).toContain('$util.qr($headers.put("X-Header", "X-Header-ValuePut"))'); -}); - -test('HttpTransformer with four basic requests with env on the URI', () => { - const validSchema = ` - type Comment { - id: ID! - content: String @http(method: POST, url: "http://www.api.com/ping\${env}") - content2: String @http(method: PUT, url: "http://www.api.com/ping\${env}") - more: String @http(url: "http://api.com/ping/me/2\${env}") - evenMore: String @http(method: DELETE, url: "http://www.google.com/query/id\${env}") - stillMore: String @http(method: PATCH, url: "https://www.api.com/ping/id\${env}") - } - `; - const transformer = new GraphQLTransform({ - transformers: [new HttpTransformer()], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const schemaDoc = parse(out.schema); - - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'content')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][0], - ).toContain('${env}'); - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'content')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][1].env.Ref, - ).toBe('env'); - - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'content2')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][0], - ).toContain('${env}'); - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'content2')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][1].env.Ref, - ).toBe('env'); - - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'more')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][0], - ).toContain('${env}'); - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'more')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][1].env.Ref, - ).toBe('env'); - - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'evenMore')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][0], - ).toContain('${env}'); - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'evenMore')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][1].env.Ref, - ).toBe('env'); - - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'stillMore')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][0], - ).toContain('${env}'); - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'stillMore')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][1].env.Ref, - ).toBe('env'); -}); - -test('HttpTransformer with four basic requests with env on the hostname', () => { - const validSchema = ` - type Comment { - id: ID! - content: String @http(method: POST, url: "http://\${env}www.api.com/ping") - content2: String @http(method: PUT, url: "http://\${env}www.api.com/ping") - more: String @http(url: "http://\${env}api.com/ping/me/2") - evenMore: String @http(method: DELETE, url: "http://\${env}www.google.com/query/id") - stillMore: String @http(method: PATCH, url: "https://\${env}www.api.com/ping/id") - } - `; - const transformer = new GraphQLTransform({ - transformers: [new HttpTransformer()], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - const schemaDoc = parse(out.schema); - - const contentDatasource = - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'content')].Properties.DataSourceName['Fn::GetAtt'][0]; - expect(out.stacks.HttpStack.Resources[contentDatasource].Properties.HttpConfig.Endpoint['Fn::Sub'][0]).toContain('${env}'); - expect(out.stacks.HttpStack.Resources[contentDatasource].Properties.HttpConfig.Endpoint['Fn::Sub'][1].env.Ref).toBe('env'); - - const content2Datasource = - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'content2')].Properties.DataSourceName[ - 'Fn::GetAtt' - ][0]; - expect(out.stacks.HttpStack.Resources[content2Datasource].Properties.HttpConfig.Endpoint['Fn::Sub'][0]).toContain('${env}'); - expect(out.stacks.HttpStack.Resources[content2Datasource].Properties.HttpConfig.Endpoint['Fn::Sub'][1].env.Ref).toBe('env'); - - const moreDatasource = - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'more')].Properties.DataSourceName['Fn::GetAtt'][0]; - expect(out.stacks.HttpStack.Resources[moreDatasource].Properties.HttpConfig.Endpoint['Fn::Sub'][0]).toContain('${env}'); - expect(out.stacks.HttpStack.Resources[moreDatasource].Properties.HttpConfig.Endpoint['Fn::Sub'][1].env.Ref).toBe('env'); - - const evenMoreDatasource = - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'evenMore')].Properties.DataSourceName[ - 'Fn::GetAtt' - ][0]; - expect(out.stacks.HttpStack.Resources[evenMoreDatasource].Properties.HttpConfig.Endpoint['Fn::Sub'][0]).toContain('${env}'); - expect(out.stacks.HttpStack.Resources[evenMoreDatasource].Properties.HttpConfig.Endpoint['Fn::Sub'][1].env.Ref).toBe('env'); - - const stillMoreDatasource = - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'stillMore')].Properties.DataSourceName[ - 'Fn::GetAtt' - ][0]; - expect(out.stacks.HttpStack.Resources[stillMoreDatasource].Properties.HttpConfig.Endpoint['Fn::Sub'][0]).toContain('${env}'); - expect(out.stacks.HttpStack.Resources[stillMoreDatasource].Properties.HttpConfig.Endpoint['Fn::Sub'][1].env.Ref).toBe('env'); -}); - -test('HttpTransformer with four basic requests with aws_region on the URI', () => { - const validSchema = ` - type Comment { - id: ID! - content: String @http(method: POST, url: "http://www.api.com/ping\${aws_region}") - content2: String @http(method: PUT, url: "http://www.api.com/ping\${aws_region}") - more: String @http(url: "http://api.com/ping/me/2\${aws_region}") - evenMore: String @http(method: DELETE, url: "http://www.google.com/query/id\${aws_region}") - stillMore: String @http(method: PATCH, url: "https://www.api.com/ping/id\${aws_region}") - } - `; - const transformer = new GraphQLTransform({ - transformers: [new HttpTransformer()], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const schemaDoc = parse(out.schema); - - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'content')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][0], - ).toContain('${aws_region}'); - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'content')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][1].aws_region.Ref, - ).toBe('AWS::Region'); - - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'content2')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][0], - ).toContain('${aws_region}'); - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'content2')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][1].aws_region.Ref, - ).toBe('AWS::Region'); - - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'more')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][0], - ).toContain('${aws_region}'); - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'more')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][1].aws_region.Ref, - ).toBe('AWS::Region'); - - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'evenMore')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][0], - ).toContain('${aws_region}'); - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'evenMore')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][1].aws_region.Ref, - ).toBe('AWS::Region'); - - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'stillMore')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][0], - ).toContain('${aws_region}'); - expect( - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'stillMore')].Properties.RequestMappingTemplate[ - 'Fn::Sub' - ][1].aws_region.Ref, - ).toBe('AWS::Region'); -}); - -test('HttpTransformer with four basic requests with aws_region on the hostname', () => { - const validSchema = ` - type Comment { - id: ID! - content: String @http(method: POST, url: "http://\${aws_region}www.api.com/ping") - content2: String @http(method: PUT, url: "http://\${aws_region}www.api.com/ping") - more: String @http(url: "http://\${aws_region}api.com/ping/me/2") - evenMore: String @http(method: DELETE, url: "http://\${aws_region}www.google.com/query/id") - stillMore: String @http(method: PATCH, url: "https://\${aws_region}www.api.com/ping/id") - } - `; - const transformer = new GraphQLTransform({ - transformers: [new HttpTransformer()], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - const schemaDoc = parse(out.schema); - - const contentDatasource = - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'content')].Properties.DataSourceName['Fn::GetAtt'][0]; - expect(out.stacks.HttpStack.Resources[contentDatasource].Properties.HttpConfig.Endpoint['Fn::Sub'][0]).toContain('${aws_region}'); - expect(out.stacks.HttpStack.Resources[contentDatasource].Properties.HttpConfig.Endpoint['Fn::Sub'][1].aws_region.Ref).toBe('AWS::Region'); - - const content2Datasource = - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'content2')].Properties.DataSourceName[ - 'Fn::GetAtt' - ][0]; - expect(out.stacks.HttpStack.Resources[content2Datasource].Properties.HttpConfig.Endpoint['Fn::Sub'][0]).toContain('${aws_region}'); - expect(out.stacks.HttpStack.Resources[content2Datasource].Properties.HttpConfig.Endpoint['Fn::Sub'][1].aws_region.Ref).toBe( - 'AWS::Region', - ); - - const moreDatasource = - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'more')].Properties.DataSourceName['Fn::GetAtt'][0]; - expect(out.stacks.HttpStack.Resources[moreDatasource].Properties.HttpConfig.Endpoint['Fn::Sub'][0]).toContain('${aws_region}'); - expect(out.stacks.HttpStack.Resources[moreDatasource].Properties.HttpConfig.Endpoint['Fn::Sub'][1].aws_region.Ref).toBe('AWS::Region'); - - const evenMoreDatasource = - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'evenMore')].Properties.DataSourceName[ - 'Fn::GetAtt' - ][0]; - expect(out.stacks.HttpStack.Resources[evenMoreDatasource].Properties.HttpConfig.Endpoint['Fn::Sub'][0]).toContain('${aws_region}'); - expect(out.stacks.HttpStack.Resources[evenMoreDatasource].Properties.HttpConfig.Endpoint['Fn::Sub'][1].aws_region.Ref).toBe( - 'AWS::Region', - ); - - const stillMoreDatasource = - out.stacks.HttpStack.Resources[ResolverResourceIDs.ResolverResourceID('Comment', 'stillMore')].Properties.DataSourceName[ - 'Fn::GetAtt' - ][0]; - expect(out.stacks.HttpStack.Resources[stillMoreDatasource].Properties.HttpConfig.Endpoint['Fn::Sub'][0]).toContain('${aws_region}'); - expect(out.stacks.HttpStack.Resources[stillMoreDatasource].Properties.HttpConfig.Endpoint['Fn::Sub'][1].aws_region.Ref).toBe( - 'AWS::Region', - ); -}); diff --git a/packages/graphql-http-transformer/src/definitions.ts b/packages/graphql-http-transformer/src/definitions.ts deleted file mode 100644 index c7be8ff075..0000000000 --- a/packages/graphql-http-transformer/src/definitions.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { - InputObjectTypeDefinitionNode, - InputValueDefinitionNode, - InterfaceTypeDefinitionNode, - ObjectTypeDefinitionNode, - FieldDefinitionNode, -} from 'graphql'; -import { makeInputValueDefinition, makeNonNullType, makeNamedType, ModelResourceIDs, unwrapNonNull } from 'graphql-transformer-common'; - -export function makeHttpArgument(name: string, inputType: InputObjectTypeDefinitionNode, makeNonNull: boolean): InputValueDefinitionNode { - // the URL params type that we create will need to be non-null, so build in some flexibility here - const type = makeNonNull ? makeNonNullType(makeNamedType(inputType.name.value)) : makeNamedType(inputType.name.value); - return makeInputValueDefinition(name, type); -} - -export function makeUrlParamInputObject( - parent: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, - field: FieldDefinitionNode, - urlParams: string[], -): InputObjectTypeDefinitionNode { - const name = ModelResourceIDs.UrlParamsInputObjectName(parent.name.value, field.name.value); - const urlParamFields = urlParams.map((param: string) => { - return makeInputValueDefinition(param, makeNonNullType(makeNamedType('String'))); - }); - return { - kind: 'InputObjectTypeDefinition', - // TODO: Service does not support new style descriptions so wait. - // description: { - // kind: 'StringValue', - // value: `Input type for ${obj.name.value} mutations` - // }, - name: { - kind: 'Name', - value: name, - }, - fields: urlParamFields, - directives: [], - }; -} - -export function makeHttpQueryInputObject( - parent: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, - field: FieldDefinitionNode, - queryArgArray: InputValueDefinitionNode[], - deNull: boolean, -): InputObjectTypeDefinitionNode { - const name = ModelResourceIDs.HttpQueryInputObjectName(parent.name.value, field.name.value); - // unwrap all the non-nulls in the argument array if the flag is set - const fields: InputValueDefinitionNode[] = deNull - ? queryArgArray.map((arg: InputValueDefinitionNode) => { - return { - ...arg, - type: unwrapNonNull(arg.type), - }; - }) - : queryArgArray; - return { - kind: 'InputObjectTypeDefinition', - // TODO: Service does not support new style descriptions so wait. - // description: { - // kind: 'StringValue', - // value: `Input type for ${obj.name.value} mutations` - // }, - name: { - kind: 'Name', - value: name, - }, - fields, - directives: [], - }; -} - -export function makeHttpBodyInputObject( - parent: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, - field: FieldDefinitionNode, - bodyArgArray: InputValueDefinitionNode[], - deNull: boolean, -): InputObjectTypeDefinitionNode { - const name = ModelResourceIDs.HttpBodyInputObjectName(parent.name.value, field.name.value); - // unwrap all the non-nulls in the argument array if the flag is set - const fields: InputValueDefinitionNode[] = deNull - ? bodyArgArray.map((arg: InputValueDefinitionNode) => { - return { - ...arg, - type: unwrapNonNull(arg.type), - }; - }) - : bodyArgArray; - return { - kind: 'InputObjectTypeDefinition', - // TODO: Service does not support new style descriptions so wait. - // description: { - // kind: 'StringValue', - // value: `Input type for ${obj.name.value} mutations` - // }, - name: { - kind: 'Name', - value: name, - }, - fields, - directives: [], - }; -} diff --git a/packages/graphql-http-transformer/src/index.ts b/packages/graphql-http-transformer/src/index.ts deleted file mode 100644 index 38c2039de0..0000000000 --- a/packages/graphql-http-transformer/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './HttpTransformer'; -// No-op change to trigger publish diff --git a/packages/graphql-http-transformer/src/resources.ts b/packages/graphql-http-transformer/src/resources.ts deleted file mode 100644 index b8f6073272..0000000000 --- a/packages/graphql-http-transformer/src/resources.ts +++ /dev/null @@ -1,323 +0,0 @@ -import { AppSync, Fn, IntrinsicFunction, Value } from 'cloudform-types'; -import { - and, - comment, - compoundExpression, - HttpMappingTemplate, - ifElse, - iff, - obj, - or, - parens, - print, - qref, - raw, - ref, - set, -} from 'graphql-mapping-template'; -import { HttpResourceIDs, ResourceConstants } from 'graphql-transformer-common'; -import Template from 'cloudform-types/types/template'; -import { HttpHeader } from './HttpTransformer'; - -export class ResourceFactory { - public makeParams() { - return {}; - } - - /** - * Creates the barebones template for an application. - */ - public initTemplate(): Template { - return { - Parameters: this.makeParams(), - Resources: {}, - Outputs: {}, - }; - } - - public makeHttpDataSource(baseURL: string) { - return new AppSync.DataSource({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - Name: HttpResourceIDs.HttpDataSourceID(baseURL), - Type: 'HTTP', - HttpConfig: { - Endpoint: this.replaceEnvAndRegion(baseURL), - }, - }); - } - - private referencesEnv(value: string): boolean { - return value.match(/(\${env})/) !== null; - } - - private referencesRegion(value: string): boolean { - return value.match(/(\${aws_region})/) !== null; - } - - private replaceEnvAndRegion(value: string): Value { - const vars: { - [key: string]: IntrinsicFunction; - } = {}; - - if (this.referencesEnv(value)) { - vars.env = Fn.Ref(ResourceConstants.PARAMETERS.Env); - } - - if (this.referencesRegion(value)) { - vars.aws_region = Fn.Ref('AWS::Region'); - } - - if (!vars.env && !vars.aws_region) { - return value; - } - - return Fn.Sub(value, vars); - } - - private makeVtlStringArray(inputArray: string[]) { - let returnArray = `[`; - inputArray.forEach((e: string) => (returnArray += `\'${e}\', `)); - return returnArray.slice(0, -2) + `]`; - } - - private makeNonNullChecks(nonNullArgs: string[]) { - return compoundExpression([ - comment('START: Manually checking that all non-null arguments are provided either in the query or the body'), - iff( - or(nonNullArgs.map((arg: string) => parens(and([raw(`!$ctx.args.body.${arg}`), raw(`!$ctx.args.query.${arg}`)])))), - ref('util.error("An argument you marked as Non-Null is not present ' + 'in the query nor the body of your request."))'), - ), - comment('END: Manually checking that all non-null arguments are provided either in the query or the body'), - ]); - } - - /** - * Create a resolver that makes a GET request. It assumes the endpoint expects query parameters in the exact - * shape of the input arguments to the http directive. Returns the result in JSON format, or an error if the status code - * is not 200 - * @param type - */ - public makeGetResolver(baseURL: string, path: string, type: string, field: string, headers: HttpHeader[]) { - const parsedHeaders = headers.map((header) => qref(`$headers.put("${header.key}", "${header.value}")`)); - - return new AppSync.Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(HttpResourceIDs.HttpDataSourceID(baseURL), 'Name'), - FieldName: field, - TypeName: type, - RequestMappingTemplate: this.replaceEnvAndRegion( - print( - compoundExpression([ - set(ref('headers'), ref('utils.http.copyHeaders($ctx.request.headers)')), - qref('$headers.put("accept-encoding", "application/json")'), - ...parsedHeaders, - HttpMappingTemplate.getRequest({ - resourcePath: path, - params: obj({ - query: ref('util.toJson($ctx.args.query)'), - headers: ref('util.toJson($headers)'), - }), - }), - ]), - ), - ), - ResponseMappingTemplate: print( - ifElse( - raw('$ctx.result.statusCode == 200'), - ifElse( - ref('ctx.result.headers.get("Content-Type").toLowerCase().contains("xml")'), - ref('utils.xml.toJsonString($ctx.result.body)'), - ref('ctx.result.body'), - ), - ref('util.qr($util.appendError($ctx.result.body, $ctx.result.statusCode))'), - ), - ), - }); // .dependsOn(ResourceConstants.RESOURCES.GraphQLSchemaLogicalID) - } - - /** - * Create a resolver that makes a POST request. It allows the user to provide arguments as either query - * parameters or in the body of the request. - * request. Returns the result in JSON format, or an error if the status code is not 200. - * Forwards the headers from the request, adding that the content type is JSON. - * @param type - */ - public makePostResolver(baseURL: string, path: string, type: string, field: string, nonNullArgs: string[], headers: HttpHeader[]) { - const parsedHeaders = headers.map((header) => qref(`$headers.put("${header.key}", "${header.value}")`)); - - return new AppSync.Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(HttpResourceIDs.HttpDataSourceID(baseURL), 'Name'), - FieldName: field, - TypeName: type, - RequestMappingTemplate: this.replaceEnvAndRegion( - print( - compoundExpression([ - nonNullArgs.length > 0 ? this.makeNonNullChecks(nonNullArgs) : null, - set(ref('headers'), ref('utils.http.copyHeaders($ctx.request.headers)')), - qref('$headers.put("Content-Type", "application/json")'), - qref('$headers.put("accept-encoding", "application/json")'), - ...parsedHeaders, - HttpMappingTemplate.postRequest({ - resourcePath: path, - params: obj({ - body: ref('util.toJson($ctx.args.body)'), - query: ref('util.toJson($ctx.args.query)'), - headers: ref('util.toJson($headers)'), - }), - }), - ]), - ), - ), - ResponseMappingTemplate: print( - ifElse( - raw('$ctx.result.statusCode == 200 || $ctx.result.statusCode == 201'), - // check if the content type returned is XML, and convert to JSON if so - ifElse( - ref('ctx.result.headers.get("Content-Type").toLowerCase().contains("xml")'), - ref('utils.xml.toJsonString($ctx.result.body)'), - ref('ctx.result.body'), - ), - ref('util.qr($util.appendError($ctx.result.body, $ctx.result.statusCode))'), - ), - ), - }); // .dependsOn(ResourceConstants.RESOURCES.GraphQLSchemaLogicalID) - } - - /** - * Create a resolver that makes a PUT request. It allows the user to provide arguments as either query - * parameters or in the body of the request. - * Returns the result in JSON format, or an error if the status code is not 200. - * Forwards the headers from the request, adding that the content type is JSON. - * @param type - */ - public makePutResolver(baseURL: string, path: string, type: string, field: string, nonNullArgs: string[], headers: HttpHeader[]) { - const parsedHeaders = headers.map((header) => qref(`$headers.put("${header.key}", "${header.value}")`)); - - return new AppSync.Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(HttpResourceIDs.HttpDataSourceID(baseURL), 'Name'), - FieldName: field, - TypeName: type, - RequestMappingTemplate: this.replaceEnvAndRegion( - print( - compoundExpression([ - nonNullArgs.length > 0 ? this.makeNonNullChecks(nonNullArgs) : null, - set(ref('headers'), ref('utils.http.copyHeaders($ctx.request.headers)')), - qref('$headers.put("Content-Type", "application/json")'), - qref('$headers.put("accept-encoding", "application/json")'), - ...parsedHeaders, - HttpMappingTemplate.putRequest({ - resourcePath: path, - params: obj({ - body: ref('util.toJson($ctx.args.body)'), - query: ref('util.toJson($ctx.args.query)'), - headers: ref('util.toJson($headers)'), - }), - }), - ]), - ), - ), - ResponseMappingTemplate: print( - ifElse( - raw('$ctx.result.statusCode == 200 || $ctx.result.statusCode == 201'), - ifElse( - ref('ctx.result.headers.get("Content-Type").toLowerCase().contains("xml")'), - ref('utils.xml.toJsonString($ctx.result.body)'), - ref('ctx.result.body'), - ), - ref('util.qr($util.appendError($ctx.result.body, $ctx.result.statusCode))'), - ), - ), - }); // .dependsOn(ResourceConstants.RESOURCES.GraphQLSchemaLogicalID) - } - - /** - * Create a resolver that makes a DELETE request. - * @param type - */ - public makeDeleteResolver(baseURL: string, path: string, type: string, field: string, headers: HttpHeader[]) { - const parsedHeaders = headers.map((header) => qref(`$headers.put("${header.key}", "${header.value}")`)); - - return new AppSync.Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(HttpResourceIDs.HttpDataSourceID(baseURL), 'Name'), - FieldName: field, - TypeName: type, - RequestMappingTemplate: this.replaceEnvAndRegion( - print( - compoundExpression([ - set(ref('headers'), ref('utils.http.copyHeaders($ctx.request.headers)')), - qref('$headers.put("accept-encoding", "application/json")'), - ...parsedHeaders, - HttpMappingTemplate.deleteRequest({ - resourcePath: path, - params: obj({ - headers: ref('util.toJson($headers)'), - }), - }), - ]), - ), - ), - ResponseMappingTemplate: print( - ifElse( - raw('$ctx.result.statusCode == 200'), - ifElse( - ref('ctx.result.headers.get("Content-Type").toLowerCase().contains("xml")'), - ref('utils.xml.toJsonString($ctx.result.body)'), - ref('ctx.result.body'), - ), - ref('util.qr($util.appendError($ctx.result.body, $ctx.result.statusCode))'), - ), - ), - }); // .dependsOn(ResourceConstants.RESOURCES.GraphQLSchemaLogicalID) - } - - /** - * Create a resolver that makes a PUT request. It allows the user to provide arguments as either query - * parameters or in the body of the request. - * Returns the result in JSON format, or an error if the status code is not 200. - * Forwards the headers from the request, adding that the content type is JSON. - * @param type - */ - public makePatchResolver(baseURL: string, path: string, type: string, field: string, nonNullArgs: string[], headers: HttpHeader[]) { - const parsedHeaders = headers.map((header) => qref(`$headers.put("${header.key}", "${header.value}")`)); - - return new AppSync.Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(HttpResourceIDs.HttpDataSourceID(baseURL), 'Name'), - FieldName: field, - TypeName: type, - RequestMappingTemplate: this.replaceEnvAndRegion( - print( - compoundExpression([ - nonNullArgs.length > 0 ? this.makeNonNullChecks(nonNullArgs) : null, - set(ref('headers'), ref('utils.http.copyHeaders($ctx.request.headers)')), - qref('$headers.put("Content-Type", "application/json")'), - qref('$headers.put("accept-encoding", "application/json")'), - ...parsedHeaders, - HttpMappingTemplate.patchRequest({ - resourcePath: path, - params: obj({ - body: ref('util.toJson($ctx.args.body)'), - query: ref('util.toJson($ctx.args.query)'), - headers: ref('util.toJson($headers)'), - }), - }), - ]), - ), - ), - ResponseMappingTemplate: print( - ifElse( - raw('$ctx.result.statusCode == 200 || $ctx.result.statusCode == 201'), - ifElse( - ref('ctx.result.headers.get("Content-Type").toLowerCase().contains("xml")'), - ref('utils.xml.toJsonString($ctx.result.body)'), - ref('ctx.result.body'), - ), - ref('util.qr($util.appendError($ctx.result.body, $ctx.result.statusCode))'), - ), - ), - }); // .dependsOn(ResourceConstants.RESOURCES.GraphQLSchemaLogicalID) - } -} diff --git a/packages/graphql-http-transformer/tsconfig.json b/packages/graphql-http-transformer/tsconfig.json deleted file mode 100644 index f3fc268a32..0000000000 --- a/packages/graphql-http-transformer/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "strict": false, // TODO enable - "rootDir": "src", - "outDir": "lib" - }, - "references": [ - { "path": "../amplify-graphql-directives" }, - { "path": "../graphql-mapping-template" }, - { "path": "../graphql-transformer-common" }, - { "path": "../graphql-transformer-core" } - ] -} diff --git a/packages/graphql-key-transformer/.npmignore b/packages/graphql-key-transformer/.npmignore deleted file mode 100644 index 3ee5d55b0b..0000000000 --- a/packages/graphql-key-transformer/.npmignore +++ /dev/null @@ -1,5 +0,0 @@ -**/__mocks__/** -**/__tests__/** -src -tsconfig.json -tsconfig.tsbuildinfo diff --git a/packages/graphql-key-transformer/API.md b/packages/graphql-key-transformer/API.md deleted file mode 100644 index 115cd18220..0000000000 --- a/packages/graphql-key-transformer/API.md +++ /dev/null @@ -1,31 +0,0 @@ -## API Report File for "graphql-key-transformer" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { DirectiveNode } from 'graphql'; -import { ObjectTypeDefinitionNode } from 'graphql'; -import { Transformer as Transformer_2 } from 'graphql-transformer-core'; -import { TransformerContext } from 'graphql-transformer-core'; - -// @public (undocumented) -export class KeyTransformer extends Transformer_2 { - constructor(); - // (undocumented) - after: (ctx: TransformerContext) => void; - // (undocumented) - appendSecondaryIndex: (definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => void; - // (undocumented) - before: (ctx: TransformerContext) => void; - // (undocumented) - isPrimaryKey: (directive: DirectiveNode) => boolean; - // (undocumented) - object: (definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => void; - // (undocumented) - replacePrimaryKey: (definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => void; -} - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/graphql-key-transformer/CHANGELOG.md b/packages/graphql-key-transformer/CHANGELOG.md deleted file mode 100644 index 3a586dfee2..0000000000 --- a/packages/graphql-key-transformer/CHANGELOG.md +++ /dev/null @@ -1,956 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [3.2.80](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.79...graphql-key-transformer@3.2.80) (2024-07-15) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.79](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.78...graphql-key-transformer@3.2.79) (2024-07-02) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.78](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.77...graphql-key-transformer@3.2.78) (2024-06-25) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.77](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.76...graphql-key-transformer@3.2.77) (2024-04-26) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.76](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.75...graphql-key-transformer@3.2.76) (2024-04-11) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.75](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.74...graphql-key-transformer@3.2.75) (2024-03-28) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.74](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.73...graphql-key-transformer@3.2.74) (2024-02-28) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.73](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.72...graphql-key-transformer@3.2.73) (2024-02-05) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.72](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.71...graphql-key-transformer@3.2.72) (2024-01-22) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.71](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.70...graphql-key-transformer@3.2.71) (2023-12-18) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.70](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.69...graphql-key-transformer@3.2.70) (2023-12-06) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.69](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.68...graphql-key-transformer@3.2.69) (2023-11-18) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.68](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.67...graphql-key-transformer@3.2.68) (2023-11-16) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.67](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.66...graphql-key-transformer@3.2.67) (2023-11-15) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.66](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.65...graphql-key-transformer@3.2.66) (2023-10-21) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.65](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.64...graphql-key-transformer@3.2.65) (2023-08-30) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.64](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.63...graphql-key-transformer@3.2.64) (2023-08-28) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.63](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.62...graphql-key-transformer@3.2.63) (2023-08-09) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.62](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.61...graphql-key-transformer@3.2.62) (2023-07-21) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.61](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.60...graphql-key-transformer@3.2.61) (2023-07-17) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.60](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.59...graphql-key-transformer@3.2.60) (2023-07-07) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.59](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.58...graphql-key-transformer@3.2.59) (2023-07-07) - -### Bug Fixes - -- trigger republish of dependencies that failed in https://app.circleci.com/pipelines/github/aws-amplify/amplify-category-api/7981/workflows/e7366f04-6f0a-4ee4-9cc2-1772089e8005/jobs/163571 ([f2c7151](https://github.com/aws-amplify/amplify-category-api/commit/f2c7151005e4a9fd29d91ac1af1f3e482a06a5cc)) - -## [3.2.58](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.57...graphql-key-transformer@3.2.58) (2023-07-07) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.57](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.56...graphql-key-transformer@3.2.57) (2023-06-29) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.56](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.55...graphql-key-transformer@3.2.56) (2023-06-20) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.55](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.54...graphql-key-transformer@3.2.55) (2023-06-05) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.54](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.53...graphql-key-transformer@3.2.54) (2023-05-23) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.53](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.52...graphql-key-transformer@3.2.53) (2023-05-17) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.52](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.51...graphql-key-transformer@3.2.52) (2023-04-25) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.51](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.50...graphql-key-transformer@3.2.51) (2023-03-30) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.50](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.49...graphql-key-transformer@3.2.50) (2023-03-15) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.49](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.48...graphql-key-transformer@3.2.49) (2023-03-01) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.48](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.47...graphql-key-transformer@3.2.48) (2023-02-27) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.47](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.46...graphql-key-transformer@3.2.47) (2023-01-26) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.46](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.45...graphql-key-transformer@3.2.46) (2023-01-12) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.45](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.44...graphql-key-transformer@3.2.45) (2023-01-12) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.44](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.43...graphql-key-transformer@3.2.44) (2022-12-03) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.43](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.42...graphql-key-transformer@3.2.43) (2022-09-14) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.42](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.40...graphql-key-transformer@3.2.42) (2022-07-20) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.41](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.40...graphql-key-transformer@3.2.41) (2022-07-14) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.40](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.39...graphql-key-transformer@3.2.40) (2022-07-01) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.39](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.38...graphql-key-transformer@3.2.39) (2022-06-23) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.38](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.37...graphql-key-transformer@3.2.38) (2022-06-13) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.37](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.36...graphql-key-transformer@3.2.37) (2022-06-10) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.36](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.35...graphql-key-transformer@3.2.36) (2022-06-10) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.35](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.32...graphql-key-transformer@3.2.35) (2022-06-07) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.34](https://github.com/aws-amplify/amplify-category-api/compare/graphql-key-transformer@3.2.32...graphql-key-transformer@3.2.34) (2022-05-31) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.33](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.32...graphql-key-transformer@3.2.33) (2022-05-02) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.32](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.31...graphql-key-transformer@3.2.32) (2022-04-29) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.31](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.30...graphql-key-transformer@3.2.31) (2022-04-27) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.30](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.29...graphql-key-transformer@3.2.30) (2022-04-11) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.29](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.28...graphql-key-transformer@3.2.29) (2022-04-07) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.28](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.27...graphql-key-transformer@3.2.28) (2022-03-23) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.27](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.26...graphql-key-transformer@3.2.27) (2022-03-17) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.26](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.25...graphql-key-transformer@3.2.26) (2022-03-14) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.24...graphql-key-transformer@3.2.25) (2022-03-07) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.23...graphql-key-transformer@3.2.24) (2022-02-25) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.22...graphql-key-transformer@3.2.23) (2022-02-15) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.18...graphql-key-transformer@3.2.22) (2022-02-10) - -## 7.6.19 (2022-02-08) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.17...graphql-key-transformer@3.2.18) (2022-02-03) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.16...graphql-key-transformer@3.2.17) (2022-01-31) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.15...graphql-key-transformer@3.2.16) (2022-01-27) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.14...graphql-key-transformer@3.2.15) (2022-01-23) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.13...graphql-key-transformer@3.2.14) (2022-01-13) - -### Bug Fixes - -- clean up missing and unused GraphQL v1 dependencies ([#9496](https://github.com/aws-amplify/amplify-cli/issues/9496)) ([fe8201b](https://github.com/aws-amplify/amplify-cli/commit/fe8201be17f42db233fce0bb366ff4d0c8358ec0)) - -## [3.2.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.11...graphql-key-transformer@3.2.13) (2022-01-10) - -## 7.6.7 (2022-01-10) - -### Bug Fixes - -- make update input id field required ([#9452](https://github.com/aws-amplify/amplify-cli/issues/9452)) ([345fe28](https://github.com/aws-amplify/amplify-cli/commit/345fe28a60bbf1de32496430e38e25463a77e96c)) - -## [3.2.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.10...graphql-key-transformer@3.2.11) (2021-12-21) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.9...graphql-key-transformer@3.2.10) (2021-12-17) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.8...graphql-key-transformer@3.2.9) (2021-12-03) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.7...graphql-key-transformer@3.2.8) (2021-12-02) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.6...graphql-key-transformer@3.2.7) (2021-12-01) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.5...graphql-key-transformer@3.2.6) (2021-11-26) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.4...graphql-key-transformer@3.2.5) (2021-11-23) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.3...graphql-key-transformer@3.2.4) (2021-11-21) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.2...graphql-key-transformer@3.2.3) (2021-11-20) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@3.2.1...graphql-key-transformer@3.2.2) (2021-11-17) - -**Note:** Version bump only for package graphql-key-transformer - -## [3.2.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.26...graphql-key-transformer@3.2.1) (2021-11-15) - -**Note:** Version bump only for package graphql-key-transformer - -# [3.0.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.26...graphql-key-transformer@3.0.0) (2021-11-13) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.26](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.25...graphql-key-transformer@2.23.26) (2021-11-11) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.24...graphql-key-transformer@2.23.25) (2021-10-10) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.23...graphql-key-transformer@2.23.24) (2021-10-06) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.22...graphql-key-transformer@2.23.23) (2021-09-27) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.21...graphql-key-transformer@2.23.22) (2021-09-18) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.21](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.20...graphql-key-transformer@2.23.21) (2021-09-14) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.20](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.19...graphql-key-transformer@2.23.20) (2021-09-09) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.19](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.18...graphql-key-transformer@2.23.19) (2021-09-02) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.17...graphql-key-transformer@2.23.18) (2021-08-24) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.16...graphql-key-transformer@2.23.17) (2021-08-06) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.15...graphql-key-transformer@2.23.16) (2021-07-30) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.14...graphql-key-transformer@2.23.15) (2021-07-27) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.13...graphql-key-transformer@2.23.14) (2021-07-16) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.12...graphql-key-transformer@2.23.13) (2021-06-30) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.11...graphql-key-transformer@2.23.12) (2021-06-24) - -### Bug Fixes - -- **graphql-transformer-common:** improve generated graphql pluralization ([#7258](https://github.com/aws-amplify/amplify-cli/issues/7258)) ([fc3ad0d](https://github.com/aws-amplify/amplify-cli/commit/fc3ad0dd5a12a7912c59ae12024f593b4cdf7f2d)), closes [#4224](https://github.com/aws-amplify/amplify-cli/issues/4224) -- validates optional non nullable fields to be not null ([#7170](https://github.com/aws-amplify/amplify-cli/issues/7170)) ([1ca842c](https://github.com/aws-amplify/amplify-cli/commit/1ca842c703bfc34e65bfffff85908ea8b2ccb521)) - -## [2.23.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.10...graphql-key-transformer@2.23.11) (2021-06-15) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.9...graphql-key-transformer@2.23.10) (2021-05-29) - -## 4.51.4 (2021-05-28) - -### Bug Fixes - -- **graphql-model-transformer:** use modelobject key for mutation resolver creation ([#7419](https://github.com/aws-amplify/amplify-cli/issues/7419)) ([37bc551](https://github.com/aws-amplify/amplify-cli/commit/37bc551030d47de993f8227ee3af0ba6cd738ab2)), closes [#i7417](https://github.com/aws-amplify/amplify-cli/issues/i7417) - -## [2.23.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.8...graphql-key-transformer@2.23.9) (2021-05-26) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.7...graphql-key-transformer@2.23.8) (2021-05-18) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.6...graphql-key-transformer@2.23.7) (2021-05-14) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.4...graphql-key-transformer@2.23.6) (2021-05-03) - -## 4.50.1 (2021-05-03) - -### Bug Fixes - -- checking mutations args when defined ([#7200](https://github.com/aws-amplify/amplify-cli/issues/7200)) ([2b59309](https://github.com/aws-amplify/amplify-cli/commit/2b593095a93bcd03663ea5d00ff6dba1e304be2b)) - -## [2.23.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.4...graphql-key-transformer@2.23.5) (2021-05-03) - -### Bug Fixes - -- checking mutations args when defined ([#7200](https://github.com/aws-amplify/amplify-cli/issues/7200)) ([2b59309](https://github.com/aws-amplify/amplify-cli/commit/2b593095a93bcd03663ea5d00ff6dba1e304be2b)) - -## [2.23.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.3...graphql-key-transformer@2.23.4) (2021-04-27) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.2...graphql-key-transformer@2.23.3) (2021-04-19) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.23.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.23.1...graphql-key-transformer@2.23.2) (2021-04-14) - -### Bug Fixes - -- **graphql-key-transformer:** optional id field if id not primary key ([#7005](https://github.com/aws-amplify/amplify-cli/issues/7005)) ([2c972a9](https://github.com/aws-amplify/amplify-cli/commit/2c972a94eb468c191e4b67f1f425e356ab33094c)) - -## [2.23.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.22.3...graphql-key-transformer@2.23.1) (2021-04-09) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.22.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.22.2...graphql-key-transformer@2.22.3) (2021-03-23) - -### Bug Fixes - -- **graphql-key-transformer:** check if lastSync == 0 ([#6859](https://github.com/aws-amplify/amplify-cli/issues/6859)) ([f3b1d1d](https://github.com/aws-amplify/amplify-cli/commit/f3b1d1d66fa2705a6ee73b5732c3919cd77632f7)) - -## [2.22.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.22.1...graphql-key-transformer@2.22.2) (2021-03-11) - -### Bug Fixes - -- gql compiler fix for user defined mutation ([#6059](https://github.com/aws-amplify/amplify-cli/issues/6059)) ([063d84f](https://github.com/aws-amplify/amplify-cli/commit/063d84ff3d31762a4434f3146623132536f4667d)) - -## [2.22.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.22.0...graphql-key-transformer@2.22.1) (2021-03-05) - -**Note:** Version bump only for package graphql-key-transformer - -# [2.22.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.21.3...graphql-key-transformer@2.22.0) (2021-02-26) - -### Features - -- **graphql-key-transformer:** only modify GSI sort key when present ([#6742](https://github.com/aws-amplify/amplify-cli/issues/6742)) ([7cbd396](https://github.com/aws-amplify/amplify-cli/commit/7cbd39632181a5bc323ac3ad3a835a358c74adf6)) - -## [2.21.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.21.2...graphql-key-transformer@2.21.3) (2021-02-24) - -### Bug Fixes - -- **graphql-key-transformer:** fix delta with selective sync query ([#6664](https://github.com/aws-amplify/amplify-cli/issues/6664)) ([c326c9c](https://github.com/aws-amplify/amplify-cli/commit/c326c9ccc4298dd5479b49e222df6f67e7a2947b)) -- **graphql-key-transformer:** fix delta with selective sync query ([#6683](https://github.com/aws-amplify/amplify-cli/issues/6683)) ([e6f0cd4](https://github.com/aws-amplify/amplify-cli/commit/e6f0cd4e8c2f625559da2090c57be598a99d6b0d)) - -## [2.21.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.21.1...graphql-key-transformer@2.21.2) (2021-02-17) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.21.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.21.0...graphql-key-transformer@2.21.1) (2021-02-11) - -**Note:** Version bump only for package graphql-key-transformer - -# [2.21.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.20.4...graphql-key-transformer@2.21.0) (2021-02-10) - -### Features - -- **graphql-key-transformer:** change default to add GSIs when using [@key](https://github.com/key) ([#5648](https://github.com/aws-amplify/amplify-cli/issues/5648)) ([4287c63](https://github.com/aws-amplify/amplify-cli/commit/4287c630295c304c7ff8343922926b4830b75cd4)) - -## [2.20.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.20.3...graphql-key-transformer@2.20.4) (2020-12-16) - -### Bug Fixes - -- **graphql-key-transformer:** prevent non-scalar key fields ([#5319](https://github.com/aws-amplify/amplify-cli/issues/5319)) ([4a5b305](https://github.com/aws-amplify/amplify-cli/commit/4a5b305dd695e61fcbc4ce0ca659b6f5a1c7e467)), closes [#5300](https://github.com/aws-amplify/amplify-cli/issues/5300) -- **graphql-key-transformer:** support sortEnum and filterInput ([#6033](https://github.com/aws-amplify/amplify-cli/issues/6033)) ([1dd373b](https://github.com/aws-amplify/amplify-cli/commit/1dd373b036b765a8bdf3b6e6bb1385519e35ef3d)), closes [#6029](https://github.com/aws-amplify/amplify-cli/issues/6029) - -### Reverts - -- Revert "fix(graphql-key-transformer): prevent non-scalar key fields (#5319)" (#6181) ([c61268d](https://github.com/aws-amplify/amplify-cli/commit/c61268d093571c906c13e7033552503b9fd83a98)), closes [#5319](https://github.com/aws-amplify/amplify-cli/issues/5319) [#6181](https://github.com/aws-amplify/amplify-cli/issues/6181) - -## [2.20.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.20.2...graphql-key-transformer@2.20.3) (2020-12-07) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.20.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.20.1...graphql-key-transformer@2.20.2) (2020-11-30) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.20.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.18...graphql-key-transformer@2.20.1) (2020-11-22) - -**Note:** Version bump only for package graphql-key-transformer - -# [2.20.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.1.7...graphql-key-transformer@2.20.0) (2020-11-22) - -### Bug Fixes - -- sync resolver for mock ([#5684](https://github.com/aws-amplify/amplify-cli/issues/5684)) ([80e2cd4](https://github.com/aws-amplify/amplify-cli/commit/80e2cd44bde1021d4415c6c3b670f44ec1bcae3c)) -- **graphql-dynamodb-transformer:** support model without id ([#4570](https://github.com/aws-amplify/amplify-cli/issues/4570)) ([7cb0648](https://github.com/aws-amplify/amplify-cli/commit/7cb064874d95527882eb58b1a18fa99dd2377ca7)) -- [#1720](https://github.com/aws-amplify/amplify-cli/issues/1720) - fix GraphQL name generation for [@key](https://github.com/key) ([#2093](https://github.com/aws-amplify/amplify-cli/issues/2093)) ([51716f3](https://github.com/aws-amplify/amplify-cli/commit/51716f340e820358087d68fd9e926084c10565eb)) -- [#2033](https://github.com/aws-amplify/amplify-cli/issues/2033) - Make sure key field order is preserved ([#2117](https://github.com/aws-amplify/amplify-cli/issues/2117)) ([58f8f76](https://github.com/aws-amplify/amplify-cli/commit/58f8f76ec2738d65f65568e5f4157d5ada0976c5)) -- [#2239](https://github.com/aws-amplify/amplify-cli/issues/2239) missing proper casing of input type argument ([#2246](https://github.com/aws-amplify/amplify-cli/issues/2246)) ([9d197f1](https://github.com/aws-amplify/amplify-cli/commit/9d197f1f67728935ddfb5c02c5fe53368b010b63)) -- [#2389](https://github.com/aws-amplify/amplify-cli/issues/2389) ([#2538](https://github.com/aws-amplify/amplify-cli/issues/2538)) ([fb92a9d](https://github.com/aws-amplify/amplify-cli/commit/fb92a9d7c6a1f807e49b7f899531de90cc1f4ee3)) -- sort direction argument for lists and queries ([#4459](https://github.com/aws-amplify/amplify-cli/issues/4459)) ([3ada816](https://github.com/aws-amplify/amplify-cli/commit/3ada81686b1cf014dade9cf454fbf624bc7a22cb)) -- **graphql-key-transformer:** add key validation in create ([#4146](https://github.com/aws-amplify/amplify-cli/issues/4146)) ([0e20424](https://github.com/aws-amplify/amplify-cli/commit/0e20424f78876a1e4d8d5e0c80e6f76bcef98f84)), closes [#1756](https://github.com/aws-amplify/amplify-cli/issues/1756) -- [#2711](https://github.com/aws-amplify/amplify-cli/issues/2711) - usage of [@auth](https://github.com/auth) without [@model](https://github.com/model) on fields ([#3590](https://github.com/aws-amplify/amplify-cli/issues/3590)) ([553186e](https://github.com/aws-amplify/amplify-cli/commit/553186e53050cafdf27120443d176023ef4acebc)) -- sanitize input in transformer resolver([#3316](https://github.com/aws-amplify/amplify-cli/issues/3316)) ([a3bc0a5](https://github.com/aws-amplify/amplify-cli/commit/a3bc0a5e5d3faa7946d16d0f6595ce8c2f3c11dc)) -- **graphql-key-transformer:** fix merge errors ([#2762](https://github.com/aws-amplify/amplify-cli/issues/2762)) ([edf4c76](https://github.com/aws-amplify/amplify-cli/commit/edf4c76aae130f300f520787168db7cd2782c324)) -- **graphql-key-transformer:** update deleteInput logic to hadle ID ([2856c9e](https://github.com/aws-amplify/amplify-cli/commit/2856c9e72be1e9ac8d5be33a44dc26e893f29ee0)) -- build break after recent merges ([#2758](https://github.com/aws-amplify/amplify-cli/issues/2758)) ([7155787](https://github.com/aws-amplify/amplify-cli/commit/7155787d74306e9708fe7115648ab6f702dc2093)) -- build break, chore: typescript, lerna update ([#2640](https://github.com/aws-amplify/amplify-cli/issues/2640)) ([29fae36](https://github.com/aws-amplify/amplify-cli/commit/29fae366f4cab054feefa58c7dc733002d19570c)) -- export Typescript definitions and fix resulting type errors ([#2452](https://github.com/aws-amplify/amplify-cli/issues/2452)) ([7de3845](https://github.com/aws-amplify/amplify-cli/commit/7de384594d3b9cbf22cdaa85107fc8df26c141ec)), closes [#2451](https://github.com/aws-amplify/amplify-cli/issues/2451) -- the KeyTransformer class name was incorrect ([#2346](https://github.com/aws-amplify/amplify-cli/issues/2346)) ([b54ef02](https://github.com/aws-amplify/amplify-cli/commit/b54ef02b18976b8457612225aa5e67cc2a805636)) -- **graphql-key-transformer:** added sort direction ([a0f9f30](https://github.com/aws-amplify/amplify-cli/commit/a0f9f30d4141f3574f34cd5d7183471044b12935)), closes [#1676](https://github.com/aws-amplify/amplify-cli/issues/1676) -- **graphql-key-transformer:** key req resolver edit ([c4a9da5](https://github.com/aws-amplify/amplify-cli/commit/c4a9da51b2db2d411fcb016934ffdd8e8425313c)), closes [#1676](https://github.com/aws-amplify/amplify-cli/issues/1676) [#1990](https://github.com/aws-amplify/amplify-cli/issues/1990) [#1629](https://github.com/aws-amplify/amplify-cli/issues/1629) - -### Features - -- **amplify-category-api:** change default graphql query limit to 100 ([#4124](https://github.com/aws-amplify/amplify-cli/issues/4124)) ([1a68c4d](https://github.com/aws-amplify/amplify-cli/commit/1a68c4d589e2101357dec4e980719fc547964e23)) -- **graphql-dynamodb-transformer:** expose createdAt and updatedAt on model ([#4149](https://github.com/aws-amplify/amplify-cli/issues/4149)) ([8e0662e](https://github.com/aws-amplify/amplify-cli/commit/8e0662eac8c88da9393f32c33457a597acf591ed)), closes [#401](https://github.com/aws-amplify/amplify-cli/issues/401) -- **graphql-key-transformer:** add query automatically for named keys ([#4458](https://github.com/aws-amplify/amplify-cli/issues/4458)) ([375282d](https://github.com/aws-amplify/amplify-cli/commit/375282d648cf9d096d13c7b958a0dfb7bd6d60b0)) -- **graphql-key-transformer:** auto population of id and timestamp ([#4382](https://github.com/aws-amplify/amplify-cli/issues/4382)) ([6586611](https://github.com/aws-amplify/amplify-cli/commit/6586611293a07db9959247ff82f95542a239ff1f)) -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c1927da10f8c54f38a523021187361131c)) -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e5346ee1f27a2e9bee25fbbdcb19417f5230f)) -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe8925a4e73358b03ba927267a2df328b78)) - -### Reverts - -- add query automatically for named keys ([#4513](https://github.com/aws-amplify/amplify-cli/issues/4513)) ([50c1120](https://github.com/aws-amplify/amplify-cli/commit/50c112050645b8fd5011a1e6863d30f58e0c55cb)) - -## [2.19.21](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.18...graphql-key-transformer@2.19.21) (2020-11-20) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.19.20](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.18...graphql-key-transformer@2.19.20) (2020-11-20) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.19.19](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.18...graphql-key-transformer@2.19.19) (2020-11-19) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.19.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.17...graphql-key-transformer@2.19.18) (2020-11-08) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.19.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.16...graphql-key-transformer@2.19.17) (2020-10-30) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.19.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.15...graphql-key-transformer@2.19.16) (2020-10-27) - -### Bug Fixes - -- sync resolver for mock ([#5684](https://github.com/aws-amplify/amplify-cli/issues/5684)) ([80e2cd4](https://github.com/aws-amplify/amplify-cli/commit/80e2cd44bde1021d4415c6c3b670f44ec1bcae3c)) - -## [2.19.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.14...graphql-key-transformer@2.19.15) (2020-10-22) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.19.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.13...graphql-key-transformer@2.19.14) (2020-10-17) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.19.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.12...graphql-key-transformer@2.19.13) (2020-10-01) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.19.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.11...graphql-key-transformer@2.19.12) (2020-09-16) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.19.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.10...graphql-key-transformer@2.19.11) (2020-09-02) - -### Bug Fixes - -- **graphql-dynamodb-transformer:** support model without id ([#4570](https://github.com/aws-amplify/amplify-cli/issues/4570)) ([7cb0648](https://github.com/aws-amplify/amplify-cli/commit/7cb064874d95527882eb58b1a18fa99dd2377ca7)) - -## [2.19.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.9...graphql-key-transformer@2.19.10) (2020-08-31) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.19.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.8...graphql-key-transformer@2.19.9) (2020-08-14) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.19.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.7...graphql-key-transformer@2.19.8) (2020-08-11) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.19.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.5...graphql-key-transformer@2.19.7) (2020-07-29) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.19.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.5...graphql-key-transformer@2.19.6) (2020-07-23) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.19.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.4...graphql-key-transformer@2.19.5) (2020-07-18) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.19.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.3...graphql-key-transformer@2.19.4) (2020-07-15) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.19.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.2...graphql-key-transformer@2.19.3) (2020-06-25) - -### Reverts - -- Revert "fix: change scope of hashed files for AppSync (#4602)" ([73aaab1](https://github.com/aws-amplify/amplify-cli/commit/73aaab1a7b1f8b2de5fa22fa1ef9aeea7de35cb4)), closes [#4602](https://github.com/aws-amplify/amplify-cli/issues/4602) - -## [2.19.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.1...graphql-key-transformer@2.19.2) (2020-06-18) - -### Bug Fixes - -- change scope of hashed files for AppSync ([#4602](https://github.com/aws-amplify/amplify-cli/issues/4602)) ([10fa9da](https://github.com/aws-amplify/amplify-cli/commit/10fa9da646f4de755e2dc92cd4bb2a6319425d72)), closes [#4458](https://github.com/aws-amplify/amplify-cli/issues/4458) - -## [2.19.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.19.0...graphql-key-transformer@2.19.1) (2020-06-11) - -### Reverts - -- add query automatically for named keys ([#4513](https://github.com/aws-amplify/amplify-cli/issues/4513)) ([6d3123b](https://github.com/aws-amplify/amplify-cli/commit/6d3123bfe3ba412d3b1af076e550e6733c988c8f)) - -# [2.19.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.18.0...graphql-key-transformer@2.19.0) (2020-06-10) - -### Bug Fixes - -- sort direction argument for lists and queries ([#4459](https://github.com/aws-amplify/amplify-cli/issues/4459)) ([6be33e1](https://github.com/aws-amplify/amplify-cli/commit/6be33e16a8a8ba52cbf717d4e299d7321d9ad400)) - -### Features - -- **graphql-key-transformer:** add query automatically for named keys ([#4458](https://github.com/aws-amplify/amplify-cli/issues/4458)) ([3d194f8](https://github.com/aws-amplify/amplify-cli/commit/3d194f805dcbd6325ddf78155c4327dbca3e7f4a)) - -# [2.18.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.17.1...graphql-key-transformer@2.18.0) (2020-06-02) - -### Features - -- **graphql-key-transformer:** auto population of id and timestamp ([#4382](https://github.com/aws-amplify/amplify-cli/issues/4382)) ([c0a4f88](https://github.com/aws-amplify/amplify-cli/commit/c0a4f8889fc363bb9c9d08ff822c591874777f7b)) - -## [2.17.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.17.0...graphql-key-transformer@2.17.1) (2020-05-26) - -**Note:** Version bump only for package graphql-key-transformer - -# [2.17.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.16.0...graphql-key-transformer@2.17.0) (2020-05-15) - -### Bug Fixes - -- **graphql-key-transformer:** add key validation in create ([#4146](https://github.com/aws-amplify/amplify-cli/issues/4146)) ([0e20424](https://github.com/aws-amplify/amplify-cli/commit/0e20424f78876a1e4d8d5e0c80e6f76bcef98f84)), closes [#1756](https://github.com/aws-amplify/amplify-cli/issues/1756) - -### Features - -- **graphql-dynamodb-transformer:** expose createdAt and updatedAt on model ([#4149](https://github.com/aws-amplify/amplify-cli/issues/4149)) ([8e0662e](https://github.com/aws-amplify/amplify-cli/commit/8e0662eac8c88da9393f32c33457a597acf591ed)), closes [#401](https://github.com/aws-amplify/amplify-cli/issues/401) - -# [2.16.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.15.3...graphql-key-transformer@2.16.0) (2020-05-08) - -### Features - -- **amplify-category-api:** change default graphql query limit to 100 ([#4124](https://github.com/aws-amplify/amplify-cli/issues/4124)) ([1a68c4d](https://github.com/aws-amplify/amplify-cli/commit/1a68c4d589e2101357dec4e980719fc547964e23)) - -## [2.15.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.15.2...graphql-key-transformer@2.15.3) (2020-04-23) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.15.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.15.1...graphql-key-transformer@2.15.2) (2020-03-22) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.15.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.13.4...graphql-key-transformer@2.15.1) (2020-03-07) - -### Bug Fixes - -- [#2711](https://github.com/aws-amplify/amplify-cli/issues/2711) - usage of [@auth](https://github.com/auth) without [@model](https://github.com/model) on fields ([#3590](https://github.com/aws-amplify/amplify-cli/issues/3590)) ([553186e](https://github.com/aws-amplify/amplify-cli/commit/553186e53050cafdf27120443d176023ef4acebc)) - -## [2.14.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.13.6-beta.0...graphql-key-transformer@2.14.1) (2020-03-05) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.13.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.13.3...graphql-key-transformer@2.13.4) (2020-02-18) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.13.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.13.2...graphql-key-transformer@2.13.3) (2020-02-13) - -**Note:** Version bump only for package graphql-key-transformer - -## [2.13.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.13.1...graphql-key-transformer@2.13.2) (2020-02-07) - -### Bug Fixes - -- sanitize input in transformer resolver([#3316](https://github.com/aws-amplify/amplify-cli/issues/3316)) ([a3bc0a5](https://github.com/aws-amplify/amplify-cli/commit/a3bc0a5e5d3faa7946d16d0f6595ce8c2f3c11dc)) - -## [2.13.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@2.13.0...graphql-key-transformer@2.13.1) (2020-01-24) - -**Note:** Version bump only for package graphql-key-transformer - -# [2.13.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.25.0...graphql-key-transformer@2.13.0) (2020-01-23) - -### Bug Fixes - -- build break after recent merges ([#2758](https://github.com/aws-amplify/amplify-cli/issues/2758)) ([7155787](https://github.com/aws-amplify/amplify-cli/commit/7155787d74306e9708fe7115648ab6f702dc2093)) -- **graphql-key-transformer:** fix merge errors ([#2762](https://github.com/aws-amplify/amplify-cli/issues/2762)) ([edf4c76](https://github.com/aws-amplify/amplify-cli/commit/edf4c76aae130f300f520787168db7cd2782c324)) -- **graphql-key-transformer:** update deleteInput logic to hadle ID ([2856c9e](https://github.com/aws-amplify/amplify-cli/commit/2856c9e72be1e9ac8d5be33a44dc26e893f29ee0)) - -### Features - -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [2.12.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.25.0...graphql-key-transformer@2.12.0) (2020-01-09) - -### Bug Fixes - -- build break after recent merges ([#2758](https://github.com/aws-amplify/amplify-cli/issues/2758)) ([7155787](https://github.com/aws-amplify/amplify-cli/commit/7155787d74306e9708fe7115648ab6f702dc2093)) -- **graphql-key-transformer:** fix merge errors ([#2762](https://github.com/aws-amplify/amplify-cli/issues/2762)) ([edf4c76](https://github.com/aws-amplify/amplify-cli/commit/edf4c76aae130f300f520787168db7cd2782c324)) -- **graphql-key-transformer:** update deleteInput logic to hadle ID ([2856c9e](https://github.com/aws-amplify/amplify-cli/commit/2856c9e72be1e9ac8d5be33a44dc26e893f29ee0)) - -### Features - -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [2.11.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.25.0...graphql-key-transformer@2.11.0) (2019-12-31) - -### Bug Fixes - -- build break after recent merges ([#2758](https://github.com/aws-amplify/amplify-cli/issues/2758)) ([7155787](https://github.com/aws-amplify/amplify-cli/commit/7155787d74306e9708fe7115648ab6f702dc2093)) -- **graphql-key-transformer:** fix merge errors ([#2762](https://github.com/aws-amplify/amplify-cli/issues/2762)) ([edf4c76](https://github.com/aws-amplify/amplify-cli/commit/edf4c76aae130f300f520787168db7cd2782c324)) -- **graphql-key-transformer:** update deleteInput logic to hadle ID ([2856c9e](https://github.com/aws-amplify/amplify-cli/commit/2856c9e72be1e9ac8d5be33a44dc26e893f29ee0)) - -### Features - -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [2.10.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.25.0...graphql-key-transformer@2.10.0) (2019-12-28) - -### Bug Fixes - -- build break after recent merges ([#2758](https://github.com/aws-amplify/amplify-cli/issues/2758)) ([7155787](https://github.com/aws-amplify/amplify-cli/commit/7155787d74306e9708fe7115648ab6f702dc2093)) -- **graphql-key-transformer:** fix merge errors ([#2762](https://github.com/aws-amplify/amplify-cli/issues/2762)) ([edf4c76](https://github.com/aws-amplify/amplify-cli/commit/edf4c76aae130f300f520787168db7cd2782c324)) -- **graphql-key-transformer:** update deleteInput logic to hadle ID ([2856c9e](https://github.com/aws-amplify/amplify-cli/commit/2856c9e72be1e9ac8d5be33a44dc26e893f29ee0)) - -### Features - -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [2.9.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.25.0...graphql-key-transformer@2.9.0) (2019-12-26) - -### Bug Fixes - -- build break after recent merges ([#2758](https://github.com/aws-amplify/amplify-cli/issues/2758)) ([7155787](https://github.com/aws-amplify/amplify-cli/commit/7155787d74306e9708fe7115648ab6f702dc2093)) -- **graphql-key-transformer:** fix merge errors ([#2762](https://github.com/aws-amplify/amplify-cli/issues/2762)) ([edf4c76](https://github.com/aws-amplify/amplify-cli/commit/edf4c76aae130f300f520787168db7cd2782c324)) -- **graphql-key-transformer:** update deleteInput logic to hadle ID ([2856c9e](https://github.com/aws-amplify/amplify-cli/commit/2856c9e72be1e9ac8d5be33a44dc26e893f29ee0)) - -### Features - -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [2.8.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.25.0...graphql-key-transformer@2.8.0) (2019-12-25) - -### Bug Fixes - -- build break after recent merges ([#2758](https://github.com/aws-amplify/amplify-cli/issues/2758)) ([7155787](https://github.com/aws-amplify/amplify-cli/commit/7155787d74306e9708fe7115648ab6f702dc2093)) -- **graphql-key-transformer:** fix merge errors ([#2762](https://github.com/aws-amplify/amplify-cli/issues/2762)) ([edf4c76](https://github.com/aws-amplify/amplify-cli/commit/edf4c76aae130f300f520787168db7cd2782c324)) -- **graphql-key-transformer:** update deleteInput logic to hadle ID ([2856c9e](https://github.com/aws-amplify/amplify-cli/commit/2856c9e72be1e9ac8d5be33a44dc26e893f29ee0)) - -### Features - -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [2.7.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.25.0...graphql-key-transformer@2.7.0) (2019-12-20) - -### Bug Fixes - -- build break after recent merges ([#2758](https://github.com/aws-amplify/amplify-cli/issues/2758)) ([7155787](https://github.com/aws-amplify/amplify-cli/commit/7155787d74306e9708fe7115648ab6f702dc2093)) -- **graphql-key-transformer:** fix merge errors ([#2762](https://github.com/aws-amplify/amplify-cli/issues/2762)) ([edf4c76](https://github.com/aws-amplify/amplify-cli/commit/edf4c76aae130f300f520787168db7cd2782c324)) -- **graphql-key-transformer:** update deleteInput logic to hadle ID ([2856c9e](https://github.com/aws-amplify/amplify-cli/commit/2856c9e72be1e9ac8d5be33a44dc26e893f29ee0)) - -### Features - -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [2.6.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.25.0...graphql-key-transformer@2.6.0) (2019-12-10) - -### Bug Fixes - -- build break after recent merges ([#2758](https://github.com/aws-amplify/amplify-cli/issues/2758)) ([7155787](https://github.com/aws-amplify/amplify-cli/commit/7155787d74306e9708fe7115648ab6f702dc2093)) -- **graphql-key-transformer:** fix merge errors ([#2762](https://github.com/aws-amplify/amplify-cli/issues/2762)) ([edf4c76](https://github.com/aws-amplify/amplify-cli/commit/edf4c76aae130f300f520787168db7cd2782c324)) -- **graphql-key-transformer:** update deleteInput logic to hadle ID ([2856c9e](https://github.com/aws-amplify/amplify-cli/commit/2856c9e72be1e9ac8d5be33a44dc26e893f29ee0)) - -### Features - -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [2.4.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.25.0...graphql-key-transformer@2.4.0) (2019-12-03) - -### Bug Fixes - -- build break after recent merges ([#2758](https://github.com/aws-amplify/amplify-cli/issues/2758)) ([7155787](https://github.com/aws-amplify/amplify-cli/commit/7155787d74306e9708fe7115648ab6f702dc2093)) -- **graphql-key-transformer:** fix merge errors ([#2762](https://github.com/aws-amplify/amplify-cli/issues/2762)) ([edf4c76](https://github.com/aws-amplify/amplify-cli/commit/edf4c76aae130f300f520787168db7cd2782c324)) -- **graphql-key-transformer:** update deleteInput logic to hadle ID ([2856c9e](https://github.com/aws-amplify/amplify-cli/commit/2856c9e72be1e9ac8d5be33a44dc26e893f29ee0)) - -### Features - -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [2.3.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.25.0...graphql-key-transformer@2.3.0) (2019-12-01) - -### Bug Fixes - -- build break after recent merges ([#2758](https://github.com/aws-amplify/amplify-cli/issues/2758)) ([7155787](https://github.com/aws-amplify/amplify-cli/commit/7155787d74306e9708fe7115648ab6f702dc2093)) -- **graphql-key-transformer:** fix merge errors ([#2762](https://github.com/aws-amplify/amplify-cli/issues/2762)) ([edf4c76](https://github.com/aws-amplify/amplify-cli/commit/edf4c76aae130f300f520787168db7cd2782c324)) -- **graphql-key-transformer:** update deleteInput logic to hadle ID ([2856c9e](https://github.com/aws-amplify/amplify-cli/commit/2856c9e72be1e9ac8d5be33a44dc26e893f29ee0)) - -### Features - -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [2.2.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.25.0...graphql-key-transformer@2.2.0) (2019-11-27) - -### Bug Fixes - -- build break after recent merges ([#2758](https://github.com/aws-amplify/amplify-cli/issues/2758)) ([7155787](https://github.com/aws-amplify/amplify-cli/commit/7155787d74306e9708fe7115648ab6f702dc2093)) -- **graphql-key-transformer:** fix merge errors ([#2762](https://github.com/aws-amplify/amplify-cli/issues/2762)) ([edf4c76](https://github.com/aws-amplify/amplify-cli/commit/edf4c76aae130f300f520787168db7cd2782c324)) -- **graphql-key-transformer:** update deleteInput logic to hadle ID ([2856c9e](https://github.com/aws-amplify/amplify-cli/commit/2856c9e72be1e9ac8d5be33a44dc26e893f29ee0)) - -### Features - -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [2.1.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.25.0...graphql-key-transformer@2.1.0) (2019-11-27) - -### Bug Fixes - -- build break after recent merges ([#2758](https://github.com/aws-amplify/amplify-cli/issues/2758)) ([7155787](https://github.com/aws-amplify/amplify-cli/commit/7155787d74306e9708fe7115648ab6f702dc2093)) -- **graphql-key-transformer:** fix merge errors ([#2762](https://github.com/aws-amplify/amplify-cli/issues/2762)) ([edf4c76](https://github.com/aws-amplify/amplify-cli/commit/edf4c76aae130f300f520787168db7cd2782c324)) -- **graphql-key-transformer:** update deleteInput logic to hadle ID ([2856c9e](https://github.com/aws-amplify/amplify-cli/commit/2856c9e72be1e9ac8d5be33a44dc26e893f29ee0)) - -### Features - -- resolver changes ([#2760](https://github.com/aws-amplify/amplify-cli/issues/2760)) ([8ce0d12](https://github.com/aws-amplify/amplify-cli/commit/8ce0d12eb1d3bd6d0132baca39b6e9daff04c39a)) - -# [1.7.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.1.7...graphql-key-transformer@1.7.0) (2019-08-30) - -### Bug Fixes - -- **graphql-key-transformer:** added sort direction ([a0f9f30](https://github.com/aws-amplify/amplify-cli/commit/a0f9f30)), closes [#1676](https://github.com/aws-amplify/amplify-cli/issues/1676) -- **graphql-key-transformer:** key req resolver edit ([c4a9da5](https://github.com/aws-amplify/amplify-cli/commit/c4a9da5)), closes [#1676](https://github.com/aws-amplify/amplify-cli/issues/1676) [#1990](https://github.com/aws-amplify/amplify-cli/issues/1990) [#1629](https://github.com/aws-amplify/amplify-cli/issues/1629) -- [#1720](https://github.com/aws-amplify/amplify-cli/issues/1720) - fix GraphQL name generation for [@key](https://github.com/key) ([#2093](https://github.com/aws-amplify/amplify-cli/issues/2093)) ([51716f3](https://github.com/aws-amplify/amplify-cli/commit/51716f3)) -- [#2033](https://github.com/aws-amplify/amplify-cli/issues/2033) - Make sure key field order is preserved ([#2117](https://github.com/aws-amplify/amplify-cli/issues/2117)) ([58f8f76](https://github.com/aws-amplify/amplify-cli/commit/58f8f76)) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e534)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [1.6.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.1.7...graphql-key-transformer@1.6.0) (2019-08-28) - -### Bug Fixes - -- **graphql-key-transformer:** added sort direction ([a0f9f30](https://github.com/aws-amplify/amplify-cli/commit/a0f9f30)), closes [#1676](https://github.com/aws-amplify/amplify-cli/issues/1676) -- **graphql-key-transformer:** key req resolver edit ([c4a9da5](https://github.com/aws-amplify/amplify-cli/commit/c4a9da5)), closes [#1676](https://github.com/aws-amplify/amplify-cli/issues/1676) [#1990](https://github.com/aws-amplify/amplify-cli/issues/1990) [#1629](https://github.com/aws-amplify/amplify-cli/issues/1629) -- [#1720](https://github.com/aws-amplify/amplify-cli/issues/1720) - fix GraphQL name generation for [@key](https://github.com/key) ([#2093](https://github.com/aws-amplify/amplify-cli/issues/2093)) ([51716f3](https://github.com/aws-amplify/amplify-cli/commit/51716f3)) -- [#2033](https://github.com/aws-amplify/amplify-cli/issues/2033) - Make sure key field order is preserved ([#2117](https://github.com/aws-amplify/amplify-cli/issues/2117)) ([58f8f76](https://github.com/aws-amplify/amplify-cli/commit/58f8f76)) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e534)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [1.5.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.1.7...graphql-key-transformer@1.5.0) (2019-08-13) - -### Bug Fixes - -- **graphql-key-transformer:** added sort direction ([a0f9f30](https://github.com/aws-amplify/amplify-cli/commit/a0f9f30)), closes [#1676](https://github.com/aws-amplify/amplify-cli/issues/1676) -- **graphql-key-transformer:** key req resolver edit ([c4a9da5](https://github.com/aws-amplify/amplify-cli/commit/c4a9da5)), closes [#1676](https://github.com/aws-amplify/amplify-cli/issues/1676) [#1990](https://github.com/aws-amplify/amplify-cli/issues/1990) [#1629](https://github.com/aws-amplify/amplify-cli/issues/1629) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e534)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [1.4.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.1.7...graphql-key-transformer@1.4.0) (2019-08-07) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e534)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [1.3.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.1.7...graphql-key-transformer@1.3.0) (2019-08-02) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [1.2.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.1.7...graphql-key-transformer@1.2.0) (2019-07-31) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -## [1.1.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.1.6...graphql-key-transformer@1.1.7) (2019-07-24) - -**Note:** Version bump only for package graphql-key-transformer - -## [1.1.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.1.4...graphql-key-transformer@1.1.6) (2019-06-30) - -**Note:** Version bump only for package graphql-key-transformer - -## [1.1.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.1.3...graphql-key-transformer@1.1.4) (2019-06-26) - -### Bug Fixes - -- **graphql-key-transformer:** Fix type resolve for 2 field [@key](https://github.com/key) when second field is an Enum ([#1619](https://github.com/aws-amplify/amplify-cli/issues/1619)) ([bbd82b0](https://github.com/aws-amplify/amplify-cli/commit/bbd82b0)), closes [#1572](https://github.com/aws-amplify/amplify-cli/issues/1572) - -## [1.1.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.1.2...graphql-key-transformer@1.1.3) (2019-06-12) - -**Note:** Version bump only for package graphql-key-transformer - -## [1.1.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.1.1...graphql-key-transformer@1.1.2) (2019-06-11) - -### Bug Fixes - -- **graphql-key-transformer:** 1587 bug fix ([3a04e19](https://github.com/aws-amplify/amplify-cli/commit/3a04e19)), closes [#1587](https://github.com/aws-amplify/amplify-cli/issues/1587) - -## [1.1.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-key-transformer@1.1.0...graphql-key-transformer@1.1.1) (2019-06-06) - -### Bug Fixes - -- **graphql-key-transformer:** update filter to emit JSON for filter expression([#1580](https://github.com/aws-amplify/amplify-cli/issues/1580)) ([8c9a3cd](https://github.com/aws-amplify/amplify-cli/commit/8c9a3cd)), closes [#1554](https://github.com/aws-amplify/amplify-cli/issues/1554) - -# 1.1.0 (2019-05-29) - -### Features - -- feature/[@key](https://github.com/key) ([#1463](https://github.com/aws-amplify/amplify-cli/issues/1463)) ([00ed819](https://github.com/aws-amplify/amplify-cli/commit/00ed819)) diff --git a/packages/graphql-key-transformer/package.json b/packages/graphql-key-transformer/package.json deleted file mode 100644 index dc78197a5c..0000000000 --- a/packages/graphql-key-transformer/package.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "name": "graphql-key-transformer", - "version": "3.2.80", - "description": "Implements the @key directive.", - "repository": { - "type": "git", - "url": "https://github.com/aws-amplify/amplify-category-api.git", - "directory": "packages/graphql-key-transformer" - }, - "author": "Amazon Web Services", - "license": "Apache-2.0", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "keywords": [ - "graphql", - "appsync", - "aws" - ], - "scripts": { - "test": "jest", - "build": "tsc", - "clean": "rimraf ./lib", - "extract-api": "ts-node ../../scripts/extract-api.ts" - }, - "dependencies": { - "cloudform-types": "^4.2.0", - "graphql": "^15.5.0", - "graphql-dynamodb-transformer": "7.2.80", - "graphql-mapping-template": "4.20.16", - "graphql-transformer-common": "4.31.1", - "graphql-transformer-core": "8.2.13", - "lodash": "^4.17.21" - }, - "jest": { - "testURL": "http://localhost", - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, - "testRegex": "(src/__tests__/.*.test.ts)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], - "collectCoverage": true, - "coverageProvider": "v8", - "coverageThreshold": { - "global": { - "branches": 90, - "functions": 90, - "lines": 90 - } - }, - "coverageReporters": [ - "clover", - "text" - ], - "collectCoverageFrom": [ - "src/**/*.ts" - ], - "coveragePathIgnorePatterns": [ - "/__tests__/" - ] - } -} diff --git a/packages/graphql-key-transformer/src/KeyTransformer.ts b/packages/graphql-key-transformer/src/KeyTransformer.ts deleted file mode 100644 index ac53778892..0000000000 --- a/packages/graphql-key-transformer/src/KeyTransformer.ts +++ /dev/null @@ -1,1330 +0,0 @@ -import { Transformer, TransformerContext, getDirectiveArguments, InvalidDirectiveError } from 'graphql-transformer-core'; -import { KeyDirectiveV1 } from '@aws-amplify/graphql-directives'; -import { - obj, - str, - ref, - printBlock, - compoundExpression, - raw, - qref, - set, - Expression, - print, - ifElse, - iff, - block, - bool, - forEach, - list, - and, - nul, - RESOLVER_VERSION_ID, - DynamoDBMappingTemplate, -} from 'graphql-mapping-template'; -import { - ResolverResourceIDs, - ResourceConstants, - isNonNullType, - attributeTypeFromScalar, - ModelResourceIDs, - makeInputValueDefinition, - wrapNonNull, - withNamedNodeNamed, - blankObject, - makeNonNullType, - makeNamedType, - getBaseType, - makeConnectionField, - makeScalarKeyConditionForType, - applyKeyExpressionForCompositeKey, - makeCompositeKeyConditionInputForKey, - makeCompositeKeyInputForKey, - toCamelCase, - graphqlName, - toUpper, - getDirectiveArgument, - unwrapNonNull, -} from 'graphql-transformer-common'; -import { - makeModelConnectionType, - makeModelSortDirectionEnumObject, - makeScalarFilterInputs, - makeEnumFilterInputObjects, - makeModelXFilterInputObject, - makeAttributeTypeEnum, - CONDITIONS_MINIMUM_VERSION, -} from 'graphql-dynamodb-transformer'; -import { - ObjectTypeDefinitionNode, - FieldDefinitionNode, - DirectiveNode, - InputObjectTypeDefinitionNode, - TypeNode, - Kind, - InputValueDefinitionNode, - EnumTypeDefinitionNode, - parse, -} from 'graphql'; -import { AppSync, Fn, Refs } from 'cloudform-types'; -import { Projection, GlobalSecondaryIndex, LocalSecondaryIndex } from 'cloudform-types/types/dynamoDb/table'; -import _ from 'lodash'; - -interface KeyArguments { - name?: string; - fields: string[]; - queryField?: string; -} - -export class KeyTransformer extends Transformer { - constructor() { - // prettier-ignore - super( - 'KeyTransformer', - parse(KeyDirectiveV1.definition), - ); - } - - public before = (ctx: TransformerContext): void => { - // generate a Map for the (resolver , VTLExpression) - if (ctx.isProjectUsingDataStore()) { - const resolverMap: Map = new Map(); - ctx.metadata.set(ResourceConstants.SNIPPETS.SyncResolverKey, resolverMap); - } - }; - - public after = (ctx: TransformerContext): void => { - // construct sync VTL code - if (ctx.isProjectUsingDataStore()) { - const resolverMap = ctx.metadata.get(ResourceConstants.SNIPPETS.SyncResolverKey); - if (resolverMap.size) { - resolverMap.forEach((syncVTLContent, resource) => { - if (syncVTLContent) { - resource.Properties.RequestMappingTemplate = ''; - resource.Properties.RequestMappingTemplate = joinSnippets([ - print(generateSyncResolverInit()), - syncVTLContent, - print(setSyncQueryFilterSnippet()), - print(setSyncKeyExpressionForHashKey(ResourceConstants.SNIPPETS.ModelQueryExpression)), - print(setSyncKeyExpressionForRangeKey(ResourceConstants.SNIPPETS.ModelQueryExpression)), - print(makeSyncQueryResolver()), - ]); - } - }); - } - } - }; - - /** - * Augment the table key structures based on the @key. - */ - object = (definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => { - this.validate(definition, directive, ctx); - this.updateIndexStructures(definition, directive, ctx); - this.updateSchema(definition, directive, ctx); - this.updateResolvers(definition, directive, ctx); - this.addKeyConditionInputs(definition, directive, ctx); - // Update ModelXConditionInput type - this.updateMutationConditionInput(ctx, definition, directive); - }; - - /** - * Update the existing @model table's index structures. Includes primary key, GSI, and LSIs. - * @param definition The object type definition node. - * @param directive The @key directive - * @param ctx The transformer context - */ - private updateIndexStructures = (definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => { - if (this.isPrimaryKey(directive)) { - // Set the table's primary key using the @key definition. - this.replacePrimaryKey(definition, directive, ctx); - } else { - // Append a GSI/LSI to the table configuration. - this.appendSecondaryIndex(definition, directive, ctx); - } - }; - - /** - * Update the structural components of the schema that are relevant to the new index structures. - * - * Updates: - * 1. getX with new primary key information. - * 2. listX with new primary key information. - * - * Creates: - * 1. A query field for each secondary index. - */ - private updateSchema = (definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => { - this.updateQueryFields(definition, directive, ctx); - this.updateInputObjects(definition, directive, ctx); - const isPrimaryKey = this.isPrimaryKey(directive); - if (isPrimaryKey) { - this.removeAutoCreatedPrimaryKey(definition, directive, ctx); - } - }; - - /** - * Update the get, list, create, update, and delete resolvers with updated key information. - */ - private updateResolvers = (definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => { - const directiveArgs: KeyArguments = getDirectiveArguments(directive); - const getResolver = ctx.getResource(ResolverResourceIDs.DynamoDBGetResolverResourceID(definition.name.value)); - const listResolver = ctx.getResource(ResolverResourceIDs.DynamoDBListResolverResourceID(definition.name.value)); - const createResolver = ctx.getResource(ResolverResourceIDs.DynamoDBCreateResolverResourceID(definition.name.value)); - const updateResolver = ctx.getResource(ResolverResourceIDs.DynamoDBUpdateResolverResourceID(definition.name.value)); - const deleteResolver = ctx.getResource(ResolverResourceIDs.DynamoDBDeleteResolverResourceID(definition.name.value)); - // update sync resolver if @key directive is present - const syncResolver = ctx.getResource(ResolverResourceIDs.SyncResolverResourceID(definition.name.value)); - if (this.isPrimaryKey(directive)) { - // When looking at a primary key we update the primary paths for writing/reading data. - // and ensure any composite sort keys for the primary index. - if (getResolver) { - getResolver.Properties.RequestMappingTemplate = joinSnippets([ - this.setKeySnippet(directive), - getResolver.Properties.RequestMappingTemplate, - ]); - } - if (listResolver) { - listResolver.Properties.RequestMappingTemplate = joinSnippets([ - print(setQuerySnippet(definition, directive, ctx, true)), - listResolver.Properties.RequestMappingTemplate, - ]); - } - if (createResolver) { - createResolver.Properties.RequestMappingTemplate = joinSnippets([ - this.setKeySnippet(directive, true), - ensureCompositeKeySnippet(directive, false), - createResolver.Properties.RequestMappingTemplate, - ]); - } - if (updateResolver) { - updateResolver.Properties.RequestMappingTemplate = joinSnippets([ - this.setKeySnippet(directive, true), - ensureCompositeKeySnippet(directive, false), - updateResolver.Properties.RequestMappingTemplate, - ]); - } - if (deleteResolver) { - deleteResolver.Properties.RequestMappingTemplate = joinSnippets([ - this.setKeySnippet(directive, true), - deleteResolver.Properties.RequestMappingTemplate, - ]); - } - if (syncResolver) { - // add table primary key - // Currently composite key not supported - constructSyncResolver(directive, ctx, syncResolver, true); - } - } else { - // When looking at a secondary key we need to ensure any composite sort key values - // and validate update operations to protect the integrity of composite sort keys. - if (createResolver) { - createResolver.Properties.RequestMappingTemplate = joinSnippets([ - this.validateKeyArgumentSnippet(directive, 'create'), - ensureCompositeKeySnippet(directive, true), - createResolver.Properties.RequestMappingTemplate, - ]); - } - if (updateResolver) { - updateResolver.Properties.RequestMappingTemplate = joinSnippets([ - this.validateKeyArgumentSnippet(directive, 'update'), - ensureCompositeKeySnippet(directive, true), - updateResolver.Properties.RequestMappingTemplate, - ]); - } - if (deleteResolver) { - deleteResolver.Properties.RequestMappingTemplate = joinSnippets([ - ensureCompositeKeySnippet(directive, false), - deleteResolver.Properties.RequestMappingTemplate, - ]); - } - if (syncResolver) { - // Currently composite key not supported - constructSyncResolver(directive, ctx, syncResolver, false); - } - - if (directiveArgs.queryField) { - const queryTypeName = ctx.getQueryTypeName(); - const queryResolverId = ResolverResourceIDs.ResolverResourceID(queryTypeName, directiveArgs.queryField); - const queryResolver = makeQueryResolver(definition, directive, ctx); - ctx.mapResourceToStack(definition.name.value, queryResolverId); - ctx.setResource(queryResolverId, queryResolver); - } - } - }; - - private removeAutoCreatedPrimaryKey = (definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext): void => { - const schemaHasIdField = definition.fields.find((f) => f.name.value === 'id'); - if (!schemaHasIdField) { - const obj = ctx.getObject(definition.name.value); - const fields = obj.fields.filter((f) => f.name.value !== 'id'); - const newObj: ObjectTypeDefinitionNode = { - ...obj, - fields, - }; - ctx.updateObject(newObj); - } - }; - - private addKeyConditionInputs = (definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => { - const args: KeyArguments = getDirectiveArguments(directive); - if (args.fields.length > 2) { - const compositeKeyFieldNames = args.fields.slice(1); - // To make sure we get the intended behavior and type conversion we have to keep the order of the fields - // as it is in the key field list - const compositeKeyFields = []; - for (const compositeKeyFieldName of compositeKeyFieldNames) { - const field = definition.fields.find((field) => field.name.value === compositeKeyFieldName); - if (!field) { - throw new InvalidDirectiveError( - `Can't find field: ${compositeKeyFieldName} in ${definition.name.value}, but it was specified in the @key definition.`, - ); - } else { - compositeKeyFields.push(field); - } - } - const keyName = toUpper(args.name || 'Primary'); - const keyConditionInput = makeCompositeKeyConditionInputForKey(definition.name.value, keyName, compositeKeyFields); - if (!ctx.getType(keyConditionInput.name.value)) { - ctx.addInput(keyConditionInput); - } - const compositeKeyInput = makeCompositeKeyInputForKey(definition.name.value, keyName, compositeKeyFields); - if (!ctx.getType(compositeKeyInput.name.value)) { - ctx.addInput(compositeKeyInput); - } - } else if (args.fields.length === 2) { - const finalSortKeyFieldName = args.fields[1]; - const finalSortKeyField = definition.fields.find((f) => f.name.value === finalSortKeyFieldName); - const typeResolver = (baseType: string) => { - const resolvedEnumType = ctx.getType(baseType) as EnumTypeDefinitionNode; - return resolvedEnumType ? 'String' : undefined; - }; - const sortKeyConditionInput = makeScalarKeyConditionForType(finalSortKeyField.type, typeResolver); - - if (!sortKeyConditionInput) { - const checkedKeyName = args.name ? args.name : ''; - throw new InvalidDirectiveError( - `Cannot resolve type for field '${finalSortKeyFieldName}' in @key '${checkedKeyName}' on type '${definition.name.value}'.`, - ); - } - - if (!ctx.getType(sortKeyConditionInput.name.value)) { - ctx.addInput(sortKeyConditionInput); - } - } - }; - - /** - * Updates query fields to include any arguments required by the key structures. - * @param definition The object type definition node. - * @param directive The @key directive - * @param ctx The transformer context - */ - private updateQueryFields = (definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => { - this.updateGetField(definition, directive, ctx); - this.updateListField(definition, directive, ctx); - this.ensureQueryField(definition, directive, ctx); - }; - - // If the get field exists, update its arguments with primary key information. - private updateGetField = (definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => { - let query = ctx.getQuery(); - const getResourceID = ResolverResourceIDs.DynamoDBGetResolverResourceID(definition.name.value); - const getResolverResource = ctx.getResource(getResourceID); - if (getResolverResource && this.isPrimaryKey(directive)) { - // By default takes a single argument named 'id'. Replace it with the updated primary key structure. - let getField: FieldDefinitionNode = query.fields.find( - (field) => field.name.value === getResolverResource.Properties.FieldName, - ) as FieldDefinitionNode; - const args: KeyArguments = getDirectiveArguments(directive); - const getArguments = args.fields.map((keyAttributeName) => { - const keyField = definition.fields.find((field) => field.name.value === keyAttributeName); - const keyArgument = makeInputValueDefinition(keyAttributeName, makeNonNullType(makeNamedType(getBaseType(keyField.type)))); - return keyArgument; - }); - getField = { ...getField, arguments: getArguments }; - query = { ...query, fields: query.fields.map((field) => (field.name.value === getField.name.value ? getField : field)) }; - ctx.putType(query); - } - }; - - // If the list field exists, update its arguments with primary key information. - private updateListField = (definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => { - const listResourceID = ResolverResourceIDs.DynamoDBListResolverResourceID(definition.name.value); - const listResolverResource = ctx.getResource(listResourceID); - if (listResolverResource && this.isPrimaryKey(directive)) { - // By default takes a single argument named 'id'. Replace it with the updated primary key structure. - let query = ctx.getQuery(); - let listField: FieldDefinitionNode = query.fields.find( - (field) => field.name.value === listResolverResource.Properties.FieldName, - ) as FieldDefinitionNode; - let listArguments: InputValueDefinitionNode[] = [...listField.arguments]; - const args: KeyArguments = getDirectiveArguments(directive); - if (args.fields.length > 2) { - listArguments = addCompositeSortKey(definition, args, listArguments); - listArguments = addHashField(definition, args, listArguments); - } else if (args.fields.length === 2) { - listArguments = addSimpleSortKey(ctx, definition, args, listArguments); - listArguments = addHashField(definition, args, listArguments); - } else { - listArguments = addHashField(definition, args, listArguments); - } - listArguments.push(makeInputValueDefinition('sortDirection', makeNamedType('ModelSortDirection'))); - listField = { ...listField, arguments: listArguments }; - query = { ...query, fields: query.fields.map((field) => (field.name.value === listField.name.value ? listField : field)) }; - ctx.putType(query); - } - }; - - // If this is a secondary key and a queryField has been provided, create the query field. - private ensureQueryField = (definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => { - const args: KeyArguments = getDirectiveArguments(directive); - if (args.queryField && !this.isPrimaryKey(directive)) { - let queryType = ctx.getQuery(); - let queryArguments = []; - if (args.fields.length > 2) { - queryArguments = addCompositeSortKey(definition, args, queryArguments); - queryArguments = addHashField(definition, args, queryArguments); - } else if (args.fields.length === 2) { - queryArguments = addSimpleSortKey(ctx, definition, args, queryArguments); - queryArguments = addHashField(definition, args, queryArguments); - } else { - queryArguments = addHashField(definition, args, queryArguments); - } - queryArguments.push(makeInputValueDefinition('sortDirection', makeNamedType('ModelSortDirection'))); - const queryField = makeConnectionField(args.queryField, definition.name.value, queryArguments); - queryType = { - ...queryType, - fields: [...queryType.fields, queryField], - }; - ctx.putType(queryType); - - // Create Sort Direction if it doesn't exist - if (!this.typeExist('ModelSortDirection', ctx)) { - const modelSortDirection = makeModelSortDirectionEnumObject(); - ctx.addEnum(modelSortDirection); - } - this.generateFilterInputs(ctx, definition); - this.generateModelXConnectionType(ctx, definition); - } - }; - - private generateFilterInputs(ctx: TransformerContext, def: ObjectTypeDefinitionNode): void { - const scalarFilters = makeScalarFilterInputs(this.supportsConditions(ctx)); - for (const filter of scalarFilters) { - if (!this.typeExist(filter.name.value, ctx)) { - ctx.addInput(filter); - } - } - - // Create the Enum filters - const enumFilters = makeEnumFilterInputObjects(def, ctx, this.supportsConditions(ctx)); - for (const filter of enumFilters) { - if (!this.typeExist(filter.name.value, ctx)) { - ctx.addInput(filter); - } - } - - // Create the ModelXFilterInput - const tableXQueryFilterInput = makeModelXFilterInputObject(def, ctx, this.supportsConditions(ctx)); - if (!this.typeExist(tableXQueryFilterInput.name.value, ctx)) { - ctx.addInput(tableXQueryFilterInput); - } - - if (this.supportsConditions(ctx)) { - const attributeTypeEnum = makeAttributeTypeEnum(); - if (!this.typeExist(attributeTypeEnum.name.value, ctx)) { - ctx.addType(attributeTypeEnum); - } - } - } - - private generateModelXConnectionType(ctx: TransformerContext, def: ObjectTypeDefinitionNode): void { - const tableXConnectionName = ModelResourceIDs.ModelConnectionTypeName(def.name.value); - if (this.typeExist(tableXConnectionName, ctx)) { - return; - } - - // Create the ModelXConnection - const connectionType = blankObject(tableXConnectionName); - ctx.addObject(connectionType); - ctx.addObjectExtension(makeModelConnectionType(def.name.value)); - } - - // Update the create, update, and delete input objects to account for any changes to the primary key. - private updateInputObjects = (definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => { - if (this.isPrimaryKey(directive)) { - const directiveArgs: KeyArguments = getDirectiveArguments(directive); - - // check @model mutation argument to update schema or not - let shouldMakeCreate = true; - let shouldMakeUpdate = true; - let shouldMakeDelete = true; - - if (ctx.featureFlags.getBoolean('skipOverrideMutationInputTypes', false)) { - const modelDirective = definition.directives.find((dir) => dir.name.value === 'model'); - const modelDirectiveArgs = getDirectiveArguments(modelDirective); - - if (!_.isEmpty(modelDirectiveArgs) && Object.keys(modelDirectiveArgs).includes('mutations')) { - // Figure out which mutations to make and if they have name overrides - shouldMakeCreate = !!modelDirectiveArgs?.mutations?.create; - shouldMakeUpdate = !!modelDirectiveArgs?.mutations?.update; - shouldMakeDelete = !!modelDirectiveArgs?.mutations?.delete; - } - } - const hasIdField = definition.fields.find((f) => f.name.value === 'id'); - if (!hasIdField) { - const createInput = ctx.getType( - ModelResourceIDs.ModelCreateInputObjectName(definition.name.value), - ) as InputObjectTypeDefinitionNode; - if (createInput && shouldMakeCreate) { - ctx.putType(replaceCreateInput(definition, createInput, directiveArgs.fields)); - } - } - - const updateInput = ctx.getType(ModelResourceIDs.ModelUpdateInputObjectName(definition.name.value)) as InputObjectTypeDefinitionNode; - if (updateInput && shouldMakeUpdate) { - ctx.putType(replaceUpdateInput(definition, updateInput, directiveArgs.fields)); - } - const deleteInput = ctx.getType(ModelResourceIDs.ModelDeleteInputObjectName(definition.name.value)) as InputObjectTypeDefinitionNode; - if (deleteInput && shouldMakeDelete) { - ctx.putType(replaceDeleteInput(definition, deleteInput, directiveArgs.fields)); - } - } - }; - - // Return a VTL snippet that sets the key for key for get, update, and delete operations. - private setKeySnippet = (directive: DirectiveNode, isMutation: boolean = false) => { - const directiveArgs = getDirectiveArguments(directive); - const cmds: Expression[] = [set(ref(ResourceConstants.SNIPPETS.ModelObjectKey), modelObjectKey(directiveArgs, isMutation))]; - return printBlock(`Set the primary @key`)(compoundExpression(cmds)); - }; - - // When issuing an create/update mutation that creates/changes one part of a composite sort key, - // you must supply the entire key so that the underlying composite key can be resaved - // in a create/update operation. We only need to update for composite sort keys on secondary indexes. - // There is some tight coupling between setting 'hasSeenSomeKeyArg' in this method and calling ensureCompositeKeySnippet with conditionallySetSortKey = true - // That function expects this function to set 'hasSeenSomeKeyArg'. - private validateKeyArgumentSnippet = (directive: DirectiveNode, keyOperation: 'create' | 'update'): string => { - const directiveArgs: KeyArguments = getDirectiveArguments(directive); - if (!this.isPrimaryKey(directive) && directiveArgs.fields.length > 2) { - const sortKeyFields = directiveArgs.fields.slice(1); - return printBlock(`Validate ${keyOperation} mutation for @key '${directiveArgs.name}'`)( - compoundExpression([ - set(ref(ResourceConstants.SNIPPETS.HasSeenSomeKeyArg), bool(false)), - set(ref('keyFieldNames'), list(sortKeyFields.map((f) => str(f)))), - forEach(ref('keyFieldName'), ref('keyFieldNames'), [ - iff( - raw(`$ctx.args.input.containsKey("$keyFieldName")`), - set(ref(ResourceConstants.SNIPPETS.HasSeenSomeKeyArg), bool(true)), - true, - ), - ]), - forEach(ref('keyFieldName'), ref('keyFieldNames'), [ - iff( - raw(`$${ResourceConstants.SNIPPETS.HasSeenSomeKeyArg} && !$ctx.args.input.containsKey("$keyFieldName")`), - raw( - `$util.error("When ${keyOperation.replace(/.$/, 'ing')} any part of the composite sort key for @key '${ - directiveArgs.name - }',` + ` you must provide all fields for the key. Missing key: '$keyFieldName'.")`, - ), - ), - ]), - ]), - ); - } - return ''; - }; - - /** - * Validates the directive usage is semantically valid. - * - * 1. There may only be 1 @key without a name (specifying the primary key) - * 2. There may only be 1 @key with a given name. - * 3. @key must only reference existing scalar fields that map to DynamoDB S, N, or B. - * 4. A primary key must not include a 'queryField'. - * 5. If there is no primary sort key, make sure there are no more LSIs. - * @param definition The object type definition node. - * @param directive The @key directive - * @param ctx The transformer context - */ - private validate = (definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => { - const directiveArgs = getDirectiveArguments(directive); - if (!directiveArgs.name) { - // 1. Make sure there are no more directives without a name. - for (const otherDirective of definition.directives.filter((d) => d.name.value === 'key')) { - const otherArgs = getDirectiveArguments(otherDirective); - if (otherDirective !== directive && !otherArgs.name) { - throw new InvalidDirectiveError(`You may only supply one primary @key on type '${definition.name.value}'.`); - } - // 5. If there is no primary sort key, make sure there are no more LSIs. - const hasPrimarySortKey = directiveArgs.fields.length > 1; - const primaryHashField = directiveArgs.fields[0]; - const otherHashField = otherArgs.fields[0]; - if ( - otherDirective !== directive && - !hasPrimarySortKey && - // If the primary key and other key share the first field and are not the same directive it is an LSI. - primaryHashField === otherHashField - ) { - throw new InvalidDirectiveError( - `Invalid @key "${otherArgs.name}". You may not create a @key where the first field in 'fields' ` + - `is the same as that of the primary @key unless the primary @key has multiple 'fields'. ` + - `You cannot have a local secondary index without a sort key in the primary index.`, - ); - } - } - // 4. Make sure that a 'queryField' is not included on a primary @key. - if (directiveArgs.queryField) { - throw new InvalidDirectiveError(`You cannot pass 'queryField' to the primary @key on type '${definition.name.value}'.`); - } - } else { - // 2. Make sure there are no more directives with the same name. - for (const otherDirective of definition.directives.filter((d) => d.name.value === 'key')) { - const otherArgs = getDirectiveArguments(otherDirective); - if (otherDirective !== directive && otherArgs.name === directiveArgs.name) { - throw new InvalidDirectiveError( - `You may only supply one @key with the name '${directiveArgs.name}' on type '${definition.name.value}'.`, - ); - } - } - } - // 3. Check that fields exists and are valid key types. - const fieldMap = new Map(); - for (const field of definition.fields) { - fieldMap.set(field.name.value, field); - } - for (const fieldName of directiveArgs.fields) { - if (!fieldMap.has(fieldName)) { - const checkedKeyName = directiveArgs.name ? directiveArgs.name : ''; - throw new InvalidDirectiveError( - `You cannot specify a nonexistent field '${fieldName}' in @key '${checkedKeyName}' on type '${definition.name.value}'.`, - ); - } else { - const existingField = fieldMap.get(fieldName); - const ddbKeyType = attributeTypeFromType(existingField.type, ctx); - if (this.isPrimaryKey(directive) && !isNonNullType(existingField.type)) { - throw new InvalidDirectiveError(`The primary @key on type '${definition.name.value}' must reference non-null fields.`); - } else if (ddbKeyType !== 'S' && ddbKeyType !== 'N' && ddbKeyType !== 'B') { - throw new InvalidDirectiveError(`A @key on type '${definition.name.value}' cannot reference non-scalar field ${fieldName}.`); - } - } - } - }; - - /** - * Returns true if the directive specifies a primary key. - * @param directive The directive node. - */ - isPrimaryKey = (directive: DirectiveNode) => { - const directiveArgs = getDirectiveArguments(directive); - return !Boolean(directiveArgs.name); - }; - - /** - * Replace the primary key schema with one defined by a @key. - * @param definition The object type definition node. - * @param directive The @key directive - * @param ctx The transformer context - */ - replacePrimaryKey = (definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => { - const args: KeyArguments = getDirectiveArguments(directive); - const ks = keySchema(args); - const attrDefs = attributeDefinitions(args, definition, ctx); - const tableLogicalID = ModelResourceIDs.ModelTableResourceID(definition.name.value); - const tableResource = ctx.getResource(tableLogicalID); - if (!tableResource) { - throw new InvalidDirectiveError(`The @key directive may only be added to object definitions annotated with @model.`); - } else { - // First remove any attribute definitions in the current primary key. - const existingAttrDefSet = new Set(tableResource.Properties.AttributeDefinitions.map((ad) => ad.AttributeName)); - for (const existingKey of tableResource.Properties.KeySchema) { - if (existingAttrDefSet.has(existingKey.AttributeName)) { - tableResource.Properties.AttributeDefinitions = tableResource.Properties.AttributeDefinitions.filter( - (ad) => ad.AttributeName !== existingKey.AttributeName, - ); - existingAttrDefSet.delete(existingKey.AttributeName); - } - } - // Then replace the KeySchema and add any new attribute definitions back. - tableResource.Properties.KeySchema = ks; - for (const attr of attrDefs) { - if (!existingAttrDefSet.has(attr.AttributeName)) { - tableResource.Properties.AttributeDefinitions.push(attr); - } - } - } - }; - - /** - * Add a LSI or GSI to the table as defined by a @key. - * @param definition The object type definition node. - * @param directive The @key directive - * @param ctx The transformer context - */ - appendSecondaryIndex = (definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => { - const args: KeyArguments = getDirectiveArguments(directive); - const ks = keySchema(args); - const attrDefs = attributeDefinitions(args, definition, ctx); - const tableLogicalID = ModelResourceIDs.ModelTableResourceID(definition.name.value); - const tableResource = ctx.getResource(tableLogicalID); - const primaryKeyDirective = getPrimaryKey(definition); - const primaryPartitionKeyName = primaryKeyDirective ? getDirectiveArguments(primaryKeyDirective).fields[0] : 'id'; - const defaultGSI = ctx.featureFlags.getBoolean('secondaryKeyAsGSI', false); - if (!tableResource) { - throw new InvalidDirectiveError(`The @key directive may only be added to object definitions annotated with @model.`); - } else { - const baseIndexProperties = { - IndexName: args.name, - KeySchema: ks, - Projection: new Projection({ - ProjectionType: 'ALL', - }), - }; - if (primaryPartitionKeyName === ks[0].AttributeName && !defaultGSI) { - // This is an LSI. - // Add the new secondary index and update the table's attribute definitions. - tableResource.Properties.LocalSecondaryIndexes = append( - tableResource.Properties.LocalSecondaryIndexes, - new LocalSecondaryIndex(baseIndexProperties), - ); - } else { - // This is a GSI. - // Add the new secondary index and update the table's attribute definitions. - tableResource.Properties.GlobalSecondaryIndexes = append( - tableResource.Properties.GlobalSecondaryIndexes, - new GlobalSecondaryIndex({ - ...baseIndexProperties, - ProvisionedThroughput: Fn.If(ResourceConstants.CONDITIONS.ShouldUsePayPerRequestBilling, Refs.NoValue, { - ReadCapacityUnits: Fn.Ref(ResourceConstants.PARAMETERS.DynamoDBModelTableReadIOPS), - WriteCapacityUnits: Fn.Ref(ResourceConstants.PARAMETERS.DynamoDBModelTableWriteIOPS), - }) as any, - }), - ); - } - const existingAttrDefSet = new Set(tableResource.Properties.AttributeDefinitions.map((ad) => ad.AttributeName)); - for (const attr of attrDefs) { - if (!existingAttrDefSet.has(attr.AttributeName)) { - tableResource.Properties.AttributeDefinitions.push(attr); - } - } - } - }; - - private updateMutationConditionInput(ctx: TransformerContext, type: ObjectTypeDefinitionNode, directive: DirectiveNode): void { - // Get the existing ModelXConditionInput - const tableXMutationConditionInputName = ModelResourceIDs.ModelConditionInputTypeName(type.name.value); - - if (this.typeExist(tableXMutationConditionInputName, ctx)) { - const tableXMutationConditionInput = ctx.getType(tableXMutationConditionInputName); - - const fieldNames = new Set(); - - // Get PK for the type from @key directive or default to 'id' - const getKeyFieldNames = (): void => { - let fields: Array; - - if (getDirectiveArgument(directive, 'name') === undefined) { - const fieldsArg = >getDirectiveArgument(directive, 'fields'); - - if (fieldsArg && fieldsArg.length && fieldsArg.length > 0) { - fields = type.fields.filter((f) => fieldsArg.includes(f.name.value)); - } - } - - fieldNames.add('id'); - - if (fields && fields.length > 0) { - fields.forEach((f) => fieldNames.add(f.name.value)); - } else { - // Add default named key for exclusion from input type - fieldNames.add('id'); - } - }; - - getKeyFieldNames(); - - if (fieldNames.size > 0) { - const reducedFields = tableXMutationConditionInput.fields.filter((field) => !fieldNames.has(field.name.value)); - - const updatedInput = { - ...tableXMutationConditionInput, - fields: reducedFields, - }; - - ctx.putType(updatedInput); - } - } - } - - private typeExist(type: string, ctx: TransformerContext): boolean { - return Boolean(type in ctx.nodeMap); - } - - private supportsConditions(context: TransformerContext) { - return context.getTransformerVersion() >= CONDITIONS_MINIMUM_VERSION; - } -} - -/** - * Return a key schema given @key directive arguments. - * @param args The arguments of the @key directive. - */ -function keySchema(args: KeyArguments) { - if (args.fields.length > 1) { - const condensedSortKey = condenseRangeKey(args.fields.slice(1)); - return [ - { AttributeName: args.fields[0], KeyType: 'HASH' }, - { AttributeName: condensedSortKey, KeyType: 'RANGE' }, - ]; - } else { - return [{ AttributeName: args.fields[0], KeyType: 'HASH' }]; - } -} - -function attributeTypeFromType(type: TypeNode, ctx: TransformerContext) { - const baseTypeName = getBaseType(type); - const ofType = ctx.getType(baseTypeName); - if (ofType && ofType.kind === Kind.ENUM_TYPE_DEFINITION) { - return 'S'; - } - return attributeTypeFromScalar(type); -} - -/** - * Return a list of attribute definitions given a @key directive arguments and an object definition. - * @param args The arguments passed to @key. - * @param def The object type definition containing the @key. - */ -function attributeDefinitions(args: KeyArguments, def: ObjectTypeDefinitionNode, ctx: TransformerContext) { - const fieldMap = new Map(); - for (const field of def.fields) { - fieldMap.set(field.name.value, field); - } - if (args.fields.length > 2) { - const hashName = args.fields[0]; - const condensedSortKey = condenseRangeKey(args.fields.slice(1)); - return [ - { AttributeName: hashName, AttributeType: attributeTypeFromType(fieldMap.get(hashName).type, ctx) }, - { AttributeName: condensedSortKey, AttributeType: 'S' }, - ]; - } else if (args.fields.length === 2) { - const hashName = args.fields[0]; - const sortName = args.fields[1]; - return [ - { AttributeName: hashName, AttributeType: attributeTypeFromType(fieldMap.get(hashName).type, ctx) }, - { AttributeName: sortName, AttributeType: attributeTypeFromType(fieldMap.get(sortName).type, ctx) }, - ]; - } else { - const fieldName = args.fields[0]; - return [{ AttributeName: fieldName, AttributeType: attributeTypeFromType(fieldMap.get(fieldName).type, ctx) }]; - } -} - -function append(maybeList: T[] | undefined, item: T) { - if (maybeList) { - return [...maybeList, item]; - } - return [item]; -} - -function getPrimaryKey(obj: ObjectTypeDefinitionNode): DirectiveNode | undefined { - for (const directive of obj.directives) { - if (directive.name.value === 'key' && !getDirectiveArguments(directive).name) { - return directive; - } - } -} - -function primaryIdFields(definition: ObjectTypeDefinitionNode, keyFields: string[]): InputValueDefinitionNode[] { - return keyFields.map((keyFieldName) => { - const keyField: FieldDefinitionNode = definition.fields.find((field) => field.name.value === keyFieldName); - return makeInputValueDefinition(keyFieldName, makeNonNullType(makeNamedType(getBaseType(keyField.type)))); - }); -} - -// Key fields are non-nullable, non-key fields are not non-nullable. -function replaceUpdateInput( - definition: ObjectTypeDefinitionNode, - input: InputObjectTypeDefinitionNode, - keyFields: string[], -): InputObjectTypeDefinitionNode { - const schemaHasIdField = definition.fields!.some((f) => f.name.value === 'id'); - const inputFields = input.fields!.filter((f) => { - if (!schemaHasIdField && f.name.value === 'id') { - return false; - } - - return true; - }); - - return { - ...input, - fields: inputFields.map((f) => { - if (keyFields.find((k) => k === f.name.value)) { - return makeInputValueDefinition(f.name.value, wrapNonNull(withNamedNodeNamed(f.type, getBaseType(f.type)))); - } - - if (f.name.value === 'id') { - return makeInputValueDefinition(f.name.value, unwrapNonNull(withNamedNodeNamed(f.type, getBaseType(f.type)))); - } - - return f; - }), - }; -} - -// Remove the id field added by @model transformer -function replaceCreateInput( - definition: ObjectTypeDefinitionNode, - input: InputObjectTypeDefinitionNode, - keyFields: string[], -): InputObjectTypeDefinitionNode { - return { - ...input, - fields: input.fields.filter((f) => f.name.value !== 'id'), - }; -} - -// Key fields are non-nullable, non-key fields are not non-nullable. -function replaceDeleteInput( - definition: ObjectTypeDefinitionNode, - input: InputObjectTypeDefinitionNode, - keyFields: string[], -): InputObjectTypeDefinitionNode { - const idFields = primaryIdFields(definition, keyFields); - // Existing fields will contain extra fields in input type that was added/updated by other transformers - // like @versioned adds expectedVersion. - // field id of type ID is a special case that we need to filter as this is automatically inserted to input by dynamo db transformer - // Todo: Find out a better way to handle input types - const existingFields = input.fields.filter( - (f) => !(idFields.find((pf) => pf.name.value === f.name.value) || (getBaseType(f.type) === 'ID' && f.name.value === 'id')), - ); - - return { - ...input, - fields: [...idFields, ...existingFields], - }; -} - -/** - * Return a VTL object containing the compressed key information. - * @param args The arguments of the @key directive. - */ -function modelObjectKey(args: KeyArguments, isMutation: boolean) { - const argsPrefix = isMutation ? 'ctx.args.input' : 'ctx.args'; - if (args.fields.length > 2) { - const rangeKeyFields = args.fields.slice(1); - const condensedSortKey = condenseRangeKey(rangeKeyFields); - const condensedSortKeyValue = condenseRangeKey(rangeKeyFields.map((keyField) => `\${${argsPrefix}.${keyField}}`)); - return obj({ - [args.fields[0]]: ref(`util.dynamodb.toDynamoDB($${argsPrefix}.${args.fields[0]})`), - [condensedSortKey]: ref(`util.dynamodb.toDynamoDB("${condensedSortKeyValue}")`), - }); - } else if (args.fields.length === 2) { - return obj({ - [args.fields[0]]: ref(`util.dynamodb.toDynamoDB($${argsPrefix}.${args.fields[0]})`), - [args.fields[1]]: ref(`util.dynamodb.toDynamoDB($${argsPrefix}.${args.fields[1]})`), - }); - } else if (args.fields.length === 1) { - return obj({ - [args.fields[0]]: ref(`util.dynamodb.toDynamoDB($${argsPrefix}.${args.fields[0]})`), - }); - } - throw new InvalidDirectiveError('@key directives must include at least one field.'); -} - -/** - * @param dir The directive to generate a resolver for - * @param conditionallySetSortKey Whether or not to check hasSeenSomeKeyArg before setting the composite sort key (see https://github.com/aws-amplify/amplify-cli/issues/6634) - */ -function ensureCompositeKeySnippet(dir: DirectiveNode, conditionallySetSortKey: boolean): string { - const args: KeyArguments = getDirectiveArguments(dir); - const argsPrefix = 'ctx.args.input'; - if (args.fields.length > 2) { - const rangeKeyFields = args.fields.slice(1); - const condensedSortKey = condenseRangeKey(rangeKeyFields); - const dynamoDBFriendlySortKeyName = toCamelCase(rangeKeyFields.map((f) => graphqlName(f))); - const condensedSortKeyValue = condenseRangeKey(rangeKeyFields.map((keyField) => `\${${argsPrefix}.${keyField}}`)); - return print( - compoundExpression([ - ifElse( - raw(`$util.isNull($${ResourceConstants.SNIPPETS.DynamoDBNameOverrideMap})`), - set( - ref(ResourceConstants.SNIPPETS.DynamoDBNameOverrideMap), - obj({ - [condensedSortKey]: str(dynamoDBFriendlySortKeyName), - }), - ), - qref(`$${ResourceConstants.SNIPPETS.DynamoDBNameOverrideMap}.put("${condensedSortKey}", "${dynamoDBFriendlySortKeyName}")`), - ), - conditionallySetSortKey - ? iff( - ref(ResourceConstants.SNIPPETS.HasSeenSomeKeyArg), - qref(`$ctx.args.input.put("${condensedSortKey}","${condensedSortKeyValue}")`), - ) - : qref(`$ctx.args.input.put("${condensedSortKey}","${condensedSortKeyValue}")`), - ]), - ); - } - return ''; -} - -function condenseRangeKey(fields: string[]) { - return fields.join(ModelResourceIDs.ModelCompositeKeySeparator()); -} - -function makeQueryResolver(definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) { - const type = definition.name.value; - const directiveArgs: KeyArguments = getDirectiveArguments(directive); - const index = directiveArgs.name; - const fieldName = directiveArgs.queryField; - const queryTypeName = ctx.getQueryTypeName(); - const requestVariable = 'QueryRequest'; - return new AppSync.Resolver({ - ApiId: Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - DataSourceName: Fn.GetAtt(ModelResourceIDs.ModelTableDataSourceID(type), 'Name'), - FieldName: fieldName, - TypeName: queryTypeName, - RequestMappingTemplate: print( - compoundExpression([ - setQuerySnippet(definition, directive, ctx, false), - set(ref('limit'), ref(`util.defaultIfNull($context.args.limit, ${ResourceConstants.DEFAULT_PAGE_LIMIT})`)), - set( - ref(requestVariable), - obj({ - version: str(RESOLVER_VERSION_ID), - operation: str('Query'), - limit: ref('limit'), - query: ref(ResourceConstants.SNIPPETS.ModelQueryExpression), - index: str(index), - }), - ), - ifElse( - raw(`!$util.isNull($ctx.args.sortDirection) - && $ctx.args.sortDirection == "DESC"`), - set(ref(`${requestVariable}.scanIndexForward`), bool(false)), - set(ref(`${requestVariable}.scanIndexForward`), bool(true)), - ), - iff(ref('context.args.nextToken'), set(ref(`${requestVariable}.nextToken`), ref('context.args.nextToken')), true), - iff( - ref('context.args.filter'), - set(ref(`${requestVariable}.filter`), ref('util.parseJson("$util.transform.toDynamoDBFilterExpression($ctx.args.filter)")')), - true, - ), - raw(`$util.toJson($${requestVariable})`), - ]), - ), - ResponseMappingTemplate: print( - compoundExpression([ - iff(ref('ctx.error'), raw('$util.error($ctx.error.message, $ctx.error.type)')), - raw('$util.toJson($ctx.result)'), - ]), - ), - }); -} - -function setQuerySnippet(definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext, isListResolver: boolean) { - const args: KeyArguments = getDirectiveArguments(directive); - const keys = args.fields; - const keyTypes = keys.map((k) => { - const field = definition.fields.find((f) => f.name.value === k); - return attributeTypeFromType(field.type, ctx); - }); - - const expressions: Expression[] = []; - - // if @key has only Hash key then we've to add sortDirection validation to the VTL as it will not work - // TODO: when we will have featureflags we can fix it by not generating sortDirection parameter at all for these operations - if (keys.length === 1) { - const sortDirectionValidation = iff( - raw(`!$util.isNull($ctx.args.sortDirection)`), - raw(`$util.error("sortDirection is not supported for List operations without a Sort key defined.", "InvalidArgumentsError")`), - ); - - expressions.push(sortDirectionValidation); - } else if (isListResolver === true && keys.length >= 1) { - // We only need this check for List queries, and not for @key queries - const sortDirectionValidation = iff( - and([raw(`$util.isNull($ctx.args.${keys[0]})`), raw(`!$util.isNull($ctx.args.sortDirection)`)]), - raw(`$util.error("When providing argument 'sortDirection' you must also provide argument '${keys[0]}'.", "InvalidArgumentsError")`), - ); - - expressions.push(sortDirectionValidation); - } - - expressions.push( - set(ref(ResourceConstants.SNIPPETS.ModelQueryExpression), obj({})), - applyKeyExpressionForCompositeKey(keys, keyTypes, ResourceConstants.SNIPPETS.ModelQueryExpression), - ); - - return block(`Set query expression for @key`, expressions); -} - -function addHashField( - definition: ObjectTypeDefinitionNode, - args: KeyArguments, - elems: InputValueDefinitionNode[], -): InputValueDefinitionNode[] { - let hashFieldName = args.fields[0]; - const hashField = definition.fields.find((field) => field.name.value === hashFieldName); - const hashKey = makeInputValueDefinition(hashFieldName, makeNamedType(getBaseType(hashField.type))); - return [hashKey, ...elems]; -} -function addSimpleSortKey( - ctx: TransformerContext, - definition: ObjectTypeDefinitionNode, - args: KeyArguments, - elems: InputValueDefinitionNode[], -): InputValueDefinitionNode[] { - let sortKeyName = args.fields[1]; - const sortField = definition.fields.find((field) => field.name.value === sortKeyName); - const baseType = getBaseType(sortField.type); - const resolvedTypeIfEnum = (ctx.getType(baseType) as EnumTypeDefinitionNode) ? 'String' : undefined; - const resolvedType = resolvedTypeIfEnum ? resolvedTypeIfEnum : baseType; - const hashKey = makeInputValueDefinition(sortKeyName, makeNamedType(ModelResourceIDs.ModelKeyConditionInputTypeName(resolvedType))); - return [hashKey, ...elems]; -} -function addCompositeSortKey( - definition: ObjectTypeDefinitionNode, - args: KeyArguments, - elems: InputValueDefinitionNode[], -): InputValueDefinitionNode[] { - let sortKeyNames = args.fields.slice(1); - const compositeSortKeyName = toCamelCase(sortKeyNames); - const hashKey = makeInputValueDefinition( - compositeSortKeyName, - makeNamedType(ModelResourceIDs.ModelCompositeKeyConditionInputTypeName(definition.name.value, toUpper(args.name || 'Primary'))), - ); - return [hashKey, ...elems]; -} -function joinSnippets(lines: string[]): string { - return lines.join('\n'); -} - -// QueryMap doesnt Support Composite Keys -function setSyncQueryMapSnippet(directive: DirectiveNode, isTable: boolean) { - const args: KeyArguments = getDirectiveArguments(directive); - const keys = args.fields; - const expressions: Expression[] = []; - const index: String = isTable ? 'dbTable' : args.name; - let key: String = ''; - if (keys.length === 1) { - key = `${keys[0]}+null`; - } else if (keys.length > 1) { - key = keys.join('+'); - } - expressions.push(raw(`$util.qr($QueryMap.put('${key}' , '${index}'))`), raw(`$util.qr($PkMap.put('${keys[0]}' , '${index}'))`)); - return block(`Set query expression for @key`, expressions); -} - -function setSyncQueryFilterSnippet() { - const expressions: Expression[] = []; - expressions.push( - compoundExpression([ - set(ref('filterArgsMap'), ref('ctx.args.filter.get("and")')), - ifElse( - raw(`!$util.isNullOrEmpty($filterArgsMap) && ($util.isNull($ctx.args.lastSync) || $ctx.args.lastSync == 0)`), - compoundExpression([ - set(ref('json'), raw(`$filterArgsMap`)), - forEach(ref('item'), ref(`json`), [ - set(ref('ind'), ref('foreach.index')), - forEach(ref('entry'), ref('item.entrySet()'), [ - iff( - raw(`$ind == 0 && !$util.isNullOrEmpty($entry.value.eq) && !$util.isNullOrEmpty($PkMap.get($entry.key))`), - compoundExpression([ - set(ref('pk'), ref('entry.key')), - set(ref('scan'), bool(false)), - raw('$util.qr($ctx.args.put($pk,$entry.value.eq))'), - set(ref('index'), ref('PkMap.get($pk)')), - ]), - ), - ifElse( - raw('$ind == 1 && !$util.isNullOrEmpty($pk) && !$util.isNullOrEmpty($QueryMap.get("${pk}+$entry.key"))'), - compoundExpression([ - set(ref('sk'), ref('entry.key')), - raw('$util.qr($ctx.args.put($sk,$entry.value))'), - set(ref('index'), ref('QueryMap.get("${pk}+$sk")')), - ]), - iff(raw('$ind > 0'), qref('$filterMap.put($entry.key,$entry.value)')), - ), - ]), - ]), - ]), - set(ref(`filterMap`), raw(`$ctx.args.filter`)), - ), - ]), - ); - return block(`Set query expression for @key`, expressions); -} - -function generateSyncResolverInit() { - const expressions: Expression[] = []; - expressions.push( - set(ref('index'), str('')), - set(ref('scan'), bool(true)), - set(ref('filterMap'), obj({})), - set(ref('QueryMap'), obj({})), - set(ref('PkMap'), obj({})), - set(ref('filterArgsMap'), obj({})), - ); - return block(`Set map initialization for @key`, expressions); -} - -function setSyncKeyExpressionForHashKey(queryExprReference: string) { - const expressions: Expression[] = []; - expressions.push( - set(ref(ResourceConstants.SNIPPETS.ModelQueryExpression), obj({})), - iff( - raw(`!$util.isNull($pk)`), - compoundExpression([ - set(ref(`${queryExprReference}.expression`), str(`#pk = :pk`)), - set(ref(`${queryExprReference}.expressionNames`), obj({ [`#pk`]: str('$pk') })), - set( - ref(`${queryExprReference}.expressionValues`), - obj({ [`:pk`]: ref('util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($pk)))') }), - ), - ]), - ), - ); - return block(`Set Primary Key initialization @key`, expressions); -} - -function setSyncKeyExpressionForRangeKey(queryExprReference: string) { - return block('Applying Key Condition', [ - iff( - raw(`!$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).beginsWith)`), - compoundExpression([ - set(ref(`${queryExprReference}.expression`), raw(`"$${queryExprReference}.expression AND begins_with(#sortKey, :sortKey)"`)), - qref(`$${queryExprReference}.expressionNames.put("#sortKey", $sk)`), - qref( - `$${queryExprReference}.expressionValues.put(":sortKey", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).beginsWith)))`, - ), - ]), - ), - iff( - raw(`!$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).between)`), - compoundExpression([ - set( - ref(`${queryExprReference}.expression`), - raw(`"$${queryExprReference}.expression AND #sortKey BETWEEN :sortKey0 AND :sortKey1"`), - ), - qref(`$${queryExprReference}.expressionNames.put("#sortKey", $sk)`), - qref( - `$${queryExprReference}.expressionValues.put(":sortKey", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).between[0])))`, - ), - qref( - `$${queryExprReference}.expressionValues.put(":sortKey", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).between[1])))`, - ), - ]), - ), - iff( - raw(`!$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).eq)`), - compoundExpression([ - set(ref(`${queryExprReference}.expression`), raw(`"$${queryExprReference}.expression AND #sortKey = :sortKey"`)), - qref(`$${queryExprReference}.expressionNames.put("#sortKey", $sk)`), - qref( - `$${queryExprReference}.expressionValues.put(":sortKey", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).eq)))`, - ), - ]), - ), - iff( - raw(`!$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).lt)`), - compoundExpression([ - set(ref(`${queryExprReference}.expression`), raw(`"$${queryExprReference}.expression AND #sortKey < :sortKey"`)), - qref(`$${queryExprReference}.expressionNames.put("#sortKey", $sk)`), - qref( - `$${queryExprReference}.expressionValues.put(":sortKey", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).lt)))`, - ), - ]), - ), - iff( - raw(`!$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).le)`), - compoundExpression([ - set(ref(`${queryExprReference}.expression`), raw(`"$${queryExprReference}.expression AND #sortKey <= :sortKey"`)), - qref(`$${queryExprReference}.expressionNames.put("#sortKey", $sk)`), - qref( - `$${queryExprReference}.expressionValues.put(":sortKey", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).le)))`, - ), - ]), - ), - iff( - raw(`!$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).gt)`), - compoundExpression([ - set(ref(`${queryExprReference}.expression`), raw(`"$${queryExprReference}.expression AND #sortKey > :sortKey"`)), - qref(`$${queryExprReference}.expressionNames.put("#sortKey", $sk)`), - qref( - `$${queryExprReference}.expressionValues.put(":sortKey", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).gt)))`, - ), - ]), - ), - iff( - raw(`!$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).ge)`), - compoundExpression([ - set(ref(`${queryExprReference}.expression`), raw(`"$${queryExprReference}.expression AND #sortKey >= :sortKey"`)), - qref(`$${queryExprReference}.expressionNames.put("#sortKey", $sk)`), - qref( - `$${queryExprReference}.expressionValues.put(":sortKey", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).ge)))`, - ), - ]), - ), - ]); -} - -function makeSyncQueryResolver() { - const requestVariable = 'QueryRequest'; - const expressions: Expression[] = []; - expressions.push( - ifElse( - raw('!$scan'), - compoundExpression([ - set(ref('limit'), ref(`util.defaultIfNull($context.args.limit, ${ResourceConstants.DEFAULT_PAGE_LIMIT})`)), - set( - ref(requestVariable), - obj({ - version: str(RESOLVER_VERSION_ID), - operation: str('Sync'), - limit: ref('limit'), - query: ref(ResourceConstants.SNIPPETS.ModelQueryExpression), - }), - ), - ifElse( - raw(`!$util.isNull($ctx.args.sortDirection) - && $ctx.args.sortDirection == "DESC"`), - set(ref(`${requestVariable}.scanIndexForward`), bool(false)), - set(ref(`${requestVariable}.scanIndexForward`), bool(true)), - ), - iff(ref('context.args.nextToken'), set(ref(`${requestVariable}.nextToken`), ref('context.args.nextToken')), true), - iff( - raw('!$util.isNullOrEmpty($filterMap)'), - set(ref(`${requestVariable}.filter`), ref('util.parseJson($util.transform.toDynamoDBFilterExpression($filterMap))')), - ), - iff(raw(`$index != "dbTable"`), set(ref(`${requestVariable}.index`), ref('index'))), - raw(`$util.toJson($${requestVariable})`), - ]), - DynamoDBMappingTemplate.syncItem({ - filter: ifElse( - raw('!$util.isNullOrEmpty($ctx.args.filter)'), - ref('util.transform.toDynamoDBFilterExpression($ctx.args.filter)'), - nul(), - ), - limit: ref(`util.defaultIfNull($ctx.args.limit, ${ResourceConstants.DEFAULT_SYNC_QUERY_PAGE_LIMIT})`), - lastSync: ref('util.toJson($util.defaultIfNull($ctx.args.lastSync, null))'), - nextToken: ref('util.toJson($util.defaultIfNull($ctx.args.nextToken, null))'), - }), - ), - ); - return block(` Set query expression for @key`, expressions); -} - -function constructSyncResolver(directive: DirectiveNode, ctx: TransformerContext, syncResolver: any, isTable: boolean) { - if (ctx.metadata.has(ResourceConstants.SNIPPETS.SyncResolverKey)) { - const resolverMap = ctx.metadata.get(ResourceConstants.SNIPPETS.SyncResolverKey); - if (resolverMap.has(syncResolver)) { - const prevSnippet = resolverMap.get(syncResolver); - resolverMap.set(syncResolver, joinSnippets([prevSnippet, print(setSyncQueryMapSnippet(directive, isTable))])); - } else { - resolverMap.set(syncResolver, print(setSyncQueryMapSnippet(directive, isTable))); - } - } -} diff --git a/packages/graphql-key-transformer/src/__tests__/KeyTransformer.test.ts b/packages/graphql-key-transformer/src/__tests__/KeyTransformer.test.ts deleted file mode 100644 index e4865a8351..0000000000 --- a/packages/graphql-key-transformer/src/__tests__/KeyTransformer.test.ts +++ /dev/null @@ -1,537 +0,0 @@ -import { parse, InputObjectTypeDefinitionNode, DefinitionNode, DocumentNode, Kind } from 'graphql'; -import { GraphQLTransform, InvalidDirectiveError, SyncConfig, ConflictHandlerType, FeatureFlagProvider } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { KeyTransformer } from '../KeyTransformer'; - -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - if (name === 'skipOverrideMutationInputTypes') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -test('Check KeyTransformer Resolver Code', () => { - const validSchema = ` - type Item @model - @key(fields: ["orderId", "status", "createdAt"]) - @key(name: "ByStatus", fields: ["status", "createdAt"], queryField: "itemsByStatus") - @key(name: "ByCreatedAt", fields: ["createdAt", "status"], queryField: "itemsByCreatedAt") - { - orderId: ID! - status: Status! - createdAt: AWSDateTime! - name: String! - } - enum Status { - DELIVERED IN_TRANSIT PENDING UNKNOWN - }`; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.resolvers).toMatchSnapshot(); -}); -test('KeyTransformer should fail if more than 1 @key is provided without a name.', () => { - const invalidSchema = ` - type Test @key(fields: ["id"]) @key(fields: ["email"]) { - id: ID! - email: String - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new KeyTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(invalidSchema)).toThrowError(InvalidDirectiveError); -}); - -test('KeyTransformer should fail if more than 1 @key is provided with the same name.', () => { - const invalidSchema = ` - type Test @key(name: "Test", fields: ["id"]) @key(name: "Test", fields: ["email"]) { - id: ID! - email: String - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new KeyTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(invalidSchema)).toThrowError(InvalidDirectiveError); -}); - -test('KeyTransformer should fail if referencing a field that does not exist.', () => { - const invalidSchema = ` - type Test @key(fields: ["someWeirdId"]) { - id: ID! - email: String - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new KeyTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(invalidSchema)).toThrowError(InvalidDirectiveError); -}); - -test('that a primary @key fails if pointing to nullable fields.', () => { - const invalidSchema = ` - type Test @key(fields: ["email"]) { - id: ID! - email: String - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new KeyTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(invalidSchema)).toThrowError(InvalidDirectiveError); -}); - -test('that model with an LSI but no primary sort key will fail.', () => { - const invalidSchema = ` - type Test @key(fields: ["id"]) @key(name: "SomeLSI", fields: ["id", "email"]) { - id: ID! - email: String! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new KeyTransformer()], - featureFlags, - }); - expect(() => transformer.transform(invalidSchema)).toThrowError(InvalidDirectiveError); -}); - -test('KeyTransformer should fail if a non-existing type field is defined as key field.', () => { - const invalidSchema = ` - type Test @key(name: "Test", fields: ["one"]) { - id: ID! - email: String - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new KeyTransformer()], - featureFlags, - }); - - expect(() => transformer.transform(invalidSchema)).toThrowError(InvalidDirectiveError); -}); - -test('Check sortDirection validation code present in list resolver code for simple keys', () => { - const validSchema = ` - type Blog - @model - @key(fields: ["id"]) - { - id: ID! - title: String! - createdAt: AWSDateTime! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - expect(out.resolvers['Query.listBlogs.req.vtl']).toMatchSnapshot(); -}); - -test('Check sortDirection validation code present in list resolver code for compound keys', () => { - const validSchema = ` - type Blog - @model - @key(fields: ["id", "createdAt"]) - { - id: ID! - title: String! - createdAt: AWSDateTime! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - - expect(out.resolvers['Query.listBlogs.req.vtl']).toMatchSnapshot(); -}); - -test('KeyTransformer should remove default primary key when primary key overidden', () => { - const validSchema = /* GraphQL */ ` - type Blog @model @key(fields: ["blogId", "createdAt"]) { - blogId: ID! - title: String! - createdAt: AWSDateTime! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const schema = parse(out.schema); - const createBlogInput: InputObjectTypeDefinitionNode = schema.definitions.find( - (d) => d.kind === 'InputObjectTypeDefinition' && d.name.value === 'CreateBlogInput', - ) as InputObjectTypeDefinitionNode | undefined; - expect(createBlogInput).toBeDefined(); - const defaultIdField = createBlogInput.fields.find((f) => f.name.value === 'id'); - expect(defaultIdField).toBeUndefined(); -}); - -test('KeyTransformer should not remove default primary key when primary key not overidden', () => { - const validSchema = /* GraphQL */ ` - type Blog @model @key(name: "btBlogIdAndCreatedAt", fields: ["blogId", "createdAt"]) { - blogId: ID! - title: String! - createdAt: AWSDateTime! - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const schema = parse(out.schema); - - const createBlogInput: InputObjectTypeDefinitionNode = schema.definitions.find( - (d) => d.kind === 'InputObjectTypeDefinition' && d.name.value === 'CreateBlogInput', - ) as InputObjectTypeDefinitionNode | undefined; - expect(createBlogInput).toBeDefined(); - const defaultIdField = createBlogInput.fields.find((f) => f.name.value === 'id'); - expect(defaultIdField).toBeDefined(); -}); - -test('Check KeyTransformer Resolver Code when sync enabled', () => { - const validSchema = ` - type Item @model - @key(fields: ["orderId", "status", "createdAt"]) - @key(name: "ByStatus", fields: ["status", "createdAt"], queryField: "itemsByStatus") - @key(name: "ByCreatedAt", fields: ["createdAt", "status"], queryField: "itemsByCreatedAt") - { - orderId: ID! - status: Status! - createdAt: AWSDateTime! - name: String! - } - enum Status { - DELIVERED IN_TRANSIT PENDING UNKNOWN - }`; - const config: SyncConfig = { - ConflictDetection: 'VERSION', - ConflictHandler: ConflictHandlerType.AUTOMERGE, - }; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - featureFlags, - transformConfig: { - ResolverConfig: { - project: config, - }, - }, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - expect(out.resolvers).toMatchSnapshot(); -}); - -test('that sort direction and filter input are generated if default list query does not exist', () => { - const validSchema = ` - type Todo - @model(queries: { get: "getTodo" }) - @key( - name: "byCreatedAt" - fields: ["createdAt"] - queryField: "byCreatedAt" - ){ - id: ID! - description: String - createdAt: AWSDateTime - }`; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const schema = parse(out.schema); - const sortDirection = schema.definitions.find((d) => d.kind === 'EnumTypeDefinition' && d.name.value === 'ModelSortDirection'); - expect(sortDirection).toBeDefined(); - const stringInputType = getInputType(schema, 'ModelStringFilterInput'); - expect(stringInputType).toBeDefined(); - const booleanInputType = getInputType(schema, 'ModelBooleanFilterInput'); - expect(booleanInputType).toBeDefined(); - const intInputType = getInputType(schema, 'ModelIntFilterInput'); - expect(intInputType).toBeDefined(); - const floatInputType = getInputType(schema, 'ModelFloatFilterInput'); - expect(floatInputType).toBeDefined(); - const idInputType = getInputType(schema, 'ModelIDFilterInput'); - expect(idInputType).toBeDefined(); - const todoInputType = getInputType(schema, 'ModelTodoFilterInput'); - expect(todoInputType).toBeDefined(); -}); - -test('GSI composite sort keys are wrapped in conditional to check presence in mutation', () => { - const validSchema = /* GraphQL */ ` - type Person - @model - @key(fields: ["id", "firstName", "lastName"]) - @key(name: "byNameAndAge", fields: ["firstName", "age", "birthDate"], queryField: "getPersonByNameByDate") - @key(name: "byNameAndNickname", fields: ["firstName", "lastName", "nickname"]) { - id: ID! - firstName: String! - lastName: String! - birthDate: AWSDate - nickname: String - age: Int - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - featureFlags, - }); - - const result = transformer.transform(validSchema); - expect(result?.resolvers?.['Mutation.createPerson.req.vtl']).toMatchSnapshot(); - expect(result?.resolvers?.['Mutation.updatePerson.req.vtl']).toMatchSnapshot(); -}); - -function getInputType(doc: DocumentNode, type: string): InputObjectTypeDefinitionNode | undefined { - return doc.definitions.find((def: DefinitionNode) => def.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION && def.name.value === type) as - | InputObjectTypeDefinitionNode - | undefined; -} - -describe('check schema input', () => { - it('@model mutation with user defined null args', () => { - const validSchema = /* GraphQL */ ` - type Call - @model(queries: null, mutations: null) - @key(fields: ["receiverId", "senderId"]) - @key(name: "bySender", fields: ["senderId", "receiverId"]) { - senderId: ID! - receiverId: ID! - } - - type Mutation { - createCall(input: CreateCallInput!): Call - deleteCall(input: DeleteCallInput!): Call - } - - input CreateCallInput { - receiverId: ID! - } - - input DeleteCallInput { - receiverId: ID! - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const schema = parse(out.schema); - - const DeleteCallInput: InputObjectTypeDefinitionNode = schema.definitions.find( - (d) => d.kind === 'InputObjectTypeDefinition' && d.name.value === 'DeleteCallInput', - ) as InputObjectTypeDefinitionNode | undefined; - expect(DeleteCallInput).toBeDefined(); - const receiverIdField = DeleteCallInput.fields.find((f) => f.name.value === 'receiverId'); - expect(receiverIdField).toBeDefined(); - expect(receiverIdField.type.kind).toBe('NonNullType'); - const senderIdField = DeleteCallInput.fields.find((f) => f.name.value === 'senderId'); - expect(senderIdField).toBeUndefined(); - }); - - it('@model mutation with user defined create args', () => { - const validSchema = /* GraphQL */ ` - type Call - @model(queries: null, mutations: { delete: "testDelete" }) - @key(fields: ["receiverId", "senderId"]) - @key(name: "bySender", fields: ["senderId", "receiverId"]) { - senderId: ID! - receiverId: ID! - } - - input CreateCallInput { - receiverId: ID! - } - - input DeleteCallInput { - receiverId: ID! - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const schema = parse(out.schema); - - const DeleteCallInput: InputObjectTypeDefinitionNode = schema.definitions.find( - (d) => d.kind === 'InputObjectTypeDefinition' && d.name.value === 'DeleteCallInput', - ) as InputObjectTypeDefinitionNode | undefined; - expect(DeleteCallInput).toBeDefined(); - const receiverIdField = DeleteCallInput.fields.find((f) => f.name.value === 'receiverId'); - expect(receiverIdField).toBeDefined(); - expect(receiverIdField.type.kind).toBe('NonNullType'); - const senderIdField = DeleteCallInput.fields.find((f) => f.name.value === 'senderId'); - expect(senderIdField).toBeDefined(); - expect(senderIdField.type.kind).toBe('NonNullType'); - }); - - it('@model mutation with default', () => { - const validSchema = /* GraphQL */ ` - type Call @model @key(fields: ["receiverId", "senderId"]) @key(name: "bySender", fields: ["senderId", "receiverId"]) { - senderId: ID! - receiverId: ID! - } - - input CreateCallInput { - receiverId: ID! - } - - input DeleteCallInput { - receiverId: ID! - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const schema = parse(out.schema); - - // checlk for delete input - const DeleteCallInput: InputObjectTypeDefinitionNode = schema.definitions.find( - (d) => d.kind === 'InputObjectTypeDefinition' && d.name.value === 'DeleteCallInput', - ) as InputObjectTypeDefinitionNode | undefined; - expect(DeleteCallInput).toBeDefined(); - const receiverIdField = DeleteCallInput.fields.find((f) => f.name.value === 'receiverId'); - expect(receiverIdField).toBeDefined(); - expect(receiverIdField.type.kind).toBe('NonNullType'); - const senderIdField = DeleteCallInput.fields.find((f) => f.name.value === 'senderId'); - expect(senderIdField).toBeDefined(); - expect(senderIdField.type.kind).toBe('NonNullType'); - - // check for create input - const CreateCallInput: InputObjectTypeDefinitionNode = schema.definitions.find( - (d) => d.kind === 'InputObjectTypeDefinition' && d.name.value === 'CreateCallInput', - ) as InputObjectTypeDefinitionNode | undefined; - expect(CreateCallInput).toBeDefined(); - const receiverIdFieldCreate = CreateCallInput.fields.find((f) => f.name.value === 'receiverId'); - expect(receiverIdFieldCreate).toBeDefined(); - expect(receiverIdFieldCreate.type.kind).toBe('NonNullType'); - const senderIdFieldCreate = CreateCallInput.fields.find((f) => f.name.value === 'senderId'); - expect(senderIdFieldCreate).toBeUndefined(); - }); - - it('@model mutation with queries', () => { - const validSchema = /* GraphQL */ ` - type Call @model(queries: null) @key(fields: ["receiverId", "senderId"]) @key(name: "bySender", fields: ["senderId", "receiverId"]) { - senderId: ID! - receiverId: ID! - } - input CreateCallInput { - receiverId: ID! - } - - input DeleteCallInput { - receiverId: ID! - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const schema = parse(out.schema); - - // checlk for delete input - const DeleteCallInput: InputObjectTypeDefinitionNode = schema.definitions.find( - (d) => d.kind === 'InputObjectTypeDefinition' && d.name.value === 'DeleteCallInput', - ) as InputObjectTypeDefinitionNode | undefined; - expect(DeleteCallInput).toBeDefined(); - const receiverIdField = DeleteCallInput.fields.find((f) => f.name.value === 'receiverId'); - expect(receiverIdField).toBeDefined(); - expect(receiverIdField.type.kind).toBe('NonNullType'); - const senderIdField = DeleteCallInput.fields.find((f) => f.name.value === 'senderId'); - expect(senderIdField).toBeDefined(); - expect(senderIdField.type.kind).toBe('NonNullType'); - - // check for create input - const CreateCallInput: InputObjectTypeDefinitionNode = schema.definitions.find( - (d) => d.kind === 'InputObjectTypeDefinition' && d.name.value === 'CreateCallInput', - ) as InputObjectTypeDefinitionNode | undefined; - expect(CreateCallInput).toBeDefined(); - const receiverIdFieldCreate = CreateCallInput.fields.find((f) => f.name.value === 'receiverId'); - expect(receiverIdFieldCreate).toBeDefined(); - expect(receiverIdFieldCreate.type.kind).toBe('NonNullType'); - const senderIdFieldCreate = CreateCallInput.fields.find((f) => f.name.value === 'senderId'); - expect(senderIdFieldCreate).toBeUndefined(); - }); - - it('id field should be optional in updateInputObjects when it is not a primary key', () => { - const validSchema = /* GraphQL */ ` - type Review - @model(subscriptions: { level: off }) - @key(fields: ["owner", "serviceId"]) - @key(name: "byService", fields: ["serviceId", "createdAt"], queryField: "listReviewsByService") - @key(name: "byStatus", fields: ["owner", "status", "createdAt"], queryField: "listReviewsByStatus") - @key(name: "byId", fields: ["id"], queryField: "listReviewsById") { - id: ID! - serviceId: ID! - owner: String! - rating: Int - title: String - status: String - createdAt: AWSDateTime! - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const schema = parse(out.schema); - - const UpdateReviewInput: InputObjectTypeDefinitionNode = schema.definitions.find( - (d) => d.kind === 'InputObjectTypeDefinition' && d.name.value === 'UpdateReviewInput', - ) as InputObjectTypeDefinitionNode | undefined; - expect(UpdateReviewInput).toBeDefined(); - const idField = UpdateReviewInput.fields.find((f) => f.name.value === 'id'); - expect(idField).toBeDefined(); - expect(idField.type.kind).toBe('NamedType'); - }); -}); diff --git a/packages/graphql-key-transformer/src/__tests__/__snapshots__/KeyTransformer.test.ts.snap b/packages/graphql-key-transformer/src/__tests__/__snapshots__/KeyTransformer.test.ts.snap deleted file mode 100644 index ca68ca480a..0000000000 --- a/packages/graphql-key-transformer/src/__tests__/__snapshots__/KeyTransformer.test.ts.snap +++ /dev/null @@ -1,1855 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Check KeyTransformer Resolver Code 1`] = ` -Object { - "Mutation.createItem.req.vtl": "## [Start] Set default values. ** -#set( $createdAt = $util.time.nowISO8601() ) -## Automatically set the createdAt timestamp. ** -$util.qr($context.args.input.put(\\"createdAt\\", $util.defaultIfNull($ctx.args.input.createdAt, $createdAt))) -## Automatically set the updatedAt timestamp. ** -$util.qr($context.args.input.put(\\"updatedAt\\", $util.defaultIfNull($ctx.args.input.updatedAt, $createdAt))) -## [End] Set default values. ** - - - - -## [Start] Set the primary @key. ** -#set( $modelObjectKey = { - \\"orderId\\": $util.dynamodb.toDynamoDB($ctx.args.input.orderId), - \\"status#createdAt\\": $util.dynamodb.toDynamoDB(\\"\${ctx.args.input.status}#\${ctx.args.input.createdAt}\\") -} ) -## [End] Set the primary @key. ** -#if( $util.isNull($dynamodbNameOverrideMap) ) - #set( $dynamodbNameOverrideMap = { - \\"status#createdAt\\": \\"statusCreatedAt\\" -} ) -#else - $util.qr($dynamodbNameOverrideMap.put(\\"status#createdAt\\", \\"statusCreatedAt\\")) -#end -$util.qr($ctx.args.input.put(\\"status#createdAt\\",\\"\${ctx.args.input.status}#\${ctx.args.input.createdAt}\\")) -## [Start] Prepare DynamoDB PutItem Request. ** -$util.qr($context.args.input.put(\\"__typename\\", \\"Item\\")) -#if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_not_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_not_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end -#else - #set( $condition = { - \\"expression\\": \\"attribute_not_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) -#end -#if( $context.args.condition ) - #set( $condition.expressionValues = {} ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"PutItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": $util.dynamodb.toDynamoDBJson($ctx.args.input.id) -} #end, - \\"attributeValues\\": $util.dynamodb.toMapValuesJson($context.args.input), - \\"condition\\": $util.toJson($condition) -} -## [End] Prepare DynamoDB PutItem Request. **", - "Mutation.createItem.res.vtl": "#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type) -#else -$util.toJson($ctx.result) -#end", - "Mutation.deleteItem.req.vtl": " - -## [Start] Set the primary @key. ** -#set( $modelObjectKey = { - \\"orderId\\": $util.dynamodb.toDynamoDB($ctx.args.input.orderId), - \\"status#createdAt\\": $util.dynamodb.toDynamoDB(\\"\${ctx.args.input.status}#\${ctx.args.input.createdAt}\\") -} ) -## [End] Set the primary @key. ** -#if( $authCondition ) - #set( $condition = $authCondition ) - #if( $modelObjectKey ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#id)\\")) - $util.qr($condition.expressionNames.put(\\"#id\\", \\"id\\")) - #end -#else - #if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - #set( $condition = { - \\"expression\\": \\"attribute_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) - #end -#end -#if( $versionedCondition ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $versionedCondition.expression\\")) - $util.qr($condition.expressionNames.putAll($versionedCondition.expressionNames)) - #set( $expressionValues = $util.defaultIfNull($condition.expressionValues, {}) ) - $util.qr($expressionValues.putAll($versionedCondition.expressionValues)) - #set( $condition.expressionValues = $expressionValues ) -#end -#if( $context.args.condition ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - #set( $conditionExpressionValues = $util.defaultIfNull($condition.expressionValues, {}) ) - $util.qr($conditionExpressionValues.putAll($conditionFilterExpressions.expressionValues)) - #set( $condition.expressionValues = $conditionExpressionValues ) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"DeleteItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": $util.dynamodb.toDynamoDBJson($ctx.args.input.id) -} #end, - \\"condition\\": $util.toJson($condition) -}", - "Mutation.deleteItem.res.vtl": "#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type) -#else -$util.toJson($ctx.result) -#end", - "Mutation.updateItem.req.vtl": " - - - -## [Start] Set the primary @key. ** -#set( $modelObjectKey = { - \\"orderId\\": $util.dynamodb.toDynamoDB($ctx.args.input.orderId), - \\"status#createdAt\\": $util.dynamodb.toDynamoDB(\\"\${ctx.args.input.status}#\${ctx.args.input.createdAt}\\") -} ) -## [End] Set the primary @key. ** -#if( $util.isNull($dynamodbNameOverrideMap) ) - #set( $dynamodbNameOverrideMap = { - \\"status#createdAt\\": \\"statusCreatedAt\\" -} ) -#else - $util.qr($dynamodbNameOverrideMap.put(\\"status#createdAt\\", \\"statusCreatedAt\\")) -#end -$util.qr($ctx.args.input.put(\\"status#createdAt\\",\\"\${ctx.args.input.status}#\${ctx.args.input.createdAt}\\")) -#set( $optionalNonNullableFields = [\\"orderId\\", \\"status\\", \\"createdAt\\", \\"name\\"] ) -#foreach( $field in $optionalNonNullableFields ) - #if( $context.arguments.input.keySet().contains($field) && $util.isNull($context.args.input.get($field)) ) -$util.error(\\"An argument you marked as Non-Null is set to Null in the query or the body of your request.\\") - #end -#end -#if( $authCondition && $authCondition.expression != \\"\\" ) - #set( $condition = $authCondition ) - #if( $modelObjectKey ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#id)\\")) - $util.qr($condition.expressionNames.put(\\"#id\\", \\"id\\")) - #end -#else - #if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - #set( $condition = { - \\"expression\\": \\"attribute_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) - #end -#end -## Automatically set the updatedAt timestamp. ** -$util.qr($context.args.input.put(\\"updatedAt\\", $util.defaultIfNull($ctx.args.input.updatedAt, $util.time.nowISO8601()))) -$util.qr($context.args.input.put(\\"__typename\\", \\"Item\\")) -## Update condition if type is @versioned ** -#if( $versionedCondition ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $versionedCondition.expression\\")) - $util.qr($condition.expressionNames.putAll($versionedCondition.expressionNames)) - $util.qr($condition.expressionValues.putAll($versionedCondition.expressionValues)) -#end -#if( $context.args.condition ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -#set( $expNames = {} ) -#set( $expValues = {} ) -#set( $expSet = {} ) -#set( $expAdd = {} ) -#set( $expRemove = [] ) -#if( $modelObjectKey ) - #set( $keyFields = [] ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($keyFields.add(\\"$entry.key\\")) - #end -#else - #set( $keyFields = [\\"id\\"] ) -#end -#foreach( $entry in $util.map.copyAndRemoveAllKeys($context.args.input, $keyFields).entrySet() ) - #if( !$util.isNull($dynamodbNameOverrideMap) && $dynamodbNameOverrideMap.containsKey(\\"$entry.key\\") ) - #set( $entryKeyAttributeName = $dynamodbNameOverrideMap.get(\\"$entry.key\\") ) - #else - #set( $entryKeyAttributeName = $entry.key ) - #end - #if( $util.isNull($entry.value) ) - #set( $discard = $expRemove.add(\\"#$entryKeyAttributeName\\") ) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - #else - $util.qr($expSet.put(\\"#$entryKeyAttributeName\\", \\":$entryKeyAttributeName\\")) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - $util.qr($expValues.put(\\":$entryKeyAttributeName\\", $util.dynamodb.toDynamoDB($entry.value))) - #end -#end -#set( $expression = \\"\\" ) -#if( !$expSet.isEmpty() ) - #set( $expression = \\"SET\\" ) - #foreach( $entry in $expSet.entrySet() ) - #set( $expression = \\"$expression $entry.key = $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expAdd.isEmpty() ) - #set( $expression = \\"$expression ADD\\" ) - #foreach( $entry in $expAdd.entrySet() ) - #set( $expression = \\"$expression $entry.key $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expRemove.isEmpty() ) - #set( $expression = \\"$expression REMOVE\\" ) - #foreach( $entry in $expRemove ) - #set( $expression = \\"$expression $entry\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#set( $update = {} ) -$util.qr($update.put(\\"expression\\", \\"$expression\\")) -#if( !$expNames.isEmpty() ) - $util.qr($update.put(\\"expressionNames\\", $expNames)) -#end -#if( !$expValues.isEmpty() ) - $util.qr($update.put(\\"expressionValues\\", $expValues)) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"UpdateItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": { - \\"S\\": $util.toJson($context.args.input.id) - } -} #end, - \\"update\\": $util.toJson($update), - \\"condition\\": $util.toJson($condition) -}", - "Mutation.updateItem.res.vtl": "#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type) -#else -$util.toJson($ctx.result) -#end", - "Query.getItem.req.vtl": "## [Start] Set the primary @key. ** -#set( $modelObjectKey = { - \\"orderId\\": $util.dynamodb.toDynamoDB($ctx.args.orderId), - \\"status#createdAt\\": $util.dynamodb.toDynamoDB(\\"\${ctx.args.status}#\${ctx.args.createdAt}\\") -} ) -## [End] Set the primary @key. ** -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": $util.dynamodb.toDynamoDBJson($ctx.args.id) -} #end -}", - "Query.getItem.res.vtl": "#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type) -#else -$util.toJson($ctx.result) -#end", - "Query.itemsByCreatedAt.req.vtl": "## [Start] Set query expression for @key ** -#set( $modelQueryExpression = {} ) -## [Start] Validate key arguments. ** -#if( !$util.isNull($ctx.args.status) && $util.isNull($ctx.args.createdAt) ) - $util.error(\\"When providing argument 'status' you must also provide arguments createdAt\\", \\"InvalidArgumentsError\\") -#end -## [End] Validate key arguments. ** -#if( !$util.isNull($ctx.args.createdAt) ) - #set( $modelQueryExpression.expression = \\"#createdAt = :createdAt\\" ) - #set( $modelQueryExpression.expressionNames = { - \\"#createdAt\\": \\"createdAt\\" -} ) - #set( $modelQueryExpression.expressionValues = { - \\":createdAt\\": { - \\"S\\": \\"$ctx.args.createdAt\\" - } -} ) -#end -## [Start] Applying Key Condition ** -#if( !$util.isNull($ctx.args.status) && !$util.isNull($ctx.args.status.beginsWith) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND begins_with(#sortKey, :sortKey)\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.status.beginsWith\\" })) -#end -#if( !$util.isNull($ctx.args.status) && !$util.isNull($ctx.args.status.between) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey BETWEEN :sortKey0 AND :sortKey1\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey0\\", { \\"S\\": \\"$ctx.args.status.between[0]\\" })) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey1\\", { \\"S\\": \\"$ctx.args.status.between[1]\\" })) -#end -#if( !$util.isNull($ctx.args.status) && !$util.isNull($ctx.args.status.eq) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey = :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.status.eq\\" })) -#end -#if( !$util.isNull($ctx.args.status) && !$util.isNull($ctx.args.status.lt) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey < :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.status.lt\\" })) -#end -#if( !$util.isNull($ctx.args.status) && !$util.isNull($ctx.args.status.le) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey <= :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.status.le\\" })) -#end -#if( !$util.isNull($ctx.args.status) && !$util.isNull($ctx.args.status.gt) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey > :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.status.gt\\" })) -#end -#if( !$util.isNull($ctx.args.status) && !$util.isNull($ctx.args.status.ge) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey >= :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.status.ge\\" })) -#end -## [End] Applying Key Condition ** -## [End] Set query expression for @key ** -#set( $limit = $util.defaultIfNull($context.args.limit, 100) ) -#set( $QueryRequest = { - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"Query\\", - \\"limit\\": $limit, - \\"query\\": $modelQueryExpression, - \\"index\\": \\"ByCreatedAt\\" -} ) -#if( !$util.isNull($ctx.args.sortDirection) - && $ctx.args.sortDirection == \\"DESC\\" ) - #set( $QueryRequest.scanIndexForward = false ) -#else - #set( $QueryRequest.scanIndexForward = true ) -#end -#if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end -$util.toJson($QueryRequest)", - "Query.itemsByCreatedAt.res.vtl": "#if( $ctx.error ) - $util.error($ctx.error.message, $ctx.error.type) -#end -$util.toJson($ctx.result)", - "Query.itemsByStatus.req.vtl": "## [Start] Set query expression for @key ** -#set( $modelQueryExpression = {} ) -## [Start] Validate key arguments. ** -#if( !$util.isNull($ctx.args.createdAt) && $util.isNull($ctx.args.status) ) - $util.error(\\"When providing argument 'createdAt' you must also provide arguments status\\", \\"InvalidArgumentsError\\") -#end -## [End] Validate key arguments. ** -#if( !$util.isNull($ctx.args.status) ) - #set( $modelQueryExpression.expression = \\"#status = :status\\" ) - #set( $modelQueryExpression.expressionNames = { - \\"#status\\": \\"status\\" -} ) - #set( $modelQueryExpression.expressionValues = { - \\":status\\": { - \\"S\\": \\"$ctx.args.status\\" - } -} ) -#end -## [Start] Applying Key Condition ** -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.beginsWith) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND begins_with(#sortKey, :sortKey)\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.beginsWith\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.between) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey BETWEEN :sortKey0 AND :sortKey1\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey0\\", { \\"S\\": \\"$ctx.args.createdAt.between[0]\\" })) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey1\\", { \\"S\\": \\"$ctx.args.createdAt.between[1]\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.eq) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey = :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.eq\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.lt) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey < :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.lt\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.le) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey <= :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.le\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.gt) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey > :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.gt\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.ge) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey >= :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.ge\\" })) -#end -## [End] Applying Key Condition ** -## [End] Set query expression for @key ** -#set( $limit = $util.defaultIfNull($context.args.limit, 100) ) -#set( $QueryRequest = { - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"Query\\", - \\"limit\\": $limit, - \\"query\\": $modelQueryExpression, - \\"index\\": \\"ByStatus\\" -} ) -#if( !$util.isNull($ctx.args.sortDirection) - && $ctx.args.sortDirection == \\"DESC\\" ) - #set( $QueryRequest.scanIndexForward = false ) -#else - #set( $QueryRequest.scanIndexForward = true ) -#end -#if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end -$util.toJson($QueryRequest)", - "Query.itemsByStatus.res.vtl": "#if( $ctx.error ) - $util.error($ctx.error.message, $ctx.error.type) -#end -$util.toJson($ctx.result)", - "Query.listItems.req.vtl": "## [Start] Set query expression for @key ** -#if( $util.isNull($ctx.args.orderId) && !$util.isNull($ctx.args.sortDirection) ) - $util.error(\\"When providing argument 'sortDirection' you must also provide argument 'orderId'.\\", \\"InvalidArgumentsError\\") -#end -#set( $modelQueryExpression = {} ) -## [Start] Validate key arguments. ** -#if( !$util.isNull($ctx.args.statusCreatedAt) && $util.isNullOrBlank($ctx.args.orderId) ) - $util.error(\\"When providing argument 'statusCreatedAt' you must also provide 'orderId'.\\", \\"InvalidArgumentsError\\") -#end -#if( !$util.isNull($ctx.args.statusCreatedAt) ) - #set( $sortKeyArgumentOperations = $ctx.args.statusCreatedAt.keySet() ) - #if( $sortKeyArgumentOperations.size() > 1 ) - $util.error(\\"Argument statusCreatedAt must specify at most one key condition operation.\\", \\"InvalidArgumentsError\\") - #end - #foreach( $operation in $sortKeyArgumentOperations ) - #if( $operation == \\"between\\" ) - #if( $ctx.args.statusCreatedAt.between.size() != 2 ) - $util.error(\\"Argument 'statusCreatedAt.between' expects exactly two elements.\\", \\"InvalidArgumentsError\\") - #end - #if( !$util.isNullOrBlank($ctx.args.statusCreatedAt.between[0].createdAt) && $util.isNullOrBlank($ctx.args.statusCreatedAt.between[0].status) ) - $util.error(\\"When providing argument 'statusCreatedAt.between[0].createdAt' you must also provide 'statusCreatedAt.between[0].status'.\\", \\"InvalidArgumentsError\\") - #end - #if( !$util.isNullOrBlank($ctx.args.statusCreatedAt.between[1].createdAt) && $util.isNullOrBlank($ctx.args.statusCreatedAt.between[1].status) ) - $util.error(\\"When providing argument 'statusCreatedAt.between[1].createdAt' you must also provide 'statusCreatedAt.between[1].status'.\\", \\"InvalidArgumentsError\\") - #end - #else - #if( !$util.isNullOrBlank($ctx.args.statusCreatedAt.get(\\"$operation\\").createdAt) && $util.isNullOrBlank($ctx.args.statusCreatedAt.get(\\"$operation\\").status) ) - $util.error(\\"When providing argument 'statusCreatedAt.$operation.createdAt' you must also provide 'statusCreatedAt.$operation.status'.\\", \\"InvalidArgumentsError\\") - #end - #end - #end -#end -## [End] Validate key arguments. ** -#if( !$util.isNull($ctx.args.orderId) ) - #set( $modelQueryExpression.expression = \\"#orderId = :orderId\\" ) - #set( $modelQueryExpression.expressionNames = { - \\"#orderId\\": \\"orderId\\" -} ) - #set( $modelQueryExpression.expressionValues = { - \\":orderId\\": { - \\"S\\": \\"$ctx.args.orderId\\" - } -} ) -#end -## [Start] Applying Key Condition ** -#set( $sortKeyValue = \\"\\" ) -#set( $sortKeyValue2 = \\"\\" ) -#if( !$util.isNull($ctx.args.statusCreatedAt) && !$util.isNull($ctx.args.statusCreatedAt.beginsWith) ) -#if( !$util.isNull($ctx.args.statusCreatedAt.beginsWith.status) ) #set( $sortKeyValue = \\"$ctx.args.statusCreatedAt.beginsWith.status\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.beginsWith.createdAt) ) #set( $sortKeyValue = \\"$sortKeyValue#$ctx.args.statusCreatedAt.beginsWith.createdAt\\" ) #end - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND begins_with(#sortKey, :sortKey)\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status#createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$sortKeyValue\\" })) -#end -#if( !$util.isNull($ctx.args.statusCreatedAt) && !$util.isNull($ctx.args.statusCreatedAt.between) ) - #if( $ctx.args.statusCreatedAt.between.size() != 2 ) - $util.error(\\"Argument statusCreatedAt.between expects exactly 2 elements.\\") - #end -#if( !$util.isNull($ctx.args.statusCreatedAt.between[0].status) ) #set( $sortKeyValue = \\"$ctx.args.statusCreatedAt.between[0].status\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.between[0].createdAt) ) #set( $sortKeyValue = \\"$sortKeyValue#$ctx.args.statusCreatedAt.between[0].createdAt\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.between[1].status) ) #set( $sortKeyValue2 = \\"$ctx.args.statusCreatedAt.between[1].status\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.between[1].createdAt) ) #set( $sortKeyValue2 = \\"$sortKeyValue2#$ctx.args.statusCreatedAt.between[1].createdAt\\" ) #end - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey BETWEEN :sortKey0 AND :sortKey1\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status#createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey0\\", { \\"S\\": \\"$sortKeyValue\\" })) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey1\\", { \\"S\\": \\"$sortKeyValue2\\" })) -#end -#if( !$util.isNull($ctx.args.statusCreatedAt) && !$util.isNull($ctx.args.statusCreatedAt.eq) ) -#if( !$util.isNull($ctx.args.statusCreatedAt.eq.status) ) #set( $sortKeyValue = \\"$ctx.args.statusCreatedAt.eq.status\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.eq.createdAt) ) #set( $sortKeyValue = \\"$sortKeyValue#$ctx.args.statusCreatedAt.eq.createdAt\\" ) #end - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey = :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status#createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$sortKeyValue\\" })) -#end -#if( !$util.isNull($ctx.args.statusCreatedAt) && !$util.isNull($ctx.args.statusCreatedAt.lt) ) -#if( !$util.isNull($ctx.args.statusCreatedAt.lt.status) ) #set( $sortKeyValue = \\"$ctx.args.statusCreatedAt.lt.status\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.lt.createdAt) ) #set( $sortKeyValue = \\"$sortKeyValue#$ctx.args.statusCreatedAt.lt.createdAt\\" ) #end - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey < :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status#createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$sortKeyValue\\" })) -#end -#if( !$util.isNull($ctx.args.statusCreatedAt) && !$util.isNull($ctx.args.statusCreatedAt.le) ) -#if( !$util.isNull($ctx.args.statusCreatedAt.le.status) ) #set( $sortKeyValue = \\"$ctx.args.statusCreatedAt.le.status\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.le.createdAt) ) #set( $sortKeyValue = \\"$sortKeyValue#$ctx.args.statusCreatedAt.le.createdAt\\" ) #end - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey <= :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status#createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$sortKeyValue\\" })) -#end -#if( !$util.isNull($ctx.args.statusCreatedAt) && !$util.isNull($ctx.args.statusCreatedAt.gt) ) -#if( !$util.isNull($ctx.args.statusCreatedAt.gt.status) ) #set( $sortKeyValue = \\"$ctx.args.statusCreatedAt.gt.status\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.gt.createdAt) ) #set( $sortKeyValue = \\"$sortKeyValue#$ctx.args.statusCreatedAt.gt.createdAt\\" ) #end - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey > :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status#createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$sortKeyValue\\" })) -#end -#if( !$util.isNull($ctx.args.statusCreatedAt) && !$util.isNull($ctx.args.statusCreatedAt.ge) ) -#if( !$util.isNull($ctx.args.statusCreatedAt.ge.status) ) #set( $sortKeyValue = \\"$ctx.args.statusCreatedAt.ge.status\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.ge.createdAt) ) #set( $sortKeyValue = \\"$sortKeyValue#$ctx.args.statusCreatedAt.ge.createdAt\\" ) #end - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey >= :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status#createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$sortKeyValue\\" })) -#end - - -## [End] Applying Key Condition ** -## [End] Set query expression for @key ** -#set( $limit = $util.defaultIfNull($context.args.limit, 100) ) -#set( $ListRequest = { - \\"version\\": \\"2018-05-29\\", - \\"limit\\": $limit -} ) -#if( $context.args.nextToken ) - #set( $ListRequest.nextToken = $context.args.nextToken ) -#end -#if( $context.args.filter ) - #set( $ListRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) -#end -#if( !$util.isNull($modelQueryExpression) - && !$util.isNullOrEmpty($modelQueryExpression.expression) ) - $util.qr($ListRequest.put(\\"operation\\", \\"Query\\")) - $util.qr($ListRequest.put(\\"query\\", $modelQueryExpression)) - #if( !$util.isNull($ctx.args.sortDirection) && $ctx.args.sortDirection == \\"DESC\\" ) - #set( $ListRequest.scanIndexForward = false ) - #else - #set( $ListRequest.scanIndexForward = true ) - #end -#else - $util.qr($ListRequest.put(\\"operation\\", \\"Scan\\")) -#end -$util.toJson($ListRequest)", - "Query.listItems.res.vtl": "#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type) -#else -$util.toJson($ctx.result) -#end", -} -`; - -exports[`Check KeyTransformer Resolver Code when sync enabled 1`] = ` -Object { - "Mutation.createItem.req.vtl": "## [Start] Set default values. ** -#set( $createdAt = $util.time.nowISO8601() ) -## Automatically set the createdAt timestamp. ** -$util.qr($context.args.input.put(\\"createdAt\\", $util.defaultIfNull($ctx.args.input.createdAt, $createdAt))) -## Automatically set the updatedAt timestamp. ** -$util.qr($context.args.input.put(\\"updatedAt\\", $util.defaultIfNull($ctx.args.input.updatedAt, $createdAt))) -## [End] Set default values. ** - - - - -## [Start] Set the primary @key. ** -#set( $modelObjectKey = { - \\"orderId\\": $util.dynamodb.toDynamoDB($ctx.args.input.orderId), - \\"status#createdAt\\": $util.dynamodb.toDynamoDB(\\"\${ctx.args.input.status}#\${ctx.args.input.createdAt}\\") -} ) -## [End] Set the primary @key. ** -#if( $util.isNull($dynamodbNameOverrideMap) ) - #set( $dynamodbNameOverrideMap = { - \\"status#createdAt\\": \\"statusCreatedAt\\" -} ) -#else - $util.qr($dynamodbNameOverrideMap.put(\\"status#createdAt\\", \\"statusCreatedAt\\")) -#end -$util.qr($ctx.args.input.put(\\"status#createdAt\\",\\"\${ctx.args.input.status}#\${ctx.args.input.createdAt}\\")) -## [Start] Prepare DynamoDB PutItem Request. ** -$util.qr($context.args.input.put(\\"__typename\\", \\"Item\\")) -#if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_not_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_not_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end -#else - #set( $condition = { - \\"expression\\": \\"attribute_not_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) -#end -#if( $context.args.condition ) - #set( $condition.expressionValues = {} ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"PutItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": $util.dynamodb.toDynamoDBJson($ctx.args.input.id) -} #end, - \\"attributeValues\\": $util.dynamodb.toMapValuesJson($context.args.input), - \\"condition\\": $util.toJson($condition) -} -## [End] Prepare DynamoDB PutItem Request. **", - "Mutation.createItem.res.vtl": "#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type, $ctx.result) -#else -$util.toJson($ctx.result) -#end", - "Mutation.deleteItem.req.vtl": " - -## [Start] Set the primary @key. ** -#set( $modelObjectKey = { - \\"orderId\\": $util.dynamodb.toDynamoDB($ctx.args.input.orderId), - \\"status#createdAt\\": $util.dynamodb.toDynamoDB(\\"\${ctx.args.input.status}#\${ctx.args.input.createdAt}\\") -} ) -## [End] Set the primary @key. ** -#if( $authCondition ) - #set( $condition = $authCondition ) - #if( $modelObjectKey ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#id)\\")) - $util.qr($condition.expressionNames.put(\\"#id\\", \\"id\\")) - #end -#else - #if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - #set( $condition = { - \\"expression\\": \\"attribute_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) - #end -#end -#if( $versionedCondition ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $versionedCondition.expression\\")) - $util.qr($condition.expressionNames.putAll($versionedCondition.expressionNames)) - #set( $expressionValues = $util.defaultIfNull($condition.expressionValues, {}) ) - $util.qr($expressionValues.putAll($versionedCondition.expressionValues)) - #set( $condition.expressionValues = $expressionValues ) -#end -#if( $context.args.condition ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - #set( $conditionExpressionValues = $util.defaultIfNull($condition.expressionValues, {}) ) - $util.qr($conditionExpressionValues.putAll($conditionFilterExpressions.expressionValues)) - #set( $condition.expressionValues = $conditionExpressionValues ) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"DeleteItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": $util.dynamodb.toDynamoDBJson($ctx.args.input.id) -} #end, - \\"condition\\": $util.toJson($condition), - \\"_version\\": $util.defaultIfNull($ctx.args.input[\\"_version\\"], \\"0\\") -}", - "Mutation.deleteItem.res.vtl": "#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type, $ctx.result) -#else -$util.toJson($ctx.result) -#end", - "Mutation.updateItem.req.vtl": " - - - -## [Start] Set the primary @key. ** -#set( $modelObjectKey = { - \\"orderId\\": $util.dynamodb.toDynamoDB($ctx.args.input.orderId), - \\"status#createdAt\\": $util.dynamodb.toDynamoDB(\\"\${ctx.args.input.status}#\${ctx.args.input.createdAt}\\") -} ) -## [End] Set the primary @key. ** -#if( $util.isNull($dynamodbNameOverrideMap) ) - #set( $dynamodbNameOverrideMap = { - \\"status#createdAt\\": \\"statusCreatedAt\\" -} ) -#else - $util.qr($dynamodbNameOverrideMap.put(\\"status#createdAt\\", \\"statusCreatedAt\\")) -#end -$util.qr($ctx.args.input.put(\\"status#createdAt\\",\\"\${ctx.args.input.status}#\${ctx.args.input.createdAt}\\")) -#set( $optionalNonNullableFields = [\\"orderId\\", \\"status\\", \\"createdAt\\", \\"name\\"] ) -#foreach( $field in $optionalNonNullableFields ) - #if( $context.arguments.input.keySet().contains($field) && $util.isNull($context.args.input.get($field)) ) -$util.error(\\"An argument you marked as Non-Null is set to Null in the query or the body of your request.\\") - #end -#end -#if( $authCondition && $authCondition.expression != \\"\\" ) - #set( $condition = $authCondition ) - #if( $modelObjectKey ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#id)\\")) - $util.qr($condition.expressionNames.put(\\"#id\\", \\"id\\")) - #end -#else - #if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - #set( $condition = { - \\"expression\\": \\"attribute_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) - #end -#end -## Automatically set the updatedAt timestamp. ** -$util.qr($context.args.input.put(\\"updatedAt\\", $util.defaultIfNull($ctx.args.input.updatedAt, $util.time.nowISO8601()))) -$util.qr($context.args.input.put(\\"__typename\\", \\"Item\\")) -## Update condition if type is @versioned ** -#if( $versionedCondition ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $versionedCondition.expression\\")) - $util.qr($condition.expressionNames.putAll($versionedCondition.expressionNames)) - $util.qr($condition.expressionValues.putAll($versionedCondition.expressionValues)) -#end -#if( $context.args.condition ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -#set( $expNames = {} ) -#set( $expValues = {} ) -#set( $expSet = {} ) -#set( $expAdd = {} ) -#set( $expRemove = [] ) -#if( $modelObjectKey ) - #set( $keyFields = [\\"_version\\", \\"_deleted\\", \\"_lastChangedAt\\"] ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($keyFields.add(\\"$entry.key\\")) - #end -#else - #set( $keyFields = [\\"id\\", \\"_version\\", \\"_deleted\\", \\"_lastChangedAt\\"] ) -#end -#foreach( $entry in $util.map.copyAndRemoveAllKeys($context.args.input, $keyFields).entrySet() ) - #if( !$util.isNull($dynamodbNameOverrideMap) && $dynamodbNameOverrideMap.containsKey(\\"$entry.key\\") ) - #set( $entryKeyAttributeName = $dynamodbNameOverrideMap.get(\\"$entry.key\\") ) - #else - #set( $entryKeyAttributeName = $entry.key ) - #end - #if( $util.isNull($entry.value) ) - #set( $discard = $expRemove.add(\\"#$entryKeyAttributeName\\") ) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - #else - $util.qr($expSet.put(\\"#$entryKeyAttributeName\\", \\":$entryKeyAttributeName\\")) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - $util.qr($expValues.put(\\":$entryKeyAttributeName\\", $util.dynamodb.toDynamoDB($entry.value))) - #end -#end -#set( $expression = \\"\\" ) -#if( !$expSet.isEmpty() ) - #set( $expression = \\"SET\\" ) - #foreach( $entry in $expSet.entrySet() ) - #set( $expression = \\"$expression $entry.key = $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expAdd.isEmpty() ) - #set( $expression = \\"$expression ADD\\" ) - #foreach( $entry in $expAdd.entrySet() ) - #set( $expression = \\"$expression $entry.key $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expRemove.isEmpty() ) - #set( $expression = \\"$expression REMOVE\\" ) - #foreach( $entry in $expRemove ) - #set( $expression = \\"$expression $entry\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#set( $update = {} ) -$util.qr($update.put(\\"expression\\", \\"$expression\\")) -#if( !$expNames.isEmpty() ) - $util.qr($update.put(\\"expressionNames\\", $expNames)) -#end -#if( !$expValues.isEmpty() ) - $util.qr($update.put(\\"expressionValues\\", $expValues)) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"UpdateItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": { - \\"S\\": $util.toJson($context.args.input.id) - } -} #end, - \\"update\\": $util.toJson($update), - \\"condition\\": $util.toJson($condition), - \\"_version\\": $util.defaultIfNull($ctx.args.input[\\"_version\\"], \\"0\\") -}", - "Mutation.updateItem.res.vtl": "#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type, $ctx.result) -#else -$util.toJson($ctx.result) -#end", - "Query.getItem.req.vtl": "## [Start] Set the primary @key. ** -#set( $modelObjectKey = { - \\"orderId\\": $util.dynamodb.toDynamoDB($ctx.args.orderId), - \\"status#createdAt\\": $util.dynamodb.toDynamoDB(\\"\${ctx.args.status}#\${ctx.args.createdAt}\\") -} ) -## [End] Set the primary @key. ** -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": $util.dynamodb.toDynamoDBJson($ctx.args.id) -} #end -}", - "Query.getItem.res.vtl": "#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type, $ctx.result) -#else -$util.toJson($ctx.result) -#end", - "Query.itemsByCreatedAt.req.vtl": "## [Start] Set query expression for @key ** -#set( $modelQueryExpression = {} ) -## [Start] Validate key arguments. ** -#if( !$util.isNull($ctx.args.status) && $util.isNull($ctx.args.createdAt) ) - $util.error(\\"When providing argument 'status' you must also provide arguments createdAt\\", \\"InvalidArgumentsError\\") -#end -## [End] Validate key arguments. ** -#if( !$util.isNull($ctx.args.createdAt) ) - #set( $modelQueryExpression.expression = \\"#createdAt = :createdAt\\" ) - #set( $modelQueryExpression.expressionNames = { - \\"#createdAt\\": \\"createdAt\\" -} ) - #set( $modelQueryExpression.expressionValues = { - \\":createdAt\\": { - \\"S\\": \\"$ctx.args.createdAt\\" - } -} ) -#end -## [Start] Applying Key Condition ** -#if( !$util.isNull($ctx.args.status) && !$util.isNull($ctx.args.status.beginsWith) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND begins_with(#sortKey, :sortKey)\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.status.beginsWith\\" })) -#end -#if( !$util.isNull($ctx.args.status) && !$util.isNull($ctx.args.status.between) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey BETWEEN :sortKey0 AND :sortKey1\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey0\\", { \\"S\\": \\"$ctx.args.status.between[0]\\" })) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey1\\", { \\"S\\": \\"$ctx.args.status.between[1]\\" })) -#end -#if( !$util.isNull($ctx.args.status) && !$util.isNull($ctx.args.status.eq) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey = :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.status.eq\\" })) -#end -#if( !$util.isNull($ctx.args.status) && !$util.isNull($ctx.args.status.lt) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey < :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.status.lt\\" })) -#end -#if( !$util.isNull($ctx.args.status) && !$util.isNull($ctx.args.status.le) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey <= :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.status.le\\" })) -#end -#if( !$util.isNull($ctx.args.status) && !$util.isNull($ctx.args.status.gt) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey > :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.status.gt\\" })) -#end -#if( !$util.isNull($ctx.args.status) && !$util.isNull($ctx.args.status.ge) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey >= :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.status.ge\\" })) -#end -## [End] Applying Key Condition ** -## [End] Set query expression for @key ** -#set( $limit = $util.defaultIfNull($context.args.limit, 100) ) -#set( $QueryRequest = { - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"Query\\", - \\"limit\\": $limit, - \\"query\\": $modelQueryExpression, - \\"index\\": \\"ByCreatedAt\\" -} ) -#if( !$util.isNull($ctx.args.sortDirection) - && $ctx.args.sortDirection == \\"DESC\\" ) - #set( $QueryRequest.scanIndexForward = false ) -#else - #set( $QueryRequest.scanIndexForward = true ) -#end -#if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end -$util.toJson($QueryRequest)", - "Query.itemsByCreatedAt.res.vtl": "#if( $ctx.error ) - $util.error($ctx.error.message, $ctx.error.type) -#end -$util.toJson($ctx.result)", - "Query.itemsByStatus.req.vtl": "## [Start] Set query expression for @key ** -#set( $modelQueryExpression = {} ) -## [Start] Validate key arguments. ** -#if( !$util.isNull($ctx.args.createdAt) && $util.isNull($ctx.args.status) ) - $util.error(\\"When providing argument 'createdAt' you must also provide arguments status\\", \\"InvalidArgumentsError\\") -#end -## [End] Validate key arguments. ** -#if( !$util.isNull($ctx.args.status) ) - #set( $modelQueryExpression.expression = \\"#status = :status\\" ) - #set( $modelQueryExpression.expressionNames = { - \\"#status\\": \\"status\\" -} ) - #set( $modelQueryExpression.expressionValues = { - \\":status\\": { - \\"S\\": \\"$ctx.args.status\\" - } -} ) -#end -## [Start] Applying Key Condition ** -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.beginsWith) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND begins_with(#sortKey, :sortKey)\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.beginsWith\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.between) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey BETWEEN :sortKey0 AND :sortKey1\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey0\\", { \\"S\\": \\"$ctx.args.createdAt.between[0]\\" })) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey1\\", { \\"S\\": \\"$ctx.args.createdAt.between[1]\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.eq) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey = :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.eq\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.lt) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey < :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.lt\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.le) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey <= :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.le\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.gt) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey > :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.gt\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.ge) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey >= :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.ge\\" })) -#end -## [End] Applying Key Condition ** -## [End] Set query expression for @key ** -#set( $limit = $util.defaultIfNull($context.args.limit, 100) ) -#set( $QueryRequest = { - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"Query\\", - \\"limit\\": $limit, - \\"query\\": $modelQueryExpression, - \\"index\\": \\"ByStatus\\" -} ) -#if( !$util.isNull($ctx.args.sortDirection) - && $ctx.args.sortDirection == \\"DESC\\" ) - #set( $QueryRequest.scanIndexForward = false ) -#else - #set( $QueryRequest.scanIndexForward = true ) -#end -#if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end -$util.toJson($QueryRequest)", - "Query.itemsByStatus.res.vtl": "#if( $ctx.error ) - $util.error($ctx.error.message, $ctx.error.type) -#end -$util.toJson($ctx.result)", - "Query.listItems.req.vtl": "## [Start] Set query expression for @key ** -#if( $util.isNull($ctx.args.orderId) && !$util.isNull($ctx.args.sortDirection) ) - $util.error(\\"When providing argument 'sortDirection' you must also provide argument 'orderId'.\\", \\"InvalidArgumentsError\\") -#end -#set( $modelQueryExpression = {} ) -## [Start] Validate key arguments. ** -#if( !$util.isNull($ctx.args.statusCreatedAt) && $util.isNullOrBlank($ctx.args.orderId) ) - $util.error(\\"When providing argument 'statusCreatedAt' you must also provide 'orderId'.\\", \\"InvalidArgumentsError\\") -#end -#if( !$util.isNull($ctx.args.statusCreatedAt) ) - #set( $sortKeyArgumentOperations = $ctx.args.statusCreatedAt.keySet() ) - #if( $sortKeyArgumentOperations.size() > 1 ) - $util.error(\\"Argument statusCreatedAt must specify at most one key condition operation.\\", \\"InvalidArgumentsError\\") - #end - #foreach( $operation in $sortKeyArgumentOperations ) - #if( $operation == \\"between\\" ) - #if( $ctx.args.statusCreatedAt.between.size() != 2 ) - $util.error(\\"Argument 'statusCreatedAt.between' expects exactly two elements.\\", \\"InvalidArgumentsError\\") - #end - #if( !$util.isNullOrBlank($ctx.args.statusCreatedAt.between[0].createdAt) && $util.isNullOrBlank($ctx.args.statusCreatedAt.between[0].status) ) - $util.error(\\"When providing argument 'statusCreatedAt.between[0].createdAt' you must also provide 'statusCreatedAt.between[0].status'.\\", \\"InvalidArgumentsError\\") - #end - #if( !$util.isNullOrBlank($ctx.args.statusCreatedAt.between[1].createdAt) && $util.isNullOrBlank($ctx.args.statusCreatedAt.between[1].status) ) - $util.error(\\"When providing argument 'statusCreatedAt.between[1].createdAt' you must also provide 'statusCreatedAt.between[1].status'.\\", \\"InvalidArgumentsError\\") - #end - #else - #if( !$util.isNullOrBlank($ctx.args.statusCreatedAt.get(\\"$operation\\").createdAt) && $util.isNullOrBlank($ctx.args.statusCreatedAt.get(\\"$operation\\").status) ) - $util.error(\\"When providing argument 'statusCreatedAt.$operation.createdAt' you must also provide 'statusCreatedAt.$operation.status'.\\", \\"InvalidArgumentsError\\") - #end - #end - #end -#end -## [End] Validate key arguments. ** -#if( !$util.isNull($ctx.args.orderId) ) - #set( $modelQueryExpression.expression = \\"#orderId = :orderId\\" ) - #set( $modelQueryExpression.expressionNames = { - \\"#orderId\\": \\"orderId\\" -} ) - #set( $modelQueryExpression.expressionValues = { - \\":orderId\\": { - \\"S\\": \\"$ctx.args.orderId\\" - } -} ) -#end -## [Start] Applying Key Condition ** -#set( $sortKeyValue = \\"\\" ) -#set( $sortKeyValue2 = \\"\\" ) -#if( !$util.isNull($ctx.args.statusCreatedAt) && !$util.isNull($ctx.args.statusCreatedAt.beginsWith) ) -#if( !$util.isNull($ctx.args.statusCreatedAt.beginsWith.status) ) #set( $sortKeyValue = \\"$ctx.args.statusCreatedAt.beginsWith.status\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.beginsWith.createdAt) ) #set( $sortKeyValue = \\"$sortKeyValue#$ctx.args.statusCreatedAt.beginsWith.createdAt\\" ) #end - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND begins_with(#sortKey, :sortKey)\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status#createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$sortKeyValue\\" })) -#end -#if( !$util.isNull($ctx.args.statusCreatedAt) && !$util.isNull($ctx.args.statusCreatedAt.between) ) - #if( $ctx.args.statusCreatedAt.between.size() != 2 ) - $util.error(\\"Argument statusCreatedAt.between expects exactly 2 elements.\\") - #end -#if( !$util.isNull($ctx.args.statusCreatedAt.between[0].status) ) #set( $sortKeyValue = \\"$ctx.args.statusCreatedAt.between[0].status\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.between[0].createdAt) ) #set( $sortKeyValue = \\"$sortKeyValue#$ctx.args.statusCreatedAt.between[0].createdAt\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.between[1].status) ) #set( $sortKeyValue2 = \\"$ctx.args.statusCreatedAt.between[1].status\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.between[1].createdAt) ) #set( $sortKeyValue2 = \\"$sortKeyValue2#$ctx.args.statusCreatedAt.between[1].createdAt\\" ) #end - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey BETWEEN :sortKey0 AND :sortKey1\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status#createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey0\\", { \\"S\\": \\"$sortKeyValue\\" })) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey1\\", { \\"S\\": \\"$sortKeyValue2\\" })) -#end -#if( !$util.isNull($ctx.args.statusCreatedAt) && !$util.isNull($ctx.args.statusCreatedAt.eq) ) -#if( !$util.isNull($ctx.args.statusCreatedAt.eq.status) ) #set( $sortKeyValue = \\"$ctx.args.statusCreatedAt.eq.status\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.eq.createdAt) ) #set( $sortKeyValue = \\"$sortKeyValue#$ctx.args.statusCreatedAt.eq.createdAt\\" ) #end - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey = :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status#createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$sortKeyValue\\" })) -#end -#if( !$util.isNull($ctx.args.statusCreatedAt) && !$util.isNull($ctx.args.statusCreatedAt.lt) ) -#if( !$util.isNull($ctx.args.statusCreatedAt.lt.status) ) #set( $sortKeyValue = \\"$ctx.args.statusCreatedAt.lt.status\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.lt.createdAt) ) #set( $sortKeyValue = \\"$sortKeyValue#$ctx.args.statusCreatedAt.lt.createdAt\\" ) #end - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey < :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status#createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$sortKeyValue\\" })) -#end -#if( !$util.isNull($ctx.args.statusCreatedAt) && !$util.isNull($ctx.args.statusCreatedAt.le) ) -#if( !$util.isNull($ctx.args.statusCreatedAt.le.status) ) #set( $sortKeyValue = \\"$ctx.args.statusCreatedAt.le.status\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.le.createdAt) ) #set( $sortKeyValue = \\"$sortKeyValue#$ctx.args.statusCreatedAt.le.createdAt\\" ) #end - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey <= :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status#createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$sortKeyValue\\" })) -#end -#if( !$util.isNull($ctx.args.statusCreatedAt) && !$util.isNull($ctx.args.statusCreatedAt.gt) ) -#if( !$util.isNull($ctx.args.statusCreatedAt.gt.status) ) #set( $sortKeyValue = \\"$ctx.args.statusCreatedAt.gt.status\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.gt.createdAt) ) #set( $sortKeyValue = \\"$sortKeyValue#$ctx.args.statusCreatedAt.gt.createdAt\\" ) #end - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey > :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status#createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$sortKeyValue\\" })) -#end -#if( !$util.isNull($ctx.args.statusCreatedAt) && !$util.isNull($ctx.args.statusCreatedAt.ge) ) -#if( !$util.isNull($ctx.args.statusCreatedAt.ge.status) ) #set( $sortKeyValue = \\"$ctx.args.statusCreatedAt.ge.status\\" ) #end -#if( !$util.isNull($ctx.args.statusCreatedAt.ge.createdAt) ) #set( $sortKeyValue = \\"$sortKeyValue#$ctx.args.statusCreatedAt.ge.createdAt\\" ) #end - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey >= :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"status#createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$sortKeyValue\\" })) -#end - - -## [End] Applying Key Condition ** -## [End] Set query expression for @key ** -#set( $limit = $util.defaultIfNull($context.args.limit, 100) ) -#set( $ListRequest = { - \\"version\\": \\"2018-05-29\\", - \\"limit\\": $limit -} ) -#if( $context.args.nextToken ) - #set( $ListRequest.nextToken = $context.args.nextToken ) -#end -#if( $context.args.filter ) - #set( $ListRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) -#end -#if( !$util.isNull($modelQueryExpression) - && !$util.isNullOrEmpty($modelQueryExpression.expression) ) - $util.qr($ListRequest.put(\\"operation\\", \\"Query\\")) - $util.qr($ListRequest.put(\\"query\\", $modelQueryExpression)) - #if( !$util.isNull($ctx.args.sortDirection) && $ctx.args.sortDirection == \\"DESC\\" ) - #set( $ListRequest.scanIndexForward = false ) - #else - #set( $ListRequest.scanIndexForward = true ) - #end -#else - $util.qr($ListRequest.put(\\"operation\\", \\"Scan\\")) -#end -$util.toJson($ListRequest)", - "Query.listItems.res.vtl": "#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type, $ctx.result) -#else -$util.toJson($ctx.result) -#end", - "Query.syncItems.req.vtl": "## [Start] Set map initialization for @key ** -#set( $index = \\"\\" ) -#set( $scan = true ) -#set( $filterMap = {} ) -#set( $QueryMap = {} ) -#set( $PkMap = {} ) -#set( $filterArgsMap = {} ) -## [End] Set map initialization for @key ** -## [Start] Set query expression for @key ** -$util.qr($QueryMap.put('orderId+status+createdAt' , 'dbTable')) -$util.qr($PkMap.put('orderId' , 'dbTable')) -## [End] Set query expression for @key ** -## [Start] Set query expression for @key ** -$util.qr($QueryMap.put('status+createdAt' , 'ByStatus')) -$util.qr($PkMap.put('status' , 'ByStatus')) -## [End] Set query expression for @key ** -## [Start] Set query expression for @key ** -$util.qr($QueryMap.put('createdAt+status' , 'ByCreatedAt')) -$util.qr($PkMap.put('createdAt' , 'ByCreatedAt')) -## [End] Set query expression for @key ** -## [Start] Set query expression for @key ** -#set( $filterArgsMap = $ctx.args.filter.get(\\"and\\") ) -#if( !$util.isNullOrEmpty($filterArgsMap) && ($util.isNull($ctx.args.lastSync) || $ctx.args.lastSync == 0) ) - #set( $json = $filterArgsMap ) - #foreach( $item in $json ) - #set( $ind = $foreach.index ) - #foreach( $entry in $item.entrySet() ) - #if( $ind == 0 && !$util.isNullOrEmpty($entry.value.eq) && !$util.isNullOrEmpty($PkMap.get($entry.key)) ) - #set( $pk = $entry.key ) - #set( $scan = false ) - $util.qr($ctx.args.put($pk,$entry.value.eq)) - #set( $index = $PkMap.get($pk) ) - #end - #if( $ind == 1 && !$util.isNullOrEmpty($pk) && !$util.isNullOrEmpty($QueryMap.get(\\"\${pk}+$entry.key\\")) ) - #set( $sk = $entry.key ) - $util.qr($ctx.args.put($sk,$entry.value)) - #set( $index = $QueryMap.get(\\"\${pk}+$sk\\") ) - #else - #if( $ind > 0 ) - $util.qr($filterMap.put($entry.key,$entry.value)) - #end - #end - #end - #end -#else - #set( $filterMap = $ctx.args.filter ) -#end -## [End] Set query expression for @key ** -## [Start] Set Primary Key initialization @key ** -#set( $modelQueryExpression = {} ) -#if( !$util.isNull($pk) ) - #set( $modelQueryExpression.expression = \\"#pk = :pk\\" ) - #set( $modelQueryExpression.expressionNames = { - \\"#pk\\": \\"$pk\\" -} ) - #set( $modelQueryExpression.expressionValues = { - \\":pk\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($pk))) -} ) -#end -## [End] Set Primary Key initialization @key ** -## [Start] Applying Key Condition ** -#if( !$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).beginsWith) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND begins_with(#sortKey, :sortKey)\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", $sk)) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).beginsWith)))) -#end -#if( !$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).between) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey BETWEEN :sortKey0 AND :sortKey1\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", $sk)) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).between[0])))) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).between[1])))) -#end -#if( !$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).eq) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey = :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", $sk)) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).eq)))) -#end -#if( !$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).lt) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey < :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", $sk)) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).lt)))) -#end -#if( !$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).le) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey <= :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", $sk)) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).le)))) -#end -#if( !$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).gt) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey > :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", $sk)) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).gt)))) -#end -#if( !$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).ge) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey >= :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", $sk)) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).ge)))) -#end -## [End] Applying Key Condition ** -## [Start] Set query expression for @key ** -#if( !$scan ) - #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) - #set( $QueryRequest = { - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"Sync\\", - \\"limit\\": $limit, - \\"query\\": $modelQueryExpression -} ) - #if( !$util.isNull($ctx.args.sortDirection) - && $ctx.args.sortDirection == \\"DESC\\" ) - #set( $QueryRequest.scanIndexForward = false ) - #else - #set( $QueryRequest.scanIndexForward = true ) - #end -#if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end - #if( !$util.isNullOrEmpty($filterMap) ) - #set( $QueryRequest.filter = $util.parseJson($util.transform.toDynamoDBFilterExpression($filterMap)) ) - #end - #if( $index != \\"dbTable\\" ) - #set( $QueryRequest.index = $index ) - #end - $util.toJson($QueryRequest) -#else -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"Sync\\", - \\"limit\\": $util.defaultIfNull($ctx.args.limit, 100), - \\"nextToken\\": $util.toJson($util.defaultIfNull($ctx.args.nextToken, null)), - \\"lastSync\\": $util.toJson($util.defaultIfNull($ctx.args.lastSync, null)), - \\"filter\\": #if( !$util.isNullOrEmpty($ctx.args.filter) ) -$util.transform.toDynamoDBFilterExpression($ctx.args.filter) - #else -null - #end - } -#end -## [End] Set query expression for @key **", - "Query.syncItems.res.vtl": "#if( $ctx.error ) -$util.error($ctx.error.message, $ctx.error.type, $ctx.result) -#else -$util.toJson($ctx.result) -#end", -} -`; - -exports[`Check sortDirection validation code present in list resolver code for compound keys 1`] = ` -"## [Start] Set query expression for @key ** -#if( $util.isNull($ctx.args.id) && !$util.isNull($ctx.args.sortDirection) ) - $util.error(\\"When providing argument 'sortDirection' you must also provide argument 'id'.\\", \\"InvalidArgumentsError\\") -#end -#set( $modelQueryExpression = {} ) -## [Start] Validate key arguments. ** -#if( !$util.isNull($ctx.args.createdAt) && $util.isNull($ctx.args.id) ) - $util.error(\\"When providing argument 'createdAt' you must also provide arguments id\\", \\"InvalidArgumentsError\\") -#end -## [End] Validate key arguments. ** -#if( !$util.isNull($ctx.args.id) ) - #set( $modelQueryExpression.expression = \\"#id = :id\\" ) - #set( $modelQueryExpression.expressionNames = { - \\"#id\\": \\"id\\" -} ) - #set( $modelQueryExpression.expressionValues = { - \\":id\\": { - \\"S\\": \\"$ctx.args.id\\" - } -} ) -#end -## [Start] Applying Key Condition ** -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.beginsWith) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND begins_with(#sortKey, :sortKey)\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.beginsWith\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.between) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey BETWEEN :sortKey0 AND :sortKey1\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey0\\", { \\"S\\": \\"$ctx.args.createdAt.between[0]\\" })) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey1\\", { \\"S\\": \\"$ctx.args.createdAt.between[1]\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.eq) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey = :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.eq\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.lt) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey < :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.lt\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.le) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey <= :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.le\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.gt) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey > :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.gt\\" })) -#end -#if( !$util.isNull($ctx.args.createdAt) && !$util.isNull($ctx.args.createdAt.ge) ) - #set( $modelQueryExpression.expression = \\"$modelQueryExpression.expression AND #sortKey >= :sortKey\\" ) - $util.qr($modelQueryExpression.expressionNames.put(\\"#sortKey\\", \\"createdAt\\")) - $util.qr($modelQueryExpression.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.createdAt.ge\\" })) -#end -## [End] Applying Key Condition ** -## [End] Set query expression for @key ** -#set( $limit = $util.defaultIfNull($context.args.limit, 100) ) -#set( $ListRequest = { - \\"version\\": \\"2018-05-29\\", - \\"limit\\": $limit -} ) -#if( $context.args.nextToken ) - #set( $ListRequest.nextToken = $context.args.nextToken ) -#end -#if( $context.args.filter ) - #set( $ListRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) -#end -#if( !$util.isNull($modelQueryExpression) - && !$util.isNullOrEmpty($modelQueryExpression.expression) ) - $util.qr($ListRequest.put(\\"operation\\", \\"Query\\")) - $util.qr($ListRequest.put(\\"query\\", $modelQueryExpression)) - #if( !$util.isNull($ctx.args.sortDirection) && $ctx.args.sortDirection == \\"DESC\\" ) - #set( $ListRequest.scanIndexForward = false ) - #else - #set( $ListRequest.scanIndexForward = true ) - #end -#else - $util.qr($ListRequest.put(\\"operation\\", \\"Scan\\")) -#end -$util.toJson($ListRequest)" -`; - -exports[`Check sortDirection validation code present in list resolver code for simple keys 1`] = ` -"## [Start] Set query expression for @key ** -#if( !$util.isNull($ctx.args.sortDirection) ) - $util.error(\\"sortDirection is not supported for List operations without a Sort key defined.\\", \\"InvalidArgumentsError\\") -#end -#set( $modelQueryExpression = {} ) -#if( !$util.isNull($ctx.args.id) ) - #set( $modelQueryExpression.expression = \\"#id = :id\\" ) - #set( $modelQueryExpression.expressionNames = { - \\"#id\\": \\"id\\" -} ) - #set( $modelQueryExpression.expressionValues = { - \\":id\\": { - \\"S\\": \\"$ctx.args.id\\" - } -} ) -#end -## [End] Set query expression for @key ** -#set( $limit = $util.defaultIfNull($context.args.limit, 100) ) -#set( $ListRequest = { - \\"version\\": \\"2018-05-29\\", - \\"limit\\": $limit -} ) -#if( $context.args.nextToken ) - #set( $ListRequest.nextToken = $context.args.nextToken ) -#end -#if( $context.args.filter ) - #set( $ListRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) -#end -#if( !$util.isNull($modelQueryExpression) - && !$util.isNullOrEmpty($modelQueryExpression.expression) ) - $util.qr($ListRequest.put(\\"operation\\", \\"Query\\")) - $util.qr($ListRequest.put(\\"query\\", $modelQueryExpression)) - #if( !$util.isNull($ctx.args.sortDirection) && $ctx.args.sortDirection == \\"DESC\\" ) - #set( $ListRequest.scanIndexForward = false ) - #else - #set( $ListRequest.scanIndexForward = true ) - #end -#else - $util.qr($ListRequest.put(\\"operation\\", \\"Scan\\")) -#end -$util.toJson($ListRequest)" -`; - -exports[`GSI composite sort keys are wrapped in conditional to check presence in mutation 1`] = ` -"## [Start] Set default values. ** -$util.qr($context.args.input.put(\\"id\\", $util.defaultIfNull($ctx.args.input.id, $util.autoId()))) -#set( $createdAt = $util.time.nowISO8601() ) -## Automatically set the createdAt timestamp. ** -$util.qr($context.args.input.put(\\"createdAt\\", $util.defaultIfNull($ctx.args.input.createdAt, $createdAt))) -## Automatically set the updatedAt timestamp. ** -$util.qr($context.args.input.put(\\"updatedAt\\", $util.defaultIfNull($ctx.args.input.updatedAt, $createdAt))) -## [End] Set default values. ** -## [Start] Validate create mutation for @key 'byNameAndNickname'. ** -#set( $hasSeenSomeKeyArg = false ) -#set( $keyFieldNames = [\\"lastName\\", \\"nickname\\"] ) -#foreach( $keyFieldName in $keyFieldNames ) -#if( $ctx.args.input.containsKey(\\"$keyFieldName\\") ) #set( $hasSeenSomeKeyArg = true ) #end -#end -#foreach( $keyFieldName in $keyFieldNames ) - #if( $hasSeenSomeKeyArg && !$ctx.args.input.containsKey(\\"$keyFieldName\\") ) - $util.error(\\"When creating any part of the composite sort key for @key 'byNameAndNickname', you must provide all fields for the key. Missing key: '$keyFieldName'.\\") - #end -#end -## [End] Validate create mutation for @key 'byNameAndNickname'. ** -#if( $util.isNull($dynamodbNameOverrideMap) ) - #set( $dynamodbNameOverrideMap = { - \\"lastName#nickname\\": \\"lastNameNickname\\" -} ) -#else - $util.qr($dynamodbNameOverrideMap.put(\\"lastName#nickname\\", \\"lastNameNickname\\")) -#end -#if( $hasSeenSomeKeyArg ) - $util.qr($ctx.args.input.put(\\"lastName#nickname\\",\\"\${ctx.args.input.lastName}#\${ctx.args.input.nickname}\\")) -#end -## [Start] Validate create mutation for @key 'byNameAndAge'. ** -#set( $hasSeenSomeKeyArg = false ) -#set( $keyFieldNames = [\\"age\\", \\"birthDate\\"] ) -#foreach( $keyFieldName in $keyFieldNames ) -#if( $ctx.args.input.containsKey(\\"$keyFieldName\\") ) #set( $hasSeenSomeKeyArg = true ) #end -#end -#foreach( $keyFieldName in $keyFieldNames ) - #if( $hasSeenSomeKeyArg && !$ctx.args.input.containsKey(\\"$keyFieldName\\") ) - $util.error(\\"When creating any part of the composite sort key for @key 'byNameAndAge', you must provide all fields for the key. Missing key: '$keyFieldName'.\\") - #end -#end -## [End] Validate create mutation for @key 'byNameAndAge'. ** -#if( $util.isNull($dynamodbNameOverrideMap) ) - #set( $dynamodbNameOverrideMap = { - \\"age#birthDate\\": \\"ageBirthDate\\" -} ) -#else - $util.qr($dynamodbNameOverrideMap.put(\\"age#birthDate\\", \\"ageBirthDate\\")) -#end -#if( $hasSeenSomeKeyArg ) - $util.qr($ctx.args.input.put(\\"age#birthDate\\",\\"\${ctx.args.input.age}#\${ctx.args.input.birthDate}\\")) -#end -## [Start] Set the primary @key. ** -#set( $modelObjectKey = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.input.id), - \\"firstName#lastName\\": $util.dynamodb.toDynamoDB(\\"\${ctx.args.input.firstName}#\${ctx.args.input.lastName}\\") -} ) -## [End] Set the primary @key. ** -#if( $util.isNull($dynamodbNameOverrideMap) ) - #set( $dynamodbNameOverrideMap = { - \\"firstName#lastName\\": \\"firstNameLastName\\" -} ) -#else - $util.qr($dynamodbNameOverrideMap.put(\\"firstName#lastName\\", \\"firstNameLastName\\")) -#end -$util.qr($ctx.args.input.put(\\"firstName#lastName\\",\\"\${ctx.args.input.firstName}#\${ctx.args.input.lastName}\\")) -## [Start] Prepare DynamoDB PutItem Request. ** -$util.qr($context.args.input.put(\\"__typename\\", \\"Person\\")) -#if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_not_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_not_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end -#else - #set( $condition = { - \\"expression\\": \\"attribute_not_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) -#end -#if( $context.args.condition ) - #set( $condition.expressionValues = {} ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"PutItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": $util.dynamodb.toDynamoDBJson($ctx.args.input.id) -} #end, - \\"attributeValues\\": $util.dynamodb.toMapValuesJson($context.args.input), - \\"condition\\": $util.toJson($condition) -} -## [End] Prepare DynamoDB PutItem Request. **" -`; - -exports[`GSI composite sort keys are wrapped in conditional to check presence in mutation 2`] = ` -"## [Start] Validate update mutation for @key 'byNameAndNickname'. ** -#set( $hasSeenSomeKeyArg = false ) -#set( $keyFieldNames = [\\"lastName\\", \\"nickname\\"] ) -#foreach( $keyFieldName in $keyFieldNames ) -#if( $ctx.args.input.containsKey(\\"$keyFieldName\\") ) #set( $hasSeenSomeKeyArg = true ) #end -#end -#foreach( $keyFieldName in $keyFieldNames ) - #if( $hasSeenSomeKeyArg && !$ctx.args.input.containsKey(\\"$keyFieldName\\") ) - $util.error(\\"When updating any part of the composite sort key for @key 'byNameAndNickname', you must provide all fields for the key. Missing key: '$keyFieldName'.\\") - #end -#end -## [End] Validate update mutation for @key 'byNameAndNickname'. ** -#if( $util.isNull($dynamodbNameOverrideMap) ) - #set( $dynamodbNameOverrideMap = { - \\"lastName#nickname\\": \\"lastNameNickname\\" -} ) -#else - $util.qr($dynamodbNameOverrideMap.put(\\"lastName#nickname\\", \\"lastNameNickname\\")) -#end -#if( $hasSeenSomeKeyArg ) - $util.qr($ctx.args.input.put(\\"lastName#nickname\\",\\"\${ctx.args.input.lastName}#\${ctx.args.input.nickname}\\")) -#end -## [Start] Validate update mutation for @key 'byNameAndAge'. ** -#set( $hasSeenSomeKeyArg = false ) -#set( $keyFieldNames = [\\"age\\", \\"birthDate\\"] ) -#foreach( $keyFieldName in $keyFieldNames ) -#if( $ctx.args.input.containsKey(\\"$keyFieldName\\") ) #set( $hasSeenSomeKeyArg = true ) #end -#end -#foreach( $keyFieldName in $keyFieldNames ) - #if( $hasSeenSomeKeyArg && !$ctx.args.input.containsKey(\\"$keyFieldName\\") ) - $util.error(\\"When updating any part of the composite sort key for @key 'byNameAndAge', you must provide all fields for the key. Missing key: '$keyFieldName'.\\") - #end -#end -## [End] Validate update mutation for @key 'byNameAndAge'. ** -#if( $util.isNull($dynamodbNameOverrideMap) ) - #set( $dynamodbNameOverrideMap = { - \\"age#birthDate\\": \\"ageBirthDate\\" -} ) -#else - $util.qr($dynamodbNameOverrideMap.put(\\"age#birthDate\\", \\"ageBirthDate\\")) -#end -#if( $hasSeenSomeKeyArg ) - $util.qr($ctx.args.input.put(\\"age#birthDate\\",\\"\${ctx.args.input.age}#\${ctx.args.input.birthDate}\\")) -#end -## [Start] Set the primary @key. ** -#set( $modelObjectKey = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.input.id), - \\"firstName#lastName\\": $util.dynamodb.toDynamoDB(\\"\${ctx.args.input.firstName}#\${ctx.args.input.lastName}\\") -} ) -## [End] Set the primary @key. ** -#if( $util.isNull($dynamodbNameOverrideMap) ) - #set( $dynamodbNameOverrideMap = { - \\"firstName#lastName\\": \\"firstNameLastName\\" -} ) -#else - $util.qr($dynamodbNameOverrideMap.put(\\"firstName#lastName\\", \\"firstNameLastName\\")) -#end -$util.qr($ctx.args.input.put(\\"firstName#lastName\\",\\"\${ctx.args.input.firstName}#\${ctx.args.input.lastName}\\")) -#set( $optionalNonNullableFields = [\\"firstName\\", \\"lastName\\"] ) -#foreach( $field in $optionalNonNullableFields ) - #if( $context.arguments.input.keySet().contains($field) && $util.isNull($context.args.input.get($field)) ) -$util.error(\\"An argument you marked as Non-Null is set to Null in the query or the body of your request.\\") - #end -#end -#if( $authCondition && $authCondition.expression != \\"\\" ) - #set( $condition = $authCondition ) - #if( $modelObjectKey ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#id)\\")) - $util.qr($condition.expressionNames.put(\\"#id\\", \\"id\\")) - #end -#else - #if( $modelObjectKey ) - #set( $condition = { - \\"expression\\": \\"\\", - \\"expressionNames\\": {}, - \\"expressionValues\\": {} -} ) - #foreach( $entry in $modelObjectKey.entrySet() ) - #if( $velocityCount == 1 ) - $util.qr($condition.put(\\"expression\\", \\"attribute_exists(#keyCondition$velocityCount)\\")) - #else - $util.qr($condition.put(\\"expression\\", \\"$condition.expression AND attribute_exists(#keyCondition$velocityCount)\\")) - #end - $util.qr($condition.expressionNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) - #end - #else - #set( $condition = { - \\"expression\\": \\"attribute_exists(#id)\\", - \\"expressionNames\\": { - \\"#id\\": \\"id\\" - }, - \\"expressionValues\\": {} -} ) - #end -#end -## Automatically set the updatedAt timestamp. ** -$util.qr($context.args.input.put(\\"updatedAt\\", $util.defaultIfNull($ctx.args.input.updatedAt, $util.time.nowISO8601()))) -$util.qr($context.args.input.put(\\"__typename\\", \\"Person\\")) -## Update condition if type is @versioned ** -#if( $versionedCondition ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $versionedCondition.expression\\")) - $util.qr($condition.expressionNames.putAll($versionedCondition.expressionNames)) - $util.qr($condition.expressionValues.putAll($versionedCondition.expressionValues)) -#end -#if( $context.args.condition ) - #set( $conditionFilterExpressions = $util.parseJson($util.transform.toDynamoDBConditionExpression($context.args.condition)) ) - $util.qr($condition.put(\\"expression\\", \\"($condition.expression) AND $conditionFilterExpressions.expression\\")) - $util.qr($condition.expressionNames.putAll($conditionFilterExpressions.expressionNames)) - $util.qr($condition.expressionValues.putAll($conditionFilterExpressions.expressionValues)) -#end -#if( $condition.expressionValues && $condition.expressionValues.size() == 0 ) - #set( $condition = { - \\"expression\\": $condition.expression, - \\"expressionNames\\": $condition.expressionNames -} ) -#end -#set( $expNames = {} ) -#set( $expValues = {} ) -#set( $expSet = {} ) -#set( $expAdd = {} ) -#set( $expRemove = [] ) -#if( $modelObjectKey ) - #set( $keyFields = [] ) - #foreach( $entry in $modelObjectKey.entrySet() ) - $util.qr($keyFields.add(\\"$entry.key\\")) - #end -#else - #set( $keyFields = [\\"id\\"] ) -#end -#foreach( $entry in $util.map.copyAndRemoveAllKeys($context.args.input, $keyFields).entrySet() ) - #if( !$util.isNull($dynamodbNameOverrideMap) && $dynamodbNameOverrideMap.containsKey(\\"$entry.key\\") ) - #set( $entryKeyAttributeName = $dynamodbNameOverrideMap.get(\\"$entry.key\\") ) - #else - #set( $entryKeyAttributeName = $entry.key ) - #end - #if( $util.isNull($entry.value) ) - #set( $discard = $expRemove.add(\\"#$entryKeyAttributeName\\") ) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - #else - $util.qr($expSet.put(\\"#$entryKeyAttributeName\\", \\":$entryKeyAttributeName\\")) - $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) - $util.qr($expValues.put(\\":$entryKeyAttributeName\\", $util.dynamodb.toDynamoDB($entry.value))) - #end -#end -#set( $expression = \\"\\" ) -#if( !$expSet.isEmpty() ) - #set( $expression = \\"SET\\" ) - #foreach( $entry in $expSet.entrySet() ) - #set( $expression = \\"$expression $entry.key = $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expAdd.isEmpty() ) - #set( $expression = \\"$expression ADD\\" ) - #foreach( $entry in $expAdd.entrySet() ) - #set( $expression = \\"$expression $entry.key $entry.value\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#if( !$expRemove.isEmpty() ) - #set( $expression = \\"$expression REMOVE\\" ) - #foreach( $entry in $expRemove ) - #set( $expression = \\"$expression $entry\\" ) - #if( $foreach.hasNext() ) - #set( $expression = \\"$expression,\\" ) - #end - #end -#end -#set( $update = {} ) -$util.qr($update.put(\\"expression\\", \\"$expression\\")) -#if( !$expNames.isEmpty() ) - $util.qr($update.put(\\"expressionNames\\", $expNames)) -#end -#if( !$expValues.isEmpty() ) - $util.qr($update.put(\\"expressionValues\\", $expValues)) -#end -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"UpdateItem\\", - \\"key\\": #if( $modelObjectKey ) $util.toJson($modelObjectKey) #else { - \\"id\\": { - \\"S\\": $util.toJson($context.args.input.id) - } -} #end, - \\"update\\": $util.toJson($update), - \\"condition\\": $util.toJson($condition) -}" -`; diff --git a/packages/graphql-key-transformer/src/index.ts b/packages/graphql-key-transformer/src/index.ts deleted file mode 100644 index c758a031dc..0000000000 --- a/packages/graphql-key-transformer/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './KeyTransformer'; -// No-op change to trigger publish diff --git a/packages/graphql-key-transformer/tsconfig.json b/packages/graphql-key-transformer/tsconfig.json deleted file mode 100644 index 1814a1ef9f..0000000000 --- a/packages/graphql-key-transformer/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "strict": false, // TODO enable - "rootDir": "src", - "outDir": "lib" - }, - "references": [ - { "path": "../amplify-graphql-directives" }, - { "path": "../graphql-dynamodb-transformer" }, - { "path": "../graphql-mapping-template" }, - { "path": "../graphql-transformer-common" }, - { "path": "../graphql-transformer-core" } - ] -} diff --git a/packages/graphql-predictions-transformer/.npmignore b/packages/graphql-predictions-transformer/.npmignore deleted file mode 100644 index 60c2a8234b..0000000000 --- a/packages/graphql-predictions-transformer/.npmignore +++ /dev/null @@ -1,6 +0,0 @@ -**/__mocks__/** -**/__tests__/** -lambdaFunction -src -tsconfig.json -tsconfig.tsbuildinfo diff --git a/packages/graphql-predictions-transformer/API.md b/packages/graphql-predictions-transformer/API.md deleted file mode 100644 index c92d1581cc..0000000000 --- a/packages/graphql-predictions-transformer/API.md +++ /dev/null @@ -1,41 +0,0 @@ -## API Report File for "graphql-predictions-transformer" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import DataSource from 'cloudform-types/types/appSync/dataSource'; -import { default as default_2 } from 'cloudform-types/types/iam/role'; -import { default as default_3 } from 'cloudform-types/types/appSync/resolver'; -import { default as default_4 } from 'cloudform-types/types/appSync/functionConfiguration'; -import { default as default_5 } from 'cloudform-types/types/lambda/function'; -import { DirectiveNode } from 'graphql'; -import { FieldDefinitionNode } from 'graphql'; -import { HttpConfig } from 'cloudform-types/types/appSync/dataSource'; -import { LambdaConfig } from 'cloudform-types/types/appSync/dataSource'; -import { ObjectTypeDefinitionNode } from 'graphql'; -import { Policy } from 'cloudform-types/types/iam/group'; -import { Transformer as Transformer_2 } from 'graphql-transformer-core'; -import { TransformerContext } from 'graphql-transformer-core'; - -// @public (undocumented) -export type PredictionsConfig = { - bucketName: string; -}; - -// @public (undocumented) -export class PredictionsTransformer extends Transformer_2 { - constructor(predictionsConfig?: PredictionsConfig); - // (undocumented) - field: (parent: ObjectTypeDefinitionNode, definition: FieldDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => void; - // (undocumented) - predictionsConfig: PredictionsConfig; - // Warning: (ae-forgotten-export) The symbol "ResourceFactory" needs to be exported by the entry point index.d.ts - // - // (undocumented) - resources: ResourceFactory; -} - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/graphql-predictions-transformer/CHANGELOG.md b/packages/graphql-predictions-transformer/CHANGELOG.md deleted file mode 100644 index 29ecac5bb7..0000000000 --- a/packages/graphql-predictions-transformer/CHANGELOG.md +++ /dev/null @@ -1,651 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [3.2.80](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.79...graphql-predictions-transformer@3.2.80) (2024-07-15) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.79](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.78...graphql-predictions-transformer@3.2.79) (2024-07-02) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.78](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.77...graphql-predictions-transformer@3.2.78) (2024-06-25) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.77](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.76...graphql-predictions-transformer@3.2.77) (2024-04-26) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.76](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.75...graphql-predictions-transformer@3.2.76) (2024-04-11) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.75](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.74...graphql-predictions-transformer@3.2.75) (2024-03-28) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.74](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.73...graphql-predictions-transformer@3.2.74) (2024-02-28) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.73](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.72...graphql-predictions-transformer@3.2.73) (2024-02-05) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.72](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.71...graphql-predictions-transformer@3.2.72) (2024-01-22) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.71](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.70...graphql-predictions-transformer@3.2.71) (2023-12-18) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.70](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.69...graphql-predictions-transformer@3.2.70) (2023-12-06) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.69](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.68...graphql-predictions-transformer@3.2.69) (2023-11-18) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.68](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.67...graphql-predictions-transformer@3.2.68) (2023-11-16) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.67](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.66...graphql-predictions-transformer@3.2.67) (2023-11-15) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.66](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.65...graphql-predictions-transformer@3.2.66) (2023-10-21) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.65](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.64...graphql-predictions-transformer@3.2.65) (2023-08-30) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.64](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.63...graphql-predictions-transformer@3.2.64) (2023-08-28) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.63](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.62...graphql-predictions-transformer@3.2.63) (2023-08-09) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.62](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.61...graphql-predictions-transformer@3.2.62) (2023-07-21) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.61](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.60...graphql-predictions-transformer@3.2.61) (2023-07-17) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.60](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.59...graphql-predictions-transformer@3.2.60) (2023-07-07) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.59](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.58...graphql-predictions-transformer@3.2.59) (2023-07-07) - -### Bug Fixes - -- trigger republish of dependencies that failed in https://app.circleci.com/pipelines/github/aws-amplify/amplify-category-api/7981/workflows/e7366f04-6f0a-4ee4-9cc2-1772089e8005/jobs/163571 ([f2c7151](https://github.com/aws-amplify/amplify-category-api/commit/f2c7151005e4a9fd29d91ac1af1f3e482a06a5cc)) - -## [3.2.58](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.57...graphql-predictions-transformer@3.2.58) (2023-07-07) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.57](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.56...graphql-predictions-transformer@3.2.57) (2023-06-29) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.56](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.55...graphql-predictions-transformer@3.2.56) (2023-06-20) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.55](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.54...graphql-predictions-transformer@3.2.55) (2023-06-05) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.54](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.53...graphql-predictions-transformer@3.2.54) (2023-05-23) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.53](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.52...graphql-predictions-transformer@3.2.53) (2023-05-17) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.52](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.51...graphql-predictions-transformer@3.2.52) (2023-04-25) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.51](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.50...graphql-predictions-transformer@3.2.51) (2023-03-30) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.50](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.49...graphql-predictions-transformer@3.2.50) (2023-03-15) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.49](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.48...graphql-predictions-transformer@3.2.49) (2023-03-01) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.48](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.47...graphql-predictions-transformer@3.2.48) (2023-02-27) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.47](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.46...graphql-predictions-transformer@3.2.47) (2023-01-26) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.46](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.45...graphql-predictions-transformer@3.2.46) (2023-01-12) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.45](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.44...graphql-predictions-transformer@3.2.45) (2023-01-12) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.44](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.43...graphql-predictions-transformer@3.2.44) (2022-12-03) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.43](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.42...graphql-predictions-transformer@3.2.43) (2022-09-14) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.42](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.40...graphql-predictions-transformer@3.2.42) (2022-07-20) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.41](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.40...graphql-predictions-transformer@3.2.41) (2022-07-14) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.40](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.39...graphql-predictions-transformer@3.2.40) (2022-07-01) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.39](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.38...graphql-predictions-transformer@3.2.39) (2022-06-23) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.38](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.37...graphql-predictions-transformer@3.2.38) (2022-06-13) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.37](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.36...graphql-predictions-transformer@3.2.37) (2022-06-10) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.36](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.35...graphql-predictions-transformer@3.2.36) (2022-06-10) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.35](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.32...graphql-predictions-transformer@3.2.35) (2022-06-07) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.34](https://github.com/aws-amplify/amplify-category-api/compare/graphql-predictions-transformer@3.2.32...graphql-predictions-transformer@3.2.34) (2022-05-31) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.33](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.32...graphql-predictions-transformer@3.2.33) (2022-05-02) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.32](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.31...graphql-predictions-transformer@3.2.32) (2022-04-29) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.31](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.30...graphql-predictions-transformer@3.2.31) (2022-04-27) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.30](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.29...graphql-predictions-transformer@3.2.30) (2022-04-11) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.29](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.28...graphql-predictions-transformer@3.2.29) (2022-04-07) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.28](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.27...graphql-predictions-transformer@3.2.28) (2022-03-23) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.27](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.26...graphql-predictions-transformer@3.2.27) (2022-03-17) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.26](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.25...graphql-predictions-transformer@3.2.26) (2022-03-14) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.24...graphql-predictions-transformer@3.2.25) (2022-03-07) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.23...graphql-predictions-transformer@3.2.24) (2022-02-25) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.22...graphql-predictions-transformer@3.2.23) (2022-02-15) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.18...graphql-predictions-transformer@3.2.22) (2022-02-10) - -## 7.6.19 (2022-02-08) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.17...graphql-predictions-transformer@3.2.18) (2022-02-03) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.16...graphql-predictions-transformer@3.2.17) (2022-01-31) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.15...graphql-predictions-transformer@3.2.16) (2022-01-27) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.14...graphql-predictions-transformer@3.2.15) (2022-01-23) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.13...graphql-predictions-transformer@3.2.14) (2022-01-13) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.11...graphql-predictions-transformer@3.2.13) (2022-01-10) - -## 7.6.7 (2022-01-10) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.10...graphql-predictions-transformer@3.2.11) (2021-12-21) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.9...graphql-predictions-transformer@3.2.10) (2021-12-17) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.8...graphql-predictions-transformer@3.2.9) (2021-12-03) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.7...graphql-predictions-transformer@3.2.8) (2021-12-02) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.6...graphql-predictions-transformer@3.2.7) (2021-12-01) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.5...graphql-predictions-transformer@3.2.6) (2021-11-26) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.4...graphql-predictions-transformer@3.2.5) (2021-11-23) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.3...graphql-predictions-transformer@3.2.4) (2021-11-21) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.2...graphql-predictions-transformer@3.2.3) (2021-11-20) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@3.2.1...graphql-predictions-transformer@3.2.2) (2021-11-17) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [3.2.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.25...graphql-predictions-transformer@3.2.1) (2021-11-15) - -**Note:** Version bump only for package graphql-predictions-transformer - -# [3.0.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.25...graphql-predictions-transformer@3.0.0) (2021-11-13) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.24...graphql-predictions-transformer@2.5.25) (2021-11-11) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.23...graphql-predictions-transformer@2.5.24) (2021-10-10) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.22...graphql-predictions-transformer@2.5.23) (2021-10-06) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.21...graphql-predictions-transformer@2.5.22) (2021-09-27) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.21](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.20...graphql-predictions-transformer@2.5.21) (2021-09-18) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.20](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.19...graphql-predictions-transformer@2.5.20) (2021-09-14) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.19](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.18...graphql-predictions-transformer@2.5.19) (2021-09-09) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.17...graphql-predictions-transformer@2.5.18) (2021-09-02) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.16...graphql-predictions-transformer@2.5.17) (2021-08-24) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.15...graphql-predictions-transformer@2.5.16) (2021-08-06) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.14...graphql-predictions-transformer@2.5.15) (2021-07-30) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.13...graphql-predictions-transformer@2.5.14) (2021-07-27) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.12...graphql-predictions-transformer@2.5.13) (2021-07-16) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.11...graphql-predictions-transformer@2.5.12) (2021-06-30) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.10...graphql-predictions-transformer@2.5.11) (2021-06-24) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.9...graphql-predictions-transformer@2.5.10) (2021-06-15) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.8...graphql-predictions-transformer@2.5.9) (2021-05-26) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.7...graphql-predictions-transformer@2.5.8) (2021-05-18) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.6...graphql-predictions-transformer@2.5.7) (2021-05-14) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.4...graphql-predictions-transformer@2.5.6) (2021-05-03) - -## 4.50.1 (2021-05-03) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.4...graphql-predictions-transformer@2.5.5) (2021-05-03) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.3...graphql-predictions-transformer@2.5.4) (2021-04-27) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.2...graphql-predictions-transformer@2.5.3) (2021-04-19) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.5.1...graphql-predictions-transformer@2.5.2) (2021-04-14) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.5.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.4.12...graphql-predictions-transformer@2.5.1) (2021-04-09) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.4.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.4.11...graphql-predictions-transformer@2.4.12) (2021-03-23) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.4.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.4.10...graphql-predictions-transformer@2.4.11) (2021-03-11) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.4.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.4.9...graphql-predictions-transformer@2.4.10) (2021-03-05) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.4.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.4.8...graphql-predictions-transformer@2.4.9) (2021-02-26) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.4.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.4.7...graphql-predictions-transformer@2.4.8) (2021-02-24) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.4.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.4.6...graphql-predictions-transformer@2.4.7) (2021-02-17) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.4.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.4.5...graphql-predictions-transformer@2.4.6) (2021-02-11) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.4.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.4.4...graphql-predictions-transformer@2.4.5) (2021-02-10) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.4.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.4.3...graphql-predictions-transformer@2.4.4) (2020-12-16) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.4.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.4.2...graphql-predictions-transformer@2.4.3) (2020-12-07) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.4.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.4.1...graphql-predictions-transformer@2.4.2) (2020-11-30) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.4.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.24...graphql-predictions-transformer@2.4.1) (2020-11-22) - -**Note:** Version bump only for package graphql-predictions-transformer - -# 2.4.0 (2020-11-22) - -### Bug Fixes - -- **graphql-predictions-transformer:** fix json validation ([#5724](https://github.com/aws-amplify/amplify-cli/issues/5724)) ([3bed4b1](https://github.com/aws-amplify/amplify-cli/commit/3bed4b10b9ac6d3088a86c28f5e211ac431644b1)) -- sanitize input in transformer resolver([#3316](https://github.com/aws-amplify/amplify-cli/issues/3316)) ([a3bc0a5](https://github.com/aws-amplify/amplify-cli/commit/a3bc0a5e5d3faa7946d16d0f6595ce8c2f3c11dc)) - -## [2.3.27](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.24...graphql-predictions-transformer@2.3.27) (2020-11-20) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.26](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.24...graphql-predictions-transformer@2.3.26) (2020-11-20) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.24...graphql-predictions-transformer@2.3.25) (2020-11-19) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.23...graphql-predictions-transformer@2.3.24) (2020-11-08) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.22...graphql-predictions-transformer@2.3.23) (2020-10-30) - -### Bug Fixes - -- **graphql-predictions-transformer:** fix json validation ([#5724](https://github.com/aws-amplify/amplify-cli/issues/5724)) ([3bed4b1](https://github.com/aws-amplify/amplify-cli/commit/3bed4b10b9ac6d3088a86c28f5e211ac431644b1)) - -## [2.3.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.21...graphql-predictions-transformer@2.3.22) (2020-10-22) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.21](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.20...graphql-predictions-transformer@2.3.21) (2020-10-17) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.20](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.19...graphql-predictions-transformer@2.3.20) (2020-10-01) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.19](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.18...graphql-predictions-transformer@2.3.19) (2020-09-16) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.17...graphql-predictions-transformer@2.3.18) (2020-08-31) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.16...graphql-predictions-transformer@2.3.17) (2020-08-14) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.15...graphql-predictions-transformer@2.3.16) (2020-08-11) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.13...graphql-predictions-transformer@2.3.15) (2020-07-29) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.13...graphql-predictions-transformer@2.3.14) (2020-07-23) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.12...graphql-predictions-transformer@2.3.13) (2020-07-18) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.11...graphql-predictions-transformer@2.3.12) (2020-07-15) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.10...graphql-predictions-transformer@2.3.11) (2020-06-25) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.9...graphql-predictions-transformer@2.3.10) (2020-06-18) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.8...graphql-predictions-transformer@2.3.9) (2020-06-11) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.7...graphql-predictions-transformer@2.3.8) (2020-06-10) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.6...graphql-predictions-transformer@2.3.7) (2020-06-02) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.5...graphql-predictions-transformer@2.3.6) (2020-05-26) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.4...graphql-predictions-transformer@2.3.5) (2020-05-15) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.3...graphql-predictions-transformer@2.3.4) (2020-05-08) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.2...graphql-predictions-transformer@2.3.3) (2020-04-23) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.3.1...graphql-predictions-transformer@2.3.2) (2020-03-22) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.3.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.1.11...graphql-predictions-transformer@2.3.1) (2020-03-07) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.2.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.1.13-beta.0...graphql-predictions-transformer@2.2.1) (2020-03-05) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.1.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.1.10...graphql-predictions-transformer@2.1.11) (2020-02-13) - -**Note:** Version bump only for package graphql-predictions-transformer - -## [2.1.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.1.9...graphql-predictions-transformer@2.1.10) (2020-02-07) - -### Bug Fixes - -- sanitize input in transformer resolver([#3316](https://github.com/aws-amplify/amplify-cli/issues/3316)) ([a3bc0a5](https://github.com/aws-amplify/amplify-cli/commit/a3bc0a5e5d3faa7946d16d0f6595ce8c2f3c11dc)) - -## [2.1.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-predictions-transformer@2.1.8...graphql-predictions-transformer@2.1.9) (2020-01-24) - -**Note:** Version bump only for package graphql-predictions-transformer - -## 2.1.8 (2020-01-23) - -**Note:** Version bump only for package graphql-predictions-transformer - -## 2.1.7 (2020-01-09) - -**Note:** Version bump only for package graphql-predictions-transformer - -## 2.1.6 (2019-12-31) - -**Note:** Version bump only for package graphql-predictions-transformer - -## 2.1.5 (2019-12-28) - -**Note:** Version bump only for package graphql-predictions-transformer - -## 2.1.4 (2019-12-26) - -**Note:** Version bump only for package graphql-predictions-transformer - -## 2.1.3 (2019-12-25) - -**Note:** Version bump only for package graphql-predictions-transformer - -## 2.1.2 (2019-12-20) - -**Note:** Version bump only for package graphql-predictions-transformer - -## 2.1.1 (2019-12-10) - -**Note:** Version bump only for package graphql-predictions-transformer - -## 2.0.5 (2019-12-03) - -**Note:** Version bump only for package graphql-predictions-transformer - -## 2.0.4 (2019-12-01) - -**Note:** Version bump only for package graphql-predictions-transformer - -## 2.0.3 (2019-11-27) - -**Note:** Version bump only for package graphql-predictions-transformer - -## 2.0.1 (2019-11-27) - -**Note:** Version bump only for package graphql-predictions-transformer diff --git a/packages/graphql-predictions-transformer/lambdaFunction/predictionsLambda.js b/packages/graphql-predictions-transformer/lambdaFunction/predictionsLambda.js deleted file mode 100644 index 985bb89e92..0000000000 --- a/packages/graphql-predictions-transformer/lambdaFunction/predictionsLambda.js +++ /dev/null @@ -1,35 +0,0 @@ -const { Polly } = require('@aws-sdk/client-polly'); -const { getSynthesizeSpeechUrl } = require('@aws-sdk/polly-request-presigner'); - -exports.handler = function (event, context, callback) { - if (event && event.action === 'convertTextToSpeech') { - convertTextToSpeech(event, callback); - } else { - callback(Error('Action not configured.')); - } -}; - -/** - * This function does the following for the textToSpeech action - * - Synthesize Speech - * - Get a presigned url for that synthesized speech - * @param {*} event - * @param {*} callback - */ -async function convertTextToSpeech(event, callback) { - try { - const params = { - OutputFormat: 'mp3', - SampleRate: '8000', - Text: event.text, - TextType: 'text', - VoiceId: event.voiceID, - }; - const client = new Polly(); - const url = await getSynthesizeSpeechUrl({ client, params }); - callback(null, { url: url }); - } catch (err) { - console.log(err, err.stack); - callback(Error(err)); - } -} diff --git a/packages/graphql-predictions-transformer/package.json b/packages/graphql-predictions-transformer/package.json deleted file mode 100644 index 9b6fc764f8..0000000000 --- a/packages/graphql-predictions-transformer/package.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "name": "graphql-predictions-transformer", - "version": "3.2.80", - "description": "Implements the @predictions directive.", - "repository": { - "type": "git", - "url": "https://github.com/aws-amplify/amplify-category-api.git", - "directory": "packages/graphql-predictions-transformer" - }, - "author": "Amazon Web Services", - "license": "Apache-2.0", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "keywords": [ - "graphql", - "appsync", - "aws" - ], - "scripts": { - "build": "tsc && cd lambdaFunction && bestzip --force node ../lib/predictionsLambdaFunction.zip predictionsLambda.js", - "watch": "tsc -w", - "test": "jest", - "clean": "rimraf ./lib", - "extract-api": "ts-node ../../scripts/extract-api.ts" - }, - "dependencies": { - "cloudform-types": "^4.2.0", - "graphql": "^15.5.0", - "graphql-mapping-template": "4.20.16", - "graphql-transformer-common": "4.31.1", - "graphql-transformer-core": "8.2.13" - }, - "devDependencies": { - "bestzip": "^2.1.5" - }, - "jest": { - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, - "testURL": "http://localhost", - "testRegex": "(src/__tests__/.*.test.ts)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], - "collectCoverage": true, - "coverageProvider": "v8", - "coverageThreshold": { - "global": { - "branches": 85, - "functions": 90, - "lines": 90 - } - }, - "coverageReporters": [ - "clover", - "text" - ], - "collectCoverageFrom": [ - "src/**/*.ts" - ], - "coveragePathIgnorePatterns": [ - "/__tests__/" - ] - } -} diff --git a/packages/graphql-predictions-transformer/src/PredictionsTransformer.ts b/packages/graphql-predictions-transformer/src/PredictionsTransformer.ts deleted file mode 100644 index 89c7e74bef..0000000000 --- a/packages/graphql-predictions-transformer/src/PredictionsTransformer.ts +++ /dev/null @@ -1,175 +0,0 @@ -import path = require('path'); -import { - ObjectTypeDefinitionNode, - FieldDefinitionNode, - DirectiveNode, - valueFromASTUntyped, - ArgumentNode, - InputValueDefinitionNode, - parse, -} from 'graphql'; -import { Transformer, TransformerContext, InvalidDirectiveError } from 'graphql-transformer-core'; -import { PredictionsDirectiveV1 } from '@aws-amplify/graphql-directives'; -import { ResolverResourceIDs, PredictionsResourceIDs } from 'graphql-transformer-common'; -import { Fn } from 'cloudform-types'; -import { getActionInputType, makeActionInputObject, getActionInputName, addInputArgument, createInputValueAction } from './definitions'; -import { ResourceFactory, ActionPolicyMap } from './resources'; -import { allowedActions } from './predictions_utils'; - -const PREDICTIONS_DIRECTIVE_STACK = 'PredictionsDirectiveStack'; - -export type PredictionsConfig = { - bucketName: string; -}; - -export class PredictionsTransformer extends Transformer { - resources: ResourceFactory; - - predictionsConfig: PredictionsConfig; - - constructor(predictionsConfig?: PredictionsConfig) { - super('PredictionsTransformer', parse(PredictionsDirectiveV1.definition)); - this.resources = new ResourceFactory(); - this.predictionsConfig = predictionsConfig; - } - - public field = (parent: ObjectTypeDefinitionNode, definition: FieldDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => { - // validate @predictions is defined on a field under a query object. - if (parent.name.value !== ctx.getQueryTypeName()) { - throw new InvalidDirectiveError('@predictions directive only works under Query operations.'); - } - // get input arguments - const actions = this.getActions(directive); - // validate that that order the transformers are correct - this.validateActions(actions); - // validate storage is in the config - if (!this.predictionsConfig || !this.predictionsConfig.bucketName) { - throw new InvalidDirectiveError('Please configure storage in your project in order to use @predictions directive'); - } - - // make changes to the schema to create the input/output types - // generate action datasources and add functions - this.createResources(ctx, definition, actions, this.predictionsConfig.bucketName); - }; - - private validateActions(actions: string[]) { - // validate actions - const supportedPredictions = allowedActions; - const allowed = []; - actions.forEach((action) => { - if (supportedPredictions[action] && (allowed.includes(action) || allowed.length === 0)) { - allowed.concat(supportedPredictions[action].next); - } else { - throw new InvalidDirectiveError(`${action} is not supported!`); - } - }); - } - - private createResources(ctx: TransformerContext, def: FieldDefinitionNode, actions: string[], storage: string) { - const fieldName = def.name.value; - const predictionFunctions: any[] = []; - const actionInputObjectFields: InputValueDefinitionNode[] = []; - let isList: boolean = false; - let actionPolicyMap: ActionPolicyMap = {}; - if (ctx.metadata.has(PredictionsResourceIDs.actionMapID)) { - actionPolicyMap = ctx.metadata.get(PredictionsResourceIDs.actionMapID); - } - actions.forEach((action, index) => { - // boolean to check if the action specified is the first action - const isFirst = index === 0; - // check if action should return a list - isList = this.needsList(action, isList); - // create input object fields which will end up in the input object - actionInputObjectFields.push(createInputValueAction(action, fieldName)); - // create policy for action if it doesn't exist - actionPolicyMap = this.resources.mergeActionRole(actionPolicyMap, action); - // grab datasource config for the action - const actionDSConfig = this.resources.getPredictionsDSConfig(action); - // add the action function into the pipeline resolver for the operation resolver - predictionFunctions.push(Fn.GetAtt(PredictionsResourceIDs.getPredictionFunctionName(action), 'FunctionId')); - // if the datasource does not exist add the resource - if (!ctx.getResource(actionDSConfig.id)) { - ctx.setResource(actionDSConfig.id, this.resources.createPredictionsDataSource(actionDSConfig)); - ctx.mapResourceToStack(PREDICTIONS_DIRECTIVE_STACK, actionDSConfig.id); - if (actionDSConfig.id === 'LambdaDataSource') { - // merge lambda permissions - actionPolicyMap = this.resources.mergeLambdaActionRole(actionPolicyMap); - // add lambda function in transformer context metadata - ctx.metadata.set(PredictionsResourceIDs.lambdaID, path.resolve(`${__dirname}/../lib/predictionsLambdaFunction.zip`)); - // TODO: If other actions should use a lambda function then the iam role should add as needed policies per action - ctx.setResource(PredictionsResourceIDs.lambdaIAMRole, this.resources.createLambdaIAMRole(storage)); - ctx.mapResourceToStack(PREDICTIONS_DIRECTIVE_STACK, PredictionsResourceIDs.lambdaIAMRole); - // create lambda function - ctx.setResource(PredictionsResourceIDs.lambdaID, this.resources.createPredictionsLambda()); - ctx.mapResourceToStack(PREDICTIONS_DIRECTIVE_STACK, PredictionsResourceIDs.lambdaID); - } - } - // add function configuration resource if it does not exist - if (!ctx.getResource(PredictionsResourceIDs.getPredictionFunctionName(action))) { - ctx.setResource( - PredictionsResourceIDs.getPredictionFunctionName(action), - this.resources.createActionFunction(action, actionDSConfig.id), - ); - ctx.mapResourceToStack(PREDICTIONS_DIRECTIVE_STACK, PredictionsResourceIDs.getPredictionFunctionName(action)); - } - // check if the input type exists in the schema - if (!this.typeExist(getActionInputName(action, fieldName), ctx)) { - const actionInput = getActionInputType(action, fieldName, isFirst); - ctx.addInput(actionInput); - } - }); - - // create iam policy - const iamRole = this.resources.createIAMRole(actionPolicyMap, storage); - ctx.setResource(PredictionsResourceIDs.iamRole, iamRole); - ctx.mapResourceToStack(PREDICTIONS_DIRECTIVE_STACK, PredictionsResourceIDs.iamRole); - // save map config in the context - ctx.metadata.set(PredictionsResourceIDs.actionMapID, actionPolicyMap); - - // generate input type based on operation name - ctx.addInput(makeActionInputObject(fieldName, actionInputObjectFields)); - // add arguments into operation - const type = ctx.getType(ctx.getQueryTypeName()) as ObjectTypeDefinitionNode; - if (type) { - const field = type.fields.find((f) => f.name.value === fieldName); - if (field) { - const newFields = [...type.fields.filter((f) => f.name.value !== field.name.value), addInputArgument(field, fieldName, isList)]; - const newMutation = { - ...type, - fields: newFields, - }; - ctx.putType(newMutation); - } - } - - // create the resolver for the operation - const resolver = this.resources.createResolver(ctx.getQueryTypeName(), def.name.value, predictionFunctions, storage); - const resolverId = ResolverResourceIDs.ResolverResourceID(ctx.getQueryTypeName(), def.name.value); - ctx.setResource(resolverId, resolver); - ctx.mapResourceToStack(PREDICTIONS_DIRECTIVE_STACK, resolverId); - } - - private getActions(directive: DirectiveNode): string[] { - const get = (s: string) => (arg: ArgumentNode) => arg.name.value === s; - const getArg = (arg: string, dflt?: any) => { - const argument = directive.arguments.find(get(arg)); - return argument ? valueFromASTUntyped(argument.value) : dflt; - }; - return getArg('actions', []) as string[]; - } - - private needsList(action: string, flag: boolean): boolean { - switch (action) { - case 'identifyLabels': - return true; - case 'convertTextToSpeech': - return false; - default: - return flag; - } - } - - private typeExist(type: string, ctx: TransformerContext): boolean { - return Boolean(type in ctx.nodeMap); - } -} diff --git a/packages/graphql-predictions-transformer/src/__tests__/PredictionsTransformer.test.ts b/packages/graphql-predictions-transformer/src/__tests__/PredictionsTransformer.test.ts deleted file mode 100644 index c53e4bedc8..0000000000 --- a/packages/graphql-predictions-transformer/src/__tests__/PredictionsTransformer.test.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { GraphQLTransform } from 'graphql-transformer-core'; -import { PredictionsTransformer } from '../PredictionsTransformer'; - -// tslint:disable: no-magic-numbers -test('lambda function is added to pipeline when lambda dependent action is added', () => { - const validSchema = ` - type Query { - speakTranslatedText: String @predictions(actions: [ translateText convertTextToSpeech ]) - } - `; - const transformer = new GraphQLTransform({ - transformers: [new PredictionsTransformer({ bucketName: 'myStorage${hash}-${env}' })], - }); - - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - /** - * AppSync DataSources x2 - * - Translate - * - Lambda - * AppSync Functions x2 - * - translateTextFunction - * - convertTextToSpeechFunction - * AppSync Query Resolver x1 - * - QueryspeakTranslatedTextResolver - * IAM Roles x2 - * - predictions IAM Role - * - lambda IAM Role - * Lambda Function x1 - * - predictionsLambda - * - * Total : 8 - */ - expect(Object.keys(out.stacks.PredictionsDirectiveStack.Resources).length).toEqual(8); - - // Schema Validation - expect(out.schema).toMatchSnapshot(); - - // Expect Schema for Query operation to return a string - expect(out.schema).toContain('speakTranslatedText(input: SpeakTranslatedTextInput!): String'); - - // IAM role - const iamRoleResource = out.stacks.PredictionsDirectiveStack.Resources.predictionsIAMRole; - expect(iamRoleResource).toBeDefined(); - expect(iamRoleResource.Properties.AssumeRolePolicyDocument.Statement[0].Principal.Service).toEqual('appsync.amazonaws.com'); - expect(iamRoleResource.Properties.AssumeRolePolicyDocument.Statement[0].Action).toEqual('sts:AssumeRole'); - iamRoleResource.Properties.Policies.forEach((policy: any) => { - expect(['translate:TranslateText', 'lambda:InvokeFunction', 's3:GetObject']).toContain(policy.PolicyDocument.Statement[0].Action[0]); - }); - - // Resolver - const resolverResource = out.stacks.PredictionsDirectiveStack.Resources.QueryspeakTranslatedTextResolver; - expect(resolverResource).toBeDefined(); - expect(resolverResource.Properties.FieldName).toEqual('speakTranslatedText'); - expect(resolverResource.Properties.TypeName).toEqual('Query'); - expect(resolverResource.Properties.Kind).toEqual('PIPELINE'); - expect(resolverResource.Properties.PipelineConfig.Functions.length).toEqual(2); -}); - -test('return type is a list based on the action', () => { - const validSchema = ` - type Query { - translateLabels: String @predictions(actions: [ identifyLabels translateText ]) - } - `; - const transformer = new GraphQLTransform({ - transformers: [new PredictionsTransformer({ bucketName: 'myStorage${hash}-${env}' })], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - // match schema snapshot - expect(out.schema).toMatchSnapshot(); - expect(Object.keys(out.stacks.PredictionsDirectiveStack.Resources).length).toEqual(6); - - // Expect Schema for Query operation to return a string - expect(out.schema).toContain('translateLabels(input: TranslateLabelsInput!): [String]'); - - // IAM role - const iamRoleResource = out.stacks.PredictionsDirectiveStack.Resources.predictionsIAMRole; - expect(iamRoleResource).toBeDefined(); - expect(iamRoleResource.Properties.AssumeRolePolicyDocument.Statement[0].Principal.Service).toEqual('appsync.amazonaws.com'); - expect(iamRoleResource.Properties.AssumeRolePolicyDocument.Statement[0].Action).toEqual('sts:AssumeRole'); - iamRoleResource.Properties.Policies.forEach((policy: any) => { - expect(['translate:TranslateText', 'rekognition:DetectLabels', 's3:GetObject']).toContain(policy.PolicyDocument.Statement[0].Action[0]); - }); -}); - -test('snapshot test to check generated function resolvers', () => { - const validSchema = ` - type Query { - speakTranslatedImageText: String @predictions(actions: [ - identifyText - translateText - convertTextToSpeech - ]) - } - `; - const transformer = new GraphQLTransform({ - transformers: [new PredictionsTransformer({ bucketName: 'myStorage${hash}-${env}' })], - }); - const out = transformer.transform(validSchema); - expect(out.schema).toBeDefined(); - expect(out.stacks['PredictionsDirectiveStack'].Resources['QueryspeakTranslatedImageTextResolver']).toMatchSnapshot(); - expect(out.pipelineFunctions['convertTextToSpeechFunction.req.vtl']).toMatchSnapshot(); - expect(out.pipelineFunctions['identifyTextFunction.req.vtl']).toMatchSnapshot(); - expect(out.pipelineFunctions['translateTextFunction.req.vtl']).toMatchSnapshot(); -}); diff --git a/packages/graphql-predictions-transformer/src/__tests__/__snapshots__/PredictionsTransformer.test.ts.snap b/packages/graphql-predictions-transformer/src/__tests__/__snapshots__/PredictionsTransformer.test.ts.snap deleted file mode 100644 index 5d0117ca95..0000000000 --- a/packages/graphql-predictions-transformer/src/__tests__/__snapshots__/PredictionsTransformer.test.ts.snap +++ /dev/null @@ -1,208 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`lambda function is added to pipeline when lambda dependent action is added 1`] = ` -"type Query { - speakTranslatedText(input: SpeakTranslatedTextInput!): String -} - -input SpeakTranslatedTextTranslateTextInput { - sourceLanguage: String! - targetLanguage: String! - text: String! -} - -input SpeakTranslatedTextConvertTextToSpeechInput { - voiceID: String! -} - -input SpeakTranslatedTextInput { - translateText: SpeakTranslatedTextTranslateTextInput! - convertTextToSpeech: SpeakTranslatedTextConvertTextToSpeechInput! -} -" -`; - -exports[`return type is a list based on the action 1`] = ` -"type Query { - translateLabels(input: TranslateLabelsInput!): [String] -} - -input TranslateLabelsIdentifyLabelsInput { - key: String! -} - -input TranslateLabelsTranslateTextInput { - sourceLanguage: String! - targetLanguage: String! -} - -input TranslateLabelsInput { - identifyLabels: TranslateLabelsIdentifyLabelsInput! - translateText: TranslateLabelsTranslateTextInput! -} -" -`; - -exports[`snapshot test to check generated function resolvers 1`] = ` -Object { - "DependsOn": Array [], - "Properties": Object { - "ApiId": Object { - "Ref": "AppSyncApiId", - }, - "FieldName": "speakTranslatedImageText", - "Kind": "PIPELINE", - "PipelineConfig": Object { - "Functions": Array [ - Object { - "Fn::GetAtt": Array [ - "identifyTextFunction", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "translateTextFunction", - "FunctionId", - ], - }, - Object { - "Fn::GetAtt": Array [ - "convertTextToSpeechFunction", - "FunctionId", - ], - }, - ], - }, - "RequestMappingTemplate": Object { - "Fn::Join": Array [ - " -", - Array [ - Object { - "Fn::If": Array [ - "HasEnvironmentParameter", - Object { - "Fn::Sub": Array [ - "$util.qr($ctx.stash.put(\\"s3Bucket\\", \\"myStorage\${hash}-\${env}\\"))", - Object { - "env": Object { - "Ref": "env", - }, - "hash": Object { - "Fn::Select": Array [ - 3, - Object { - "Fn::Split": Array [ - "-", - Object { - "Ref": "AWS::StackName", - }, - ], - }, - ], - }, - }, - ], - }, - Object { - "Fn::Sub": Array [ - "$util.qr($ctx.stash.put(\\"s3Bucket\\", \\"myStorage\${hash}\\"))", - Object { - "hash": Object { - "Fn::Select": Array [ - 3, - Object { - "Fn::Split": Array [ - "-", - Object { - "Ref": "AWS::StackName", - }, - ], - }, - ], - }, - }, - ], - }, - ], - }, - "$util.qr($ctx.stash.put(\\"isList\\", false)) -{}", - ], - ], - }, - "ResponseMappingTemplate": "## If the result is a list return the result as a list ** -#if( $ctx.stash.get(\\"isList\\") ) - #set( $result = $ctx.result.split(\\"[ ,]+\\") ) - $util.toJson($result) -#else - $util.toJson($ctx.result) -#end", - "TypeName": "Query", - }, - "Type": "AWS::AppSync::Resolver", -} -`; - -exports[`snapshot test to check generated function resolvers 2`] = ` -"#set( $bucketName = $ctx.stash.get(\\"s3Bucket\\") ) -$util.qr($ctx.stash.put(\\"isList\\", false)) -#set( $text = $util.defaultIfNull($ctx.args.input.convertTextToSpeech.text, $ctx.prev.result) ) -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"Invoke\\", - \\"payload\\": $util.toJson({ - \\"uuid\\": \\"$util.autoId()\\", - \\"action\\": \\"convertTextToSpeech\\", - \\"voiceID\\": $ctx.args.input.convertTextToSpeech.voiceID, - \\"text\\": $text -}) -}" -`; - -exports[`snapshot test to check generated function resolvers 3`] = ` -"#set( $bucketName = $ctx.stash.get(\\"s3Bucket\\") ) -#set( $identityTextKey = $ctx.args.input.identifyText.key ) -#set( $identifyTextPayload = { - \\"version\\": \\"2018-05-29\\", - \\"method\\": \\"POST\\", - \\"resourcePath\\": \\"/\\", - \\"params\\": { - \\"body\\": { - \\"Image\\": { - \\"S3Object\\": { - \\"Bucket\\": \\"$bucketName\\", - \\"Name\\": \\"public/$identityTextKey\\" - } - } - }, - \\"headers\\": { - \\"Content-Type\\": \\"application/x-amz-json-1.1\\", - \\"X-Amz-Target\\": \\"RekognitionService.DetectText\\" - } - } -} ) -$util.toJson($identifyTextPayload)" -`; - -exports[`snapshot test to check generated function resolvers 4`] = ` -"#set( $text = $util.defaultIfNull($ctx.args.input.translateText.text, $ctx.prev.result) ) -#set( $translateTextPayload = { - \\"version\\": \\"2018-05-29\\", - \\"method\\": \\"POST\\", - \\"resourcePath\\": \\"/\\", - \\"params\\": { - \\"body\\": { - \\"SourceLanguageCode\\": $ctx.args.input.translateText.sourceLanguage, - \\"TargetLanguageCode\\": $ctx.args.input.translateText.targetLanguage, - \\"Text\\": $text - }, - \\"headers\\": { - \\"Content-Type\\": \\"application/x-amz-json-1.1\\", - \\"X-Amz-Target\\": \\"AWSShineFrontendService_20170701.TranslateText\\" - } - } -} ) -$util.toJson($translateTextPayload)" -`; diff --git a/packages/graphql-predictions-transformer/src/definitions.ts b/packages/graphql-predictions-transformer/src/definitions.ts deleted file mode 100644 index d8651ee7b1..0000000000 --- a/packages/graphql-predictions-transformer/src/definitions.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { InputValueDefinitionNode, InputObjectTypeDefinitionNode, Kind, FieldDefinitionNode } from 'graphql'; -import { makeNamedType, makeNonNullType, makeListType } from 'graphql-transformer-common'; - -function inputValueDefinition(inputValue: string, namedType: string, isNonNull: boolean = false): InputValueDefinitionNode { - return { - kind: Kind.INPUT_VALUE_DEFINITION, - name: { kind: 'Name' as const, value: inputValue }, - type: isNonNull ? makeNonNullType(makeNamedType(namedType)) : makeNamedType(namedType), - directives: [], - }; -} - -export function capitalizeFirstLetter(str: string) { - return str.charAt(0).toUpperCase() + str.slice(1); -} - -export function getActionInputName(action: string, fieldName: string) { - return `${capitalizeFirstLetter(fieldName)}${capitalizeFirstLetter(action)}Input`; -} - -export function makeActionInputObject(fieldName: string, fields: InputValueDefinitionNode[]): InputObjectTypeDefinitionNode { - return { - kind: Kind.INPUT_OBJECT_TYPE_DEFINITION, - name: { kind: 'Name' as const, value: `${capitalizeFirstLetter(fieldName)}Input` }, - fields, - directives: [], - }; -} - -export function getActionInputType(action: string, fieldName: string, isFirst: boolean = false): InputObjectTypeDefinitionNode { - const actionInputFields: { [action: string]: InputValueDefinitionNode[] } = { - identifyText: [inputValueDefinition('key', 'String', true)], - identifyLabels: [inputValueDefinition('key', 'String', true)], - translateText: [ - inputValueDefinition('sourceLanguage', 'String', true), - inputValueDefinition('targetLanguage', 'String', true), - ...(isFirst ? [inputValueDefinition('text', 'String', true)] : []), - ], - convertTextToSpeech: [ - inputValueDefinition('voiceID', 'String', true), - ...(isFirst ? [inputValueDefinition('text', 'String', true)] : []), - ], - }; - return { - kind: Kind.INPUT_OBJECT_TYPE_DEFINITION, - name: { kind: 'Name', value: getActionInputName(action, fieldName) }, - fields: actionInputFields[action], - directives: [], - }; -} - -export function addInputArgument(field: FieldDefinitionNode, fieldName: string, isList: boolean): FieldDefinitionNode { - return { - ...field, - arguments: [ - { - kind: Kind.INPUT_VALUE_DEFINITION, - name: { kind: 'Name' as const, value: 'input' }, - type: makeNonNullType(makeNamedType(`${capitalizeFirstLetter(fieldName)}Input`)), - directives: [], - }, - ], - type: isList ? makeListType(makeNamedType('String')) : makeNamedType('String'), - }; -} - -export function createInputValueAction(action: string, fieldName: string): InputValueDefinitionNode { - return { - kind: Kind.INPUT_VALUE_DEFINITION, - name: { kind: 'Name' as const, value: `${action}` }, - type: makeNonNullType(makeNamedType(getActionInputName(action, fieldName))), - directives: [], - }; -} diff --git a/packages/graphql-predictions-transformer/src/index.ts b/packages/graphql-predictions-transformer/src/index.ts deleted file mode 100644 index e9392ed832..0000000000 --- a/packages/graphql-predictions-transformer/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './PredictionsTransformer'; -// No-op change to trigger publish diff --git a/packages/graphql-predictions-transformer/src/predictions_utils.ts b/packages/graphql-predictions-transformer/src/predictions_utils.ts deleted file mode 100644 index ab0d5dc47d..0000000000 --- a/packages/graphql-predictions-transformer/src/predictions_utils.ts +++ /dev/null @@ -1,22 +0,0 @@ -export const iamActions = { - identifyText: 'rekognition:DetectText', - identifyLabels: 'rekognition:DetectLabels', - translateText: 'translate:TranslateText', -}; - -export const iamLambdaActions = ['convertTextToSpeech']; - -export const allowedActions = { - identifyText: { - next: ['translateText'], - }, - identifyLabels: { - next: ['translateText', 'convertTextToSpeech'], - }, - translateText: { - next: ['convertTextToSpeech'], - }, - convertTextToSpeech: { - next: [], - }, -}; diff --git a/packages/graphql-predictions-transformer/src/resources.ts b/packages/graphql-predictions-transformer/src/resources.ts deleted file mode 100644 index fa051df0e1..0000000000 --- a/packages/graphql-predictions-transformer/src/resources.ts +++ /dev/null @@ -1,479 +0,0 @@ -import { ResourceConstants, PredictionsResourceIDs } from 'graphql-transformer-common'; -import { - obj, - str, - print, - int, - ref, - iff, - compoundExpression, - ifElse, - raw, - set, - forEach, - ObjectNode, - CompoundExpressionNode, - qref, - toJson, - comment, - HttpMappingTemplate, -} from 'graphql-mapping-template'; -import { IAM, Fn, AppSync, Lambda } from 'cloudform-types'; -import DataSource, { HttpConfig, LambdaConfig } from 'cloudform-types/types/appSync/dataSource'; -import { Policy } from 'cloudform-types/types/iam/group'; -import { iamActions } from './predictions_utils'; - -// tslint:disable: no-magic-numbers -export interface PredictionsDSConfig { - id: 'RekognitionDataSource' | 'TranslateDataSource' | 'LambdaDataSource'; - httpConfig?: HttpConfig; - lambdaConfig?: LambdaConfig; -} -export type ActionPolicyMap = { - [action: string]: Policy; -}; -export class ResourceFactory { - public createIAMRole(map: ActionPolicyMap, bucketName: string) { - return new IAM.Role({ - RoleName: this.joinWithEnv('-', [ - PredictionsResourceIDs.iamRole, - Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - ]), - AssumeRolePolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Principal: { - Service: 'appsync.amazonaws.com', - }, - Action: 'sts:AssumeRole', - }, - ], - }, - Policies: [ - new IAM.Role.Policy({ - PolicyName: 'PredictionsStorageAccess', - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Action: ['s3:GetObject'], - Effect: 'Allow', - Resource: this.getStorageARN(bucketName), - }, - ], - }, - }), - ...Object.values(map), - ], - }); - } - - private getStorageARN(name: string) { - const substitutions = { - hash: Fn.Select(3, Fn.Split('-', Fn.Ref('AWS::StackName'))), - }; - if (this.referencesEnv(name)) { - substitutions['env'] = Fn.Ref(ResourceConstants.PARAMETERS.Env); - } - return Fn.If( - ResourceConstants.CONDITIONS.HasEnvironmentParameter, - Fn.Sub(this.s3ArnKey(name), substitutions), - Fn.Sub(this.s3ArnKey(this.removeEnvReference(name)), { hash: Fn.Select(3, Fn.Split('-', Fn.Ref('AWS::StackName'))) }), - ); - } - - private addStorageInStash(storage: string) { - const substitutions = { - hash: Fn.Select(3, Fn.Split('-', Fn.Ref('AWS::StackName'))), - }; - if (this.referencesEnv(storage)) { - substitutions['env'] = Fn.Ref(ResourceConstants.PARAMETERS.Env); - } - return Fn.If( - ResourceConstants.CONDITIONS.HasEnvironmentParameter, - Fn.Sub(`$util.qr($ctx.stash.put("s3Bucket", "${storage}"))`, substitutions), - Fn.Sub(`$util.qr($ctx.stash.put("s3Bucket", "${this.removeEnvReference(storage)}"))`, { - hash: Fn.Select(3, Fn.Split('-', Fn.Ref('AWS::StackName'))), - }), - ); - } - - private s3ArnKey(name: string) { - return `arn:aws:s3:::${name}/public/*`; - } - - public mergeActionRole(map: ActionPolicyMap, action: string) { - if (!map[action] && iamActions[action]) { - map[action] = new IAM.Role.Policy({ - PolicyName: `${action}Access`, - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Action: [iamActions[action]], - Effect: 'Allow', - Resource: '*', - }, - ], - }, - }); - } - return map; - } - - public mergeLambdaActionRole(map: ActionPolicyMap) { - if (!map['PredictionsLambdaAccess']) { - map['PredictionsLambdaAccess'] = new IAM.Role.Policy({ - PolicyName: 'PredictionsLambdaAccess', - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Action: ['lambda:InvokeFunction'], - Effect: 'Allow', - Resource: Fn.GetAtt(PredictionsResourceIDs.lambdaID, 'Arn'), - }, - ], - }, - }); - } - return map; - } - - public createLambdaIAMRole(bucketName: string) { - return new IAM.Role({ - RoleName: this.joinWithEnv('-', [ - PredictionsResourceIDs.lambdaIAMRole, - Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - ]), - AssumeRolePolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Principal: { - Service: 'lambda.amazonaws.com', - }, - Action: 'sts:AssumeRole', - }, - ], - }, - Policies: [ - new IAM.Role.Policy({ - PolicyName: 'PollyAccess', - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Action: ['polly:SynthesizeSpeech'], - Effect: 'Allow', - Resource: '*', - }, - ], - }, - }), - ], - }); - } - - public createPredictionsDataSource(config: PredictionsDSConfig): DataSource { - let dataSource: DataSource; - if (config.httpConfig) { - dataSource = new AppSync.DataSource({ - ApiId: Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), - Name: config.id, - Type: 'HTTP', - ServiceRoleArn: Fn.GetAtt(PredictionsResourceIDs.iamRole, 'Arn'), - HttpConfig: config.httpConfig, - }).dependsOn(PredictionsResourceIDs.iamRole); - } - if (config.lambdaConfig) { - dataSource = new AppSync.DataSource({ - ApiId: Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), - Name: config.id, - Type: 'AWS_LAMBDA', - ServiceRoleArn: Fn.GetAtt(PredictionsResourceIDs.iamRole, 'Arn'), - LambdaConfig: config.lambdaConfig, - }).dependsOn([PredictionsResourceIDs.iamRole, PredictionsResourceIDs.lambdaID]); - } - return dataSource; - } - - public getPredictionsDSConfig(action: string): PredictionsDSConfig { - switch (action) { - case 'identifyEntities': - case 'identifyText': - case 'identifyLabels': - return { - id: 'RekognitionDataSource', - httpConfig: { - Endpoint: Fn.Sub('https://rekognition.${AWS::Region}.amazonaws.com', {}), - AuthorizationConfig: { - AuthorizationType: 'AWS_IAM', - AwsIamConfig: { - SigningRegion: Fn.Sub('${AWS::Region}', {}), - SigningServiceName: 'rekognition', - }, - }, - }, - }; - case 'translateText': - return { - id: 'TranslateDataSource', - httpConfig: { - Endpoint: Fn.Sub('https://translate.${AWS::Region}.amazonaws.com', {}), - AuthorizationConfig: { - AuthorizationType: 'AWS_IAM', - AwsIamConfig: { - SigningRegion: Fn.Sub('${AWS::Region}', {}), - SigningServiceName: 'translate', - }, - }, - }, - }; - case 'convertTextToSpeech': - return { - id: 'LambdaDataSource', - lambdaConfig: { - LambdaFunctionArn: Fn.GetAtt(PredictionsResourceIDs.lambdaID, 'Arn'), - }, - }; - default: - break; - } - } - - private joinWithEnv(separator: string, listToJoin: any[]) { - return Fn.If( - ResourceConstants.CONDITIONS.HasEnvironmentParameter, - Fn.Join(separator, [...listToJoin, Fn.Ref(ResourceConstants.PARAMETERS.Env)]), - Fn.Join(separator, listToJoin), - ); - } - - public createResolver(type: string, field: string, pipelineFunctions: any[], bucketName: string) { - return new AppSync.Resolver({ - ApiId: Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), - TypeName: type, - FieldName: field, - Kind: 'PIPELINE', - PipelineConfig: { - Functions: pipelineFunctions, - }, - RequestMappingTemplate: Fn.Join('\n', [ - this.addStorageInStash(bucketName), - print(compoundExpression([qref('$ctx.stash.put("isList", false)'), obj({})])), - ]), - ResponseMappingTemplate: print( - compoundExpression([ - comment('If the result is a list return the result as a list'), - ifElse( - ref('ctx.stash.get("isList")'), - compoundExpression([set(ref('result'), ref('ctx.result.split("[ ,]+")')), toJson(ref('result'))]), - toJson(ref('ctx.result')), - ), - ]), - ), - }).dependsOn(pipelineFunctions); - } - - // predictions action functions - public createActionFunction(action: string, datasourceName: string) { - const httpPayload = `${action}Payload`; - const actionFunctionResolvers = { - identifyText: { - request: compoundExpression([ - set(ref('bucketName'), ref('ctx.stash.get("s3Bucket")')), - set(ref('identityTextKey'), ref('ctx.args.input.identifyText.key')), - set( - ref(httpPayload), - HttpMappingTemplate.postRequest({ - resourcePath: '/', - params: obj({ - body: obj({ - Image: obj({ - S3Object: obj({ - Bucket: str('$bucketName'), - Name: str('public/$identityTextKey'), - }), - }), - }), - headers: obj({ - 'Content-Type': str('application/x-amz-json-1.1'), - 'X-Amz-Target': str('RekognitionService.DetectText'), - }), - }), - }), - ), - toJson(ref(httpPayload)), - ]), - response: compoundExpression([ - iff(ref('ctx.error'), ref('util.error($ctx.error.message)')), - ifElse( - raw('$ctx.result.statusCode == 200'), - compoundExpression([ - set(ref('results'), ref('util.parseJson($ctx.result.body)')), - set(ref('finalResult'), str('')), - forEach(/** for */ ref('item'), /** in */ ref('results.TextDetections'), [ - iff(raw('$item.Type == "LINE"'), set(ref('finalResult'), str('$finalResult$item.DetectedText '))), - ]), - ref('util.toJson($finalResult.trim())'), - ]), - ref('utils.error($ctx.result.body)'), - ), - ]), - }, - identifyLabels: { - request: compoundExpression([ - set(ref('bucketName'), ref('ctx.stash.get("s3Bucket")')), - set(ref('identifyLabelKey'), ref('$ctx.args.input.identifyLabels.key')), - qref('$ctx.stash.put("isList", true)'), - set( - ref(httpPayload), - HttpMappingTemplate.postRequest({ - resourcePath: '/', - params: obj({ - body: obj({ - Image: obj({ - S3Object: obj({ - Bucket: str('$bucketName'), - Name: str('public/$identifyLabelKey'), - }), - }), - MaxLabels: int(10), - MinConfidence: int(55), - }), - headers: obj({ - 'Content-Type': str('application/x-amz-json-1.1'), - 'X-Amz-Target': str('RekognitionService.DetectLabels'), - }), - }), - }), - ), - toJson(ref(httpPayload)), - ]), - response: compoundExpression([ - iff(ref('ctx.error'), ref('util.error($ctx.error.message)')), - ifElse( - raw('$ctx.result.statusCode == 200'), - compoundExpression([ - set(ref('labels'), str('')), - set(ref('result'), ref('util.parseJson($ctx.result.body)')), - forEach(/** for */ ref('label'), /** in */ ref('result.Labels'), [set(ref('labels'), str('$labels$label.Name, '))]), - toJson(ref('labels.replaceAll(", $", "")')), // trim unnessary space - ]), - ref('util.error($ctx.result.body)'), - ), - ]), - }, - translateText: { - request: compoundExpression([ - set(ref('text'), ref('util.defaultIfNull($ctx.args.input.translateText.text, $ctx.prev.result)')), - set( - ref(httpPayload), - HttpMappingTemplate.postRequest({ - resourcePath: '/', - params: obj({ - body: obj({ - SourceLanguageCode: ref('ctx.args.input.translateText.sourceLanguage'), - TargetLanguageCode: ref('ctx.args.input.translateText.targetLanguage'), - Text: ref('text'), - }), - headers: obj({ - 'Content-Type': str('application/x-amz-json-1.1'), - 'X-Amz-Target': str('AWSShineFrontendService_20170701.TranslateText'), - }), - }), - }), - ), - toJson(ref(httpPayload)), - ]), - response: compoundExpression([ - iff(ref('ctx.error'), ref('util.error($ctx.error.message)')), - ifElse( - raw('$ctx.result.statusCode == 200'), - compoundExpression([set(ref('result'), ref('util.parseJson($ctx.result.body)')), ref('util.toJson($result.TranslatedText)')]), - ref('util.error($ctx.result.body)'), - ), - ]), - }, - convertTextToSpeech: { - request: compoundExpression([ - set(ref('bucketName'), ref('ctx.stash.get("s3Bucket")')), - qref('$ctx.stash.put("isList", false)'), - set(ref('text'), ref('util.defaultIfNull($ctx.args.input.convertTextToSpeech.text, $ctx.prev.result)')), - obj({ - version: str('2018-05-29'), - operation: str('Invoke'), - payload: toJson( - obj({ - uuid: str('$util.autoId()'), - action: str('convertTextToSpeech'), - voiceID: ref('ctx.args.input.convertTextToSpeech.voiceID'), - text: ref('text'), - }), - ), - }), - ]), - response: compoundExpression([ - iff(ref('ctx.error'), ref('util.error($ctx.error.message, $ctx.error.type)')), - set(ref('response'), ref('util.parseJson($ctx.result)')), - ref('util.toJson($ctx.result.url)'), - ]), - }, - }; - return this.genericFunction(action, datasourceName, PredictionsResourceIDs.iamRole, actionFunctionResolvers[action]); - } - - private genericFunction( - action: string, - datasourceName: string, - iamRole: string, - resolver: { - request: ObjectNode | CompoundExpressionNode; - response: ObjectNode | CompoundExpressionNode; - }, - ) { - return new AppSync.FunctionConfiguration({ - ApiId: Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), - Name: `${action}Function`, - DataSourceName: datasourceName, - FunctionVersion: '2018-05-29', - RequestMappingTemplate: print(resolver.request), - ResponseMappingTemplate: print(resolver.response), - }).dependsOn([iamRole, datasourceName]); - } - - // Predictions Lambda Function - public createPredictionsLambda() { - return new Lambda.Function({ - Code: { - S3Bucket: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentBucket), - S3Key: Fn.Join('/', [ - Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentRootKey), - 'functions', - Fn.Join('.', [PredictionsResourceIDs.lambdaID, 'zip']), - ]), - }, - FunctionName: this.joinWithEnv('-', [ - PredictionsResourceIDs.lambdaName, - Fn.GetAtt(ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'), - ]), - Handler: PredictionsResourceIDs.lambdaHandlerName, - Role: Fn.GetAtt(PredictionsResourceIDs.lambdaIAMRole, 'Arn'), - Runtime: PredictionsResourceIDs.lambdaRuntime, - Timeout: PredictionsResourceIDs.lambdaTimeout, - }).dependsOn([PredictionsResourceIDs.lambdaIAMRole]); - } - - // storage env ref - public referencesEnv(value: string) { - return value.match(/(\${env})/) !== null; - } - - public removeEnvReference(value: string) { - return value.replace(/(-\${env})/, ''); - } -} diff --git a/packages/graphql-predictions-transformer/tsconfig.json b/packages/graphql-predictions-transformer/tsconfig.json deleted file mode 100644 index f3fc268a32..0000000000 --- a/packages/graphql-predictions-transformer/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "strict": false, // TODO enable - "rootDir": "src", - "outDir": "lib" - }, - "references": [ - { "path": "../amplify-graphql-directives" }, - { "path": "../graphql-mapping-template" }, - { "path": "../graphql-transformer-common" }, - { "path": "../graphql-transformer-core" } - ] -} diff --git a/packages/graphql-relational-schema-transformer/.npmignore b/packages/graphql-relational-schema-transformer/.npmignore deleted file mode 100644 index 3ee5d55b0b..0000000000 --- a/packages/graphql-relational-schema-transformer/.npmignore +++ /dev/null @@ -1,5 +0,0 @@ -**/__mocks__/** -**/__tests__/** -src -tsconfig.json -tsconfig.tsbuildinfo diff --git a/packages/graphql-relational-schema-transformer/API.md b/packages/graphql-relational-schema-transformer/API.md deleted file mode 100644 index 5ec2038233..0000000000 --- a/packages/graphql-relational-schema-transformer/API.md +++ /dev/null @@ -1,163 +0,0 @@ -## API Report File for "graphql-relational-schema-transformer" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { DocumentNode } from 'graphql'; -import { InputObjectTypeDefinitionNode } from 'graphql'; -import { ObjectTypeDefinitionNode } from 'graphql'; -import { SchemaDefinitionNode } from 'graphql'; -import Template from 'cloudform-types/types/template'; - -// @public (undocumented) -export class AuroraDataAPIClient { - constructor(databaseRegion: string, awsSecretStoreArn: string, dbClusterOrInstanceArn: string, database: string, aws: any); - // (undocumented) - AWS: any; - // (undocumented) - describeTable: (tableName: string) => Promise; - // (undocumented) - getTableForeignKeyReferences: (tableName: string) => Promise; - // (undocumented) - listTables: () => Promise; - // (undocumented) - Params: DataApiParams; - // (undocumented) - RDS: any; - // (undocumented) - setRDSClient(rdsClient: any): void; -} - -// Warning: (ae-forgotten-export) The symbol "IRelationalDBReader" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export class AuroraServerlessMySQLDatabaseReader implements IRelationalDBReader { - constructor(dbRegion: string, awsSecretStoreArn: string, dbClusterOrInstanceArn: string, database: string, aws: any); - // (undocumented) - auroraClient: AuroraDataAPIClient; - // (undocumented) - awsSecretStoreArn: string; - // (undocumented) - database: string; - // (undocumented) - dbClusterOrInstanceArn: string; - // (undocumented) - dbRegion: string; - // (undocumented) - describeTable: (tableName: string) => Promise; - // (undocumented) - getTableForeignKeyReferences: (tableName: string) => Promise; - // (undocumented) - hydrateTemplateContext: (contextShell: TemplateContext) => Promise; - // (undocumented) - listTables: () => Promise; - // (undocumented) - setAuroraClient(auroraClient: AuroraDataAPIClient): void; -} - -// @public (undocumented) -export class ColumnDescription { - // (undocumented) - Default: string; - // (undocumented) - Extra: string; - // (undocumented) - Field: string; - // (undocumented) - Key: string; - // (undocumented) - Null: string; - // (undocumented) - Type: string; -} - -// @public (undocumented) -export class DataApiParams { - // (undocumented) - database: string; - // (undocumented) - resourceArn: string; - // (undocumented) - secretArn: string; - // (undocumented) - sql: string; -} - -// @public (undocumented) -export class RelationalDBSchemaTransformer { - constructor(dbReader: IRelationalDBReader, database: string, improvePluralization: boolean); - // (undocumented) - database: string; - // (undocumented) - dbReader: IRelationalDBReader; - // (undocumented) - getConnectionType(tableName: string): ObjectTypeDefinitionNode; - // (undocumented) - getSchemaType(): SchemaDefinitionNode; - // (undocumented) - improvePluralization: boolean; - // (undocumented) - introspectDatabaseSchema: () => Promise; -} - -// @public (undocumented) -export class RelationalDBTemplateGenerator { - constructor(context: TemplateContext); - // (undocumented) - addRelationalResolvers(template: Template, resolverFilePath: string, improvePluralization: boolean): Template; - // (undocumented) - context: TemplateContext; - // (undocumented) - createTemplate(context: any): Template; - // (undocumented) - printCloudformationTemplate(template: Template): string; -} - -// @public (undocumented) -export class TableContext { - constructor(typeDefinition: ObjectTypeDefinitionNode, createDefinition: InputObjectTypeDefinitionNode, updateDefinition: InputObjectTypeDefinitionNode, primaryKeyField: string, primaryKeyType: string, stringFieldList: string[], intFieldList: string[]); - // (undocumented) - createTypeDefinition: InputObjectTypeDefinitionNode; - // (undocumented) - intFieldList: string[]; - // (undocumented) - stringFieldList: string[]; - // (undocumented) - tableKeyField: string; - // (undocumented) - tableKeyFieldType: string; - // (undocumented) - tableTypeDefinition: ObjectTypeDefinitionNode; - // (undocumented) - updateTypeDefinition: InputObjectTypeDefinitionNode; -} - -// @public (undocumented) -export class TemplateContext { - constructor(schemaDoc: DocumentNode, typePrimaryKeyMap: Map, stringFieldMap: Map, intFieldMap: Map, typePrimaryKeyTypeMap?: Map); - // (undocumented) - databaseName: string; - // (undocumented) - databaseSchema: string; - // (undocumented) - intFieldMap: Map; - // (undocumented) - rdsClusterIdentifier: string; - // (undocumented) - region: string; - // (undocumented) - schemaDoc: DocumentNode; - // (undocumented) - secretStoreArn: string; - // (undocumented) - stringFieldMap: Map; - // (undocumented) - typePrimaryKeyMap: Map; - // (undocumented) - typePrimaryKeyTypeMap: Map; -} - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/graphql-relational-schema-transformer/CHANGELOG.md b/packages/graphql-relational-schema-transformer/CHANGELOG.md deleted file mode 100644 index 05e4b071a6..0000000000 --- a/packages/graphql-relational-schema-transformer/CHANGELOG.md +++ /dev/null @@ -1,537 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [2.21.34](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.33...graphql-relational-schema-transformer@2.21.34) (2024-07-02) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.33](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.32...graphql-relational-schema-transformer@2.21.33) (2024-06-25) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.32](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.31...graphql-relational-schema-transformer@2.21.32) (2024-04-26) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.31](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.30...graphql-relational-schema-transformer@2.21.31) (2024-04-11) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.30](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.29...graphql-relational-schema-transformer@2.21.30) (2024-03-28) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.29](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.28...graphql-relational-schema-transformer@2.21.29) (2024-02-28) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.28](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.27...graphql-relational-schema-transformer@2.21.28) (2024-02-05) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.27](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.26...graphql-relational-schema-transformer@2.21.27) (2023-12-18) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.26](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.25...graphql-relational-schema-transformer@2.21.26) (2023-12-06) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.25](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.24...graphql-relational-schema-transformer@2.21.25) (2023-11-18) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.24](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.23...graphql-relational-schema-transformer@2.21.24) (2023-11-16) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.23](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.22...graphql-relational-schema-transformer@2.21.23) (2023-11-15) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.22](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.21...graphql-relational-schema-transformer@2.21.22) (2023-08-30) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.21](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.20...graphql-relational-schema-transformer@2.21.21) (2023-07-21) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.20](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.19...graphql-relational-schema-transformer@2.21.20) (2023-07-17) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.19](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.18...graphql-relational-schema-transformer@2.21.19) (2023-06-29) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.18](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.17...graphql-relational-schema-transformer@2.21.18) (2023-05-17) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.17](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.16...graphql-relational-schema-transformer@2.21.17) (2023-04-25) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.16](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.15...graphql-relational-schema-transformer@2.21.16) (2023-03-01) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.16-beta.1](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.15...graphql-relational-schema-transformer@2.21.16-beta.1) (2023-02-21) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.16-beta.0](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.15...graphql-relational-schema-transformer@2.21.16-beta.0) (2023-02-15) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.15](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.14...graphql-relational-schema-transformer@2.21.15) (2023-02-10) - -### Bug Fixes - -- add util.toJson to values of variableMap ([052da87](https://github.com/aws-amplify/amplify-category-api/commit/052da87c5a35162f4bc32526064ca56413829abc)) -- convert the variableMap toJson only once ([ce8c555](https://github.com/aws-amplify/amplify-category-api/commit/ce8c55585a2483869b5a88da092f7dfed229588e)) -- use parameterized SQL statements and variableMap ([005cad7](https://github.com/aws-amplify/amplify-category-api/commit/005cad720cc130cb6b46c01b15f0abed976ac16b)) - -## [2.21.14](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.13...graphql-relational-schema-transformer@2.21.14) (2023-01-26) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.13](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.12...graphql-relational-schema-transformer@2.21.13) (2023-01-12) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.12](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.11...graphql-relational-schema-transformer@2.21.12) (2023-01-12) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.11](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.10...graphql-relational-schema-transformer@2.21.11) (2022-12-03) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.10](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.9...graphql-relational-schema-transformer@2.21.10) (2022-07-01) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.9](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.8...graphql-relational-schema-transformer@2.21.9) (2022-06-23) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.8](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.6...graphql-relational-schema-transformer@2.21.8) (2022-06-07) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.7](https://github.com/aws-amplify/amplify-category-api/compare/graphql-relational-schema-transformer@2.21.6...graphql-relational-schema-transformer@2.21.7) (2022-05-31) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.21.5...graphql-relational-schema-transformer@2.21.6) (2022-04-27) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.21.4...graphql-relational-schema-transformer@2.21.5) (2022-03-07) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.21.3...graphql-relational-schema-transformer@2.21.4) (2022-01-31) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.21.2...graphql-relational-schema-transformer@2.21.3) (2022-01-13) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.21.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.21.0...graphql-relational-schema-transformer@2.21.2) (2022-01-10) - -## 7.6.7 (2022-01-10) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -# [2.21.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.20.2...graphql-relational-schema-transformer@2.21.0) (2021-11-23) - -### Features - -- override support for api category ([#9013](https://github.com/aws-amplify/amplify-cli/issues/9013)) ([ae7b001](https://github.com/aws-amplify/amplify-cli/commit/ae7b001f274f327a29c99c67fe851272c6208e84)), closes [#9001](https://github.com/aws-amplify/amplify-cli/issues/9001) [#8954](https://github.com/aws-amplify/amplify-cli/issues/8954) [#8958](https://github.com/aws-amplify/amplify-cli/issues/8958) [#8960](https://github.com/aws-amplify/amplify-cli/issues/8960) [#8967](https://github.com/aws-amplify/amplify-cli/issues/8967) [#8971](https://github.com/aws-amplify/amplify-cli/issues/8971) [#8976](https://github.com/aws-amplify/amplify-cli/issues/8976) [#8975](https://github.com/aws-amplify/amplify-cli/issues/8975) [#8981](https://github.com/aws-amplify/amplify-cli/issues/8981) [#8983](https://github.com/aws-amplify/amplify-cli/issues/8983) [#8992](https://github.com/aws-amplify/amplify-cli/issues/8992) [#9000](https://github.com/aws-amplify/amplify-cli/issues/9000) [#9002](https://github.com/aws-amplify/amplify-cli/issues/9002) [#9005](https://github.com/aws-amplify/amplify-cli/issues/9005) [#9006](https://github.com/aws-amplify/amplify-cli/issues/9006) [#9007](https://github.com/aws-amplify/amplify-cli/issues/9007) [#9008](https://github.com/aws-amplify/amplify-cli/issues/9008) [#9010](https://github.com/aws-amplify/amplify-cli/issues/9010) [#9011](https://github.com/aws-amplify/amplify-cli/issues/9011) [#9012](https://github.com/aws-amplify/amplify-cli/issues/9012) [#9014](https://github.com/aws-amplify/amplify-cli/issues/9014) [#9015](https://github.com/aws-amplify/amplify-cli/issues/9015) [#9017](https://github.com/aws-amplify/amplify-cli/issues/9017) [#9020](https://github.com/aws-amplify/amplify-cli/issues/9020) [#9024](https://github.com/aws-amplify/amplify-cli/issues/9024) [#9027](https://github.com/aws-amplify/amplify-cli/issues/9027) [#9028](https://github.com/aws-amplify/amplify-cli/issues/9028) [#9029](https://github.com/aws-amplify/amplify-cli/issues/9029) [#9032](https://github.com/aws-amplify/amplify-cli/issues/9032) [#9031](https://github.com/aws-amplify/amplify-cli/issues/9031) [#9035](https://github.com/aws-amplify/amplify-cli/issues/9035) [#9038](https://github.com/aws-amplify/amplify-cli/issues/9038) [#9039](https://github.com/aws-amplify/amplify-cli/issues/9039) - -## [2.20.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.20.1...graphql-relational-schema-transformer@2.20.2) (2021-11-17) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.20.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.18.8...graphql-relational-schema-transformer@2.20.1) (2021-11-15) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.18.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.18.7...graphql-relational-schema-transformer@2.18.8) (2021-11-11) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.18.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.18.6...graphql-relational-schema-transformer@2.18.7) (2021-09-27) - -### Bug Fixes - -- [#8223](https://github.com/aws-amplify/amplify-cli/issues/8223), conversion to typescript ([#8245](https://github.com/aws-amplify/amplify-cli/issues/8245)) ([096e6ca](https://github.com/aws-amplify/amplify-cli/commit/096e6ca19b94aa40ef249ea98d008380395afa16)) -- **graphql-relational-transformer:** fixes broken list and update resolvers ([#8101](https://github.com/aws-amplify/amplify-cli/issues/8101)) ([e61b362](https://github.com/aws-amplify/amplify-cli/commit/e61b362b75e6dfce6406e35e5ab52ffbaf718483)), closes [#8008](https://github.com/aws-amplify/amplify-cli/issues/8008) - -## [2.18.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.18.5...graphql-relational-schema-transformer@2.18.6) (2021-09-02) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.18.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.18.4...graphql-relational-schema-transformer@2.18.5) (2021-08-24) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.18.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.18.3...graphql-relational-schema-transformer@2.18.4) (2021-08-06) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.18.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.18.2...graphql-relational-schema-transformer@2.18.3) (2021-07-27) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.18.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.18.1...graphql-relational-schema-transformer@2.18.2) (2021-07-16) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.18.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.18.0...graphql-relational-schema-transformer@2.18.1) (2021-06-30) - -### Bug Fixes - -- **graphql-transformer-common:** improve generated graphql pluralization ([#7258](https://github.com/aws-amplify/amplify-cli/issues/7258)) ([fc3ad0d](https://github.com/aws-amplify/amplify-cli/commit/fc3ad0dd5a12a7912c59ae12024f593b4cdf7f2d)), closes [#4224](https://github.com/aws-amplify/amplify-cli/issues/4224) - -# [2.18.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.17.3...graphql-relational-schema-transformer@2.18.0) (2021-06-02) - -# 4.52.0 (2021-06-01) - -### Features - -- add support for SMS Sandbox ([#7436](https://github.com/aws-amplify/amplify-cli/issues/7436)) ([cdcb626](https://github.com/aws-amplify/amplify-cli/commit/cdcb6260c11bbedef5b056fdcd730612d8bb3230)) - -## [2.17.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.17.1...graphql-relational-schema-transformer@2.17.3) (2021-05-03) - -## 4.50.1 (2021-05-03) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.17.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.17.1...graphql-relational-schema-transformer@2.17.2) (2021-05-03) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.17.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.16.5...graphql-relational-schema-transformer@2.17.1) (2021-04-09) - -### Bug Fixes - -- **graphql-relational-schema-transformer:** escape String primary key ([#6673](https://github.com/aws-amplify/amplify-cli/issues/6673)) ([de240bd](https://github.com/aws-amplify/amplify-cli/commit/de240bdf2995b23767c9518aa51bc51197f41796)) - -## [2.16.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.16.4...graphql-relational-schema-transformer@2.16.5) (2021-03-05) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.16.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.16.3...graphql-relational-schema-transformer@2.16.4) (2021-02-26) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.16.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.16.2...graphql-relational-schema-transformer@2.16.3) (2021-02-24) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.16.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.16.1...graphql-relational-schema-transformer@2.16.2) (2021-02-11) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.16.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.19...graphql-relational-schema-transformer@2.16.1) (2020-11-22) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -# [2.16.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.13...graphql-relational-schema-transformer@2.16.0) (2020-11-22) - -### Bug Fixes - -- **graphql-relational-schema-transformer:** escape SQL reserved keywords ([#5529](https://github.com/aws-amplify/amplify-cli/issues/5529)) ([9c0408a](https://github.com/aws-amplify/amplify-cli/commit/9c0408adf0a3541ca30b9547c6b84d28b7709783)) -- **graphql-relational-schema-transformer:** fix add datasource update ([#3542](https://github.com/aws-amplify/amplify-cli/issues/3542)) ([176f313](https://github.com/aws-amplify/amplify-cli/commit/176f313fea1e7504bbf12255dc44f424ae1ea4a1)) -- e2e test dependency and cloudform depe for relational ([#3352](https://github.com/aws-amplify/amplify-cli/issues/3352)) ([6b74433](https://github.com/aws-amplify/amplify-cli/commit/6b74433a4ddf7706fef3834f02247a3cd0fd75c2)) -- **graphql-relational-schema-transformer:** fix [#3025](https://github.com/aws-amplify/amplify-cli/issues/3025) rds resolver correctly handles no data in response ([#3314](https://github.com/aws-amplify/amplify-cli/issues/3314)) ([cb826a7](https://github.com/aws-amplify/amplify-cli/commit/cb826a7ec7680ad9b5fc46fd7a931c30747cd0ce)) -- build break, chore: typescript, lerna update ([#2640](https://github.com/aws-amplify/amplify-cli/issues/2640)) ([29fae36](https://github.com/aws-amplify/amplify-cli/commit/29fae366f4cab054feefa58c7dc733002d19570c)) -- export Typescript definitions and fix resulting type errors ([#2452](https://github.com/aws-amplify/amplify-cli/issues/2452)) ([7de3845](https://github.com/aws-amplify/amplify-cli/commit/7de384594d3b9cbf22cdaa85107fc8df26c141ec)), closes [#2451](https://github.com/aws-amplify/amplify-cli/issues/2451) -- **graphql-relational-schema-transformer:** fix input type casing ([#2249](https://github.com/aws-amplify/amplify-cli/issues/2249)) ([3a00d56](https://github.com/aws-amplify/amplify-cli/commit/3a00d56320f8c6a7de415e12ac9c6c4b5954d934)), closes [#2217](https://github.com/aws-amplify/amplify-cli/issues/2217) -- **graphql-relational-schema-transformer:** fix template for string keys ([#2205](https://github.com/aws-amplify/amplify-cli/issues/2205)) ([294fbc6](https://github.com/aws-amplify/amplify-cli/commit/294fbc67c7d8d806c4fe8100eb27b04571a4c811)), closes [#2133](https://github.com/aws-amplify/amplify-cli/issues/2133) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c1927da10f8c54f38a523021187361131c)) -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- implement multi-auth functionality ([#1916](https://github.com/aws-amplify/amplify-cli/issues/1916)) ([b99f58e](https://github.com/aws-amplify/amplify-cli/commit/b99f58e4a2b85cbe9f430838554ae3c277440132)) - -## [2.15.19](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.18...graphql-relational-schema-transformer@2.15.19) (2020-11-08) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.15.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.17...graphql-relational-schema-transformer@2.15.18) (2020-10-30) - -### Bug Fixes - -- **graphql-relational-schema-transformer:** escape SQL reserved keywords ([#5529](https://github.com/aws-amplify/amplify-cli/issues/5529)) ([9c0408a](https://github.com/aws-amplify/amplify-cli/commit/9c0408adf0a3541ca30b9547c6b84d28b7709783)) - -## [2.15.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.16...graphql-relational-schema-transformer@2.15.17) (2020-10-22) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.15.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.15...graphql-relational-schema-transformer@2.15.16) (2020-10-07) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.15.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.14...graphql-relational-schema-transformer@2.15.15) (2020-09-16) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.15.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.13...graphql-relational-schema-transformer@2.15.14) (2020-08-31) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.15.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.12...graphql-relational-schema-transformer@2.15.13) (2020-08-14) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.15.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.10...graphql-relational-schema-transformer@2.15.12) (2020-07-29) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.15.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.10...graphql-relational-schema-transformer@2.15.11) (2020-07-23) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.15.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.9...graphql-relational-schema-transformer@2.15.10) (2020-07-18) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.15.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.8...graphql-relational-schema-transformer@2.15.9) (2020-07-15) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.15.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.7...graphql-relational-schema-transformer@2.15.8) (2020-06-25) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.15.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.6...graphql-relational-schema-transformer@2.15.7) (2020-06-18) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.15.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.5...graphql-relational-schema-transformer@2.15.6) (2020-06-11) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.15.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.4...graphql-relational-schema-transformer@2.15.5) (2020-06-10) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.15.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.3...graphql-relational-schema-transformer@2.15.4) (2020-06-02) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.15.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.2...graphql-relational-schema-transformer@2.15.3) (2020-05-08) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.15.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.15.1...graphql-relational-schema-transformer@2.15.2) (2020-03-22) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.15.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.13.3...graphql-relational-schema-transformer@2.15.1) (2020-03-07) - -### Bug Fixes - -- **graphql-relational-schema-transformer:** fix add datasource update ([#3542](https://github.com/aws-amplify/amplify-cli/issues/3542)) ([176f313](https://github.com/aws-amplify/amplify-cli/commit/176f313fea1e7504bbf12255dc44f424ae1ea4a1)) - -## [2.14.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.13.5-beta.0...graphql-relational-schema-transformer@2.14.1) (2020-03-05) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.13.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.13.2...graphql-relational-schema-transformer@2.13.3) (2020-02-13) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [2.13.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.13.1...graphql-relational-schema-transformer@2.13.2) (2020-02-07) - -### Bug Fixes - -- **graphql-relational-schema-transformer:** fix [#3025](https://github.com/aws-amplify/amplify-cli/issues/3025) rds resolver correctly handles no data in response ([#3314](https://github.com/aws-amplify/amplify-cli/issues/3314)) ([cb826a7](https://github.com/aws-amplify/amplify-cli/commit/cb826a7ec7680ad9b5fc46fd7a931c30747cd0ce)) -- e2e test dependency and cloudform depe for relational ([#3352](https://github.com/aws-amplify/amplify-cli/issues/3352)) ([6b74433](https://github.com/aws-amplify/amplify-cli/commit/6b74433a4ddf7706fef3834f02247a3cd0fd75c2)) - -## [2.13.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@2.13.0...graphql-relational-schema-transformer@2.13.1) (2020-01-24) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -# [2.13.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.24.0...graphql-relational-schema-transformer@2.13.0) (2020-01-23) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.12.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.24.0...graphql-relational-schema-transformer@2.12.0) (2020-01-09) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.11.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.24.0...graphql-relational-schema-transformer@2.11.0) (2019-12-31) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.10.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.24.0...graphql-relational-schema-transformer@2.10.0) (2019-12-28) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.9.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.24.0...graphql-relational-schema-transformer@2.9.0) (2019-12-26) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.8.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.24.0...graphql-relational-schema-transformer@2.8.0) (2019-12-25) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.7.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.24.0...graphql-relational-schema-transformer@2.7.0) (2019-12-20) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.6.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.24.0...graphql-relational-schema-transformer@2.6.0) (2019-12-10) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.4.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.24.0...graphql-relational-schema-transformer@2.4.0) (2019-12-03) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.3.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.24.0...graphql-relational-schema-transformer@2.3.0) (2019-12-01) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.2.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.24.0...graphql-relational-schema-transformer@2.2.0) (2019-11-27) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.1.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.24.0...graphql-relational-schema-transformer@2.1.0) (2019-11-27) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [1.6.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.13...graphql-relational-schema-transformer@1.6.0) (2019-08-30) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [1.5.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.13...graphql-relational-schema-transformer@1.5.0) (2019-08-28) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [1.4.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.13...graphql-relational-schema-transformer@1.4.0) (2019-08-13) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [1.3.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.13...graphql-relational-schema-transformer@1.3.0) (2019-08-07) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [1.2.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.13...graphql-relational-schema-transformer@1.2.0) (2019-08-02) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [1.1.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.13...graphql-relational-schema-transformer@1.1.0) (2019-07-31) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -## [1.0.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.12...graphql-relational-schema-transformer@1.0.13) (2019-07-24) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [1.0.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.10...graphql-relational-schema-transformer@1.0.12) (2019-06-30) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [1.0.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.9...graphql-relational-schema-transformer@1.0.10) (2019-06-26) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [1.0.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.8...graphql-relational-schema-transformer@1.0.9) (2019-06-12) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [1.0.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.7...graphql-relational-schema-transformer@1.0.8) (2019-05-29) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [1.0.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.6...graphql-relational-schema-transformer@1.0.7) (2019-05-24) - -### Bug Fixes - -- **graphql-relational-schema-transformer:** add additional RDS Policies ([#1508](https://github.com/aws-amplify/amplify-cli/issues/1508)) ([b1dcd08](https://github.com/aws-amplify/amplify-cli/commit/b1dcd08)) -- **graphql-relational-schema-transformer:** support \_ in table name ([17e9a04](https://github.com/aws-amplify/amplify-cli/commit/17e9a04)), closes [#1504](https://github.com/aws-amplify/amplify-cli/issues/1504) - -## [1.0.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.5...graphql-relational-schema-transformer@1.0.6) (2019-05-21) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [1.0.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.4...graphql-relational-schema-transformer@1.0.5) (2019-05-17) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [1.0.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.3...graphql-relational-schema-transformer@1.0.4) (2019-05-07) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [1.0.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.2...graphql-relational-schema-transformer@1.0.3) (2019-04-24) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## [1.0.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-relational-schema-transformer@1.0.1...graphql-relational-schema-transformer@1.0.2) (2019-04-16) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -## 1.0.1 (2019-04-16) - -**Note:** Version bump only for package graphql-relational-schema-transformer - -**Note:** Version bump only for package graphql-relational-schema-transformer diff --git a/packages/graphql-relational-schema-transformer/package.json b/packages/graphql-relational-schema-transformer/package.json deleted file mode 100644 index e9b44876c8..0000000000 --- a/packages/graphql-relational-schema-transformer/package.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "name": "graphql-relational-schema-transformer", - "version": "2.21.34", - "description": "An AppSync model transform that takes a relational database and turns that into a GraphQL API.", - "repository": { - "type": "git", - "url": "https://github.com/aws-amplify/amplify-category-api.git", - "directory": "packages/graphql-relational-schema-transformer" - }, - "author": "Amazon Web Services", - "license": "Apache-2.0", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "keywords": [ - "graphql", - "appsync", - "aws" - ], - "scripts": { - "test": "jest --coverage", - "build": "tsc", - "watch": "tsc -w", - "clean": "rimraf ./lib", - "extract-api": "ts-node ../../scripts/extract-api.ts" - }, - "dependencies": { - "cloudform-types": "^4.2.0", - "fs-extra": "^8.1.0", - "graphql": "^15.5.0", - "graphql-mapping-template": "4.20.16", - "graphql-transformer-common": "4.31.1" - }, - "devDependencies": { - "@types/fs-extra": "^8.0.1", - "aws-sdk": "^2.1113.0" - }, - "jest": { - "collectCoverage": true, - "coverageProvider": "v8", - "coverageThreshold": { - "global": { - "branches": 90, - "functions": 90, - "lines": 90 - } - }, - "coverageReporters": [ - "clover", - "text" - ], - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, - "testURL": "http://localhost", - "testRegex": "(src/__tests__/.*.test\\.(js|ts))$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], - "globals": { - "ts-jest": { - "diagnostics": false - } - }, - "collectCoverageFrom": [ - "src/**/*.ts" - ], - "coveragePathIgnorePatterns": [ - "/__tests__/" - ] - } -} diff --git a/packages/graphql-relational-schema-transformer/src/AuroraDataAPIClient.ts b/packages/graphql-relational-schema-transformer/src/AuroraDataAPIClient.ts deleted file mode 100644 index acd1089e80..0000000000 --- a/packages/graphql-relational-schema-transformer/src/AuroraDataAPIClient.ts +++ /dev/null @@ -1,128 +0,0 @@ -/** - * A wrapper around the RDS data service client, forming their responses for - * easier consumption. - */ -export class AuroraDataAPIClient { - AWS: any; - - RDS: any; - - Params: DataApiParams; - - setRDSClient(rdsClient: any) { - this.RDS = rdsClient; - } - - constructor(databaseRegion: string, awsSecretStoreArn: string, dbClusterOrInstanceArn: string, database: string, aws: any) { - this.AWS = aws; - this.AWS.config.update({ - region: databaseRegion, - }); - - this.RDS = new this.AWS.RDSDataService(); - this.Params = new DataApiParams(); - - this.Params.secretArn = awsSecretStoreArn; - this.Params.resourceArn = dbClusterOrInstanceArn; - this.Params.database = database; - } - - /** - * Lists all of the tables in the set database. - * - * @return a list of tables in the database. - */ - public listTables = async () => { - this.Params.sql = 'SHOW TABLES'; - const response = await this.RDS.executeStatement(this.Params).promise(); - - let tableList = []; - const records = response['records']; - for (const record of records) { - tableList.push(record[0]['stringValue']); - } - - return tableList; - }; - - /** - * Describes the table given, by breaking it down into individual column descriptions. - * - * @param the name of the table to be described. - * @return a list of column descriptions. - */ - public describeTable = async (tableName: string) => { - this.Params.sql = `DESCRIBE \`${tableName}\``; - const response = await this.RDS.executeStatement(this.Params).promise(); - const listOfColumns = response['records']; - let columnDescriptions = []; - for (const column of listOfColumns) { - let colDescription = new ColumnDescription(); - - colDescription.Field = column[MYSQL_DESCRIBE_TABLE_ORDER.Field]['stringValue']; - colDescription.Type = column[MYSQL_DESCRIBE_TABLE_ORDER.Type]['stringValue']; - colDescription.Null = column[MYSQL_DESCRIBE_TABLE_ORDER.Null]['stringValue']; - colDescription.Key = column[MYSQL_DESCRIBE_TABLE_ORDER.Key]['stringValue']; - colDescription.Default = column[MYSQL_DESCRIBE_TABLE_ORDER.Default]['stringValue']; - colDescription.Extra = column[MYSQL_DESCRIBE_TABLE_ORDER.Extra]['stringValue']; - - columnDescriptions.push(colDescription); - } - - return columnDescriptions; - }; - - /** - * Gets foreign keys for the given table, if any exist. - * - * @param tableName the name of the table to be checked. - * @return a list of tables referencing the provided table, if any exist. - */ - public getTableForeignKeyReferences = async (tableName: string) => { - this.Params.sql = `SELECT TABLE_NAME FROM information_schema.key_column_usage - WHERE referenced_table_name is not null - AND REFERENCED_TABLE_NAME = '${tableName}';`; - const response = await this.RDS.executeStatement(this.Params).promise(); - - let tableList = []; - const records = response['records']; - for (const record of records) { - tableList.push(record[0]['stringValue']); - } - - return tableList; - }; -} - -export class DataApiParams { - database: string; - - secretArn: string; - - resourceArn: string; - - sql: string; -} - -export class ColumnDescription { - Field: string; - - Type: string; - - Null: string; - - Key: string; - - Default: string; - - Extra: string; -} - -enum MYSQL_DESCRIBE_TABLE_ORDER { - Field, - Type, - Null, - Key, - Default, - Extra, -} diff --git a/packages/graphql-relational-schema-transformer/src/AuroraServerlessMySQLDatabaseReader.ts b/packages/graphql-relational-schema-transformer/src/AuroraServerlessMySQLDatabaseReader.ts deleted file mode 100644 index 9fa246f718..0000000000 --- a/packages/graphql-relational-schema-transformer/src/AuroraServerlessMySQLDatabaseReader.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { toUpper } from 'graphql-transformer-common'; -import { TemplateContext, TableContext } from './RelationalDBSchemaTransformer'; -import { - getNamedType, - getNonNullType, - getInputValueDefinition, - getGraphQLTypeFromMySQLType, - getTypeDefinition, - getFieldDefinition, - getInputTypeDefinition, -} from './RelationalDBSchemaTransformerUtils'; -import { AuroraDataAPIClient } from './AuroraDataAPIClient'; -import { IRelationalDBReader } from './IRelationalDBReader'; - -/** - * A class to manage interactions with a Aurora Serverless MySQL Relational Databse - * using the Aurora Data API. - */ -export class AuroraServerlessMySQLDatabaseReader implements IRelationalDBReader { - auroraClient: AuroraDataAPIClient; - - dbRegion: string; - - awsSecretStoreArn: string; - - dbClusterOrInstanceArn: string; - - database: string; - - setAuroraClient(auroraClient: AuroraDataAPIClient) { - this.auroraClient = auroraClient; - } - - constructor(dbRegion: string, awsSecretStoreArn: string, dbClusterOrInstanceArn: string, database: string, aws: any) { - this.auroraClient = new AuroraDataAPIClient(dbRegion, awsSecretStoreArn, dbClusterOrInstanceArn, database, aws); - this.dbRegion = dbRegion; - this.awsSecretStoreArn = awsSecretStoreArn; - this.dbClusterOrInstanceArn = dbClusterOrInstanceArn; - this.database = database; - } - - /** - * Stores some of the Aurora Serverless MySQL context into the template context, - * for later consumption. - * - * @param contextShell the basic template context, with db source independent fields set. - * @returns a fully hydrated template context, complete with Aurora Serverless MySQL context. - */ - hydrateTemplateContext = async (contextShell: TemplateContext): Promise => { - /** - * Information needed for creating the AppSync - RDS Data Source - * Store as part of the TemplateContext - */ - contextShell.secretStoreArn = this.awsSecretStoreArn; - contextShell.rdsClusterIdentifier = this.dbClusterOrInstanceArn; - contextShell.databaseSchema = 'mysql'; - contextShell.databaseName = this.database; - contextShell.region = this.dbRegion; - return contextShell; - }; - - /** - * Gets a list of all the table names in the provided database. - * - * @returns a list of tablenames inside the database. - */ - listTables = async (): Promise => { - const results = await this.auroraClient.listTables(); - return results; - }; - - /** - * Looks up any foreign key constraints that might exist for the provided table. - * This is done to ensure our generated schema includes nested types, where possible. - * - * @param tableName the name of the table to be checked for foreign key constraints. - * @returns a list of table names that are applicable as having constraints. - */ - getTableForeignKeyReferences = async (tableName: string): Promise => { - const results = await this.auroraClient.getTableForeignKeyReferences(tableName); - return results; - }; - - /** - * For the provided table, this will create a table context. That context holds definitions for - * the base table type, the create input type, and the update input type (e.g. Post, CreatePostInput, and UpdatePostInput, respectively), - * as well as the table primary key structure for proper operation definition. - * - * Create inputs will only differ from the base table type in that any nested types will not be present. Update table - * inputs will differ in that the only required field will be the primary key/identifier, as all fields don't have to - * be updated. Instead, it assumes the proper ones were provided on create. - * - * @param tableName the name of the table to be translated into a GraphQL type. - * @returns a promise of a table context structure. - */ - describeTable = async (tableName: string): Promise => { - const columnDescriptions = await this.auroraClient.describeTable(tableName); - // Fields in the general type (e.g. Post). Both the identifying field and any others the db dictates will be required. - const fields = new Array(); - // Fields in the update input type (e.g. UpdatePostInput). Only the identifying field will be required, any others will be optional. - const updateFields = new Array(); - // Field in the create input type (e.g. CreatePostInput). - const createFields = new Array(); - - // The primary key, used to help generate queries and mutations - let primaryKey = ''; - let primaryKeyType = ''; - - // Field Lists needed as context for auto-generating the Query Resolvers - const intFieldList = new Array(); - const stringFieldList = new Array(); - - const formattedTableName = toUpper(tableName); - - for (const columnDescription of columnDescriptions) { - // If a field is the primary key, save it. - if (columnDescription.Key == 'PRI') { - primaryKey = columnDescription.Field; - primaryKeyType = getGraphQLTypeFromMySQLType(columnDescription.Type); - } else { - /** - * If the field is not a key, then store it in the fields list. - * As we need this information later to generate query resolvers - * - * Currently we will only auto-gen query resolvers for the Int and String scalars - */ - const type = getGraphQLTypeFromMySQLType(columnDescription.Type); - if (type === 'Int') { - intFieldList.push(columnDescription.Field); - } else if (type === 'String') { - stringFieldList.push(columnDescription.Field); - } - } - - // Create the basic field type shape, to be consumed by every field definition - const baseType = getNamedType(getGraphQLTypeFromMySQLType(columnDescription.Type)); - - const isPrimaryKey = columnDescription.Key == 'PRI'; - const isNullable = columnDescription.Null == 'YES'; - - // Generate the field for the general type and the create input type - const type = !isPrimaryKey && isNullable ? baseType : getNonNullType(baseType); - fields.push(getFieldDefinition(columnDescription.Field, type)); - - createFields.push(getInputValueDefinition(type, columnDescription.Field)); - - // UpdateInput has only the primary key as required, ignoring all other that the database requests as non-nullable - const updateType = !isPrimaryKey ? baseType : getNonNullType(baseType); - updateFields.push(getInputValueDefinition(updateType, columnDescription.Field)); - } - - // Add foreign key for this table - - // NOTE from @mikeparisstuff: It would be great to re-enable this such that foreign key relationships are - // resolver automatically. This code was breaking compilation because it was not - // creating XConnection types correctly. This package also does not yet support - // wiring up the resolvers (or ideally selection set introspection & automatic JOINs) - // so there is not point in creating these connection fields anyway. Disabling until - // supported. - // let tablesWithRef = await this.getTableForeignKeyReferences(tableName) - // for (const tableWithRef of tablesWithRef) { - // if (tableWithRef && tableWithRef.length > 0) { - // const baseType = getNamedType(`${tableWithRef}Connection`) - // fields.push(getFieldDefinition(`${tableWithRef}`, baseType)) - // } - // } - - return new TableContext( - getTypeDefinition(fields, tableName), - getInputTypeDefinition(createFields, `Create${formattedTableName}Input`), - getInputTypeDefinition(updateFields, `Update${formattedTableName}Input`), - primaryKey, - primaryKeyType, - stringFieldList, - intFieldList, - ); - }; -} diff --git a/packages/graphql-relational-schema-transformer/src/IRelationalDBReader.ts b/packages/graphql-relational-schema-transformer/src/IRelationalDBReader.ts deleted file mode 100644 index 2395b29142..0000000000 --- a/packages/graphql-relational-schema-transformer/src/IRelationalDBReader.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { TemplateContext, TableContext } from './RelationalDBSchemaTransformer'; - -/** - * An interface to manage interactions with a relational database across - * various forms of clients. - */ -export interface IRelationalDBReader { - listTables(): Promise; - - getTableForeignKeyReferences(tableName: string): Promise; - - describeTable(tableName: string): Promise; - - hydrateTemplateContext(contextShell: TemplateContext): Promise; -} diff --git a/packages/graphql-relational-schema-transformer/src/RelationalDBMappingTemplate.ts b/packages/graphql-relational-schema-transformer/src/RelationalDBMappingTemplate.ts deleted file mode 100644 index f76f74ff0b..0000000000 --- a/packages/graphql-relational-schema-transformer/src/RelationalDBMappingTemplate.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { obj, str, ObjectNode, ListNode, ref, methodCall } from 'graphql-mapping-template'; - -/** - * The class that contains the resolver templates for interacting - * with the Relational Database data source. - */ -export class RelationalDBMappingTemplate { - /** - * Provided a SQL statement, creates the rds-query item resolver template. - * - * @param param0 - the SQL statement to use when querying the RDS cluster - */ - public static rdsQuery({ statements, variableMapRefName }: { statements: ListNode; variableMapRefName?: string }): ObjectNode { - return obj({ - version: str('2018-05-29'), - statements: statements, - variableMap: variableMapRefName ? methodCall(ref('util.toJson'), ref(variableMapRefName)) : obj({}), - }); - } -} diff --git a/packages/graphql-relational-schema-transformer/src/RelationalDBParsingException.ts b/packages/graphql-relational-schema-transformer/src/RelationalDBParsingException.ts deleted file mode 100644 index fd4d716a39..0000000000 --- a/packages/graphql-relational-schema-transformer/src/RelationalDBParsingException.ts +++ /dev/null @@ -1,8 +0,0 @@ -export class RelationalDBParsingException extends Error { - constructor(message: string, stack?: string) { - super(message); - - Object.setPrototypeOf(this, RelationalDBParsingException.prototype); - this.stack = stack; - } -} diff --git a/packages/graphql-relational-schema-transformer/src/RelationalDBResolverGenerator.ts b/packages/graphql-relational-schema-transformer/src/RelationalDBResolverGenerator.ts deleted file mode 100644 index 2ec4c16f89..0000000000 --- a/packages/graphql-relational-schema-transformer/src/RelationalDBResolverGenerator.ts +++ /dev/null @@ -1,507 +0,0 @@ -import * as fs from 'fs-extra'; - -import { - compoundExpression, - forEach, - iff, - list, - methodCall, - obj, - print, - ref, - ret, - set, - str, - ReferenceNode, - StringNode, -} from 'graphql-mapping-template'; -import { graphqlName, plurality, toUpper } from 'graphql-transformer-common'; - -import AppSync from 'cloudform-types/types/appSync'; -import { DocumentNode } from 'graphql'; -import { Fn } from 'cloudform-types'; -import { RelationalDBMappingTemplate } from './RelationalDBMappingTemplate'; -import { ResourceConstants } from './ResourceConstants'; -import { TemplateContext } from './RelationalDBSchemaTransformer'; - -const s3BaseUrl = 's3://${S3DeploymentBucket}/${S3DeploymentRootKey}/resolvers/${ResolverFileName}'; -const resolverFileName = 'ResolverFileName'; - -const rdsResponseErrorMessage = 'Invalid response from RDS DataSource. See info for the full response.'; -const rdsResponseErrorType = 'InvalidResponse'; -/** - * This Class is responsible for Generating the RDS Resolvers based on the - * GraphQL Schema + Metadata of the RDS Cluster (i.e. Primary Keys for Tables). - * - * It will generate the CRUDL+Q (Create, Retrieve, Update, Delete, List + Queries) Resolvers as - * Cloudform Resources so that they may be added on to the base template that the - * RelationDBTemplateGenerator creates. - */ -export class RelationalDBResolverGenerator { - document: DocumentNode; - - typePrimaryKeyMap: Map; - - stringFieldMap: Map; - - intFieldMap: Map; - - resolverFilePath: string; - - typePrimaryKeyTypeMap: Map; - - variableMapRefName: string; - - constructor(context: TemplateContext) { - this.document = context.schemaDoc; - this.typePrimaryKeyMap = context.typePrimaryKeyMap; - this.stringFieldMap = context.stringFieldMap; - this.intFieldMap = context.intFieldMap; - this.typePrimaryKeyTypeMap = context.typePrimaryKeyTypeMap; - this.variableMapRefName = 'variableMap'; - } - - /** - * Creates the CRUDL+Q Resolvers as a Map of Cloudform Resources. The output can then be - * merged with an existing Template's map of Resources. - */ - public createRelationalResolvers(resolverFilePath: string, improvePluralization: boolean) { - let resources = {}; - this.resolverFilePath = resolverFilePath; - this.typePrimaryKeyMap.forEach((value: string, key: string) => { - const resourceName = key.replace(/[^A-Za-z0-9]/g, ''); - resources = { - ...resources, - ...{ [resourceName + 'CreateResolver']: this.makeCreateRelationalResolver(key) }, - ...{ [resourceName + 'GetResolver']: this.makeGetRelationalResolver(key) }, - ...{ [resourceName + 'UpdateResolver']: this.makeUpdateRelationalResolver(key) }, - ...{ [resourceName + 'DeleteResolver']: this.makeDeleteRelationalResolver(key) }, - ...{ [resourceName + 'ListResolver']: this.makeListRelationalResolver(key, improvePluralization) }, - }; - // TODO: Add Guesstimate Query Resolvers - }); - - return resources; - } - - /** - * Private Helpers to Generate the CFN Spec for the Resolver Resources - */ - - /** - * Creates and returns the CFN Spec for the 'Create' Resolver Resource provided - * a GraphQL Type as the input - * - * @param type - the graphql type for which the create resolver will be created - * @param mutationTypeName - will be 'Mutation' - */ - private makeCreateRelationalResolver(type: string, mutationTypeName: string = 'Mutation') { - const tableName = this.getTableName(type); - const operationType = GRAPHQL_RESOLVER_OPERATION.Create; - const fieldName = this.getFieldName(type, operationType); - const createSql = this.generateInsertStatement(type); - const selectSql = this.generateSelectByPrimaryKeyStatement(type, operationType); - const reqFileName = `${mutationTypeName}.${fieldName}.req.vtl`; - const resFileName = `${mutationTypeName}.${fieldName}.res.vtl`; - - const reqTemplate = print( - compoundExpression([ - set(ref('cols'), list([])), - set(ref('vals'), list([])), - set(ref(this.variableMapRefName), obj({})), - forEach(ref('entry'), ref(`ctx.args.create${tableName}Input.keySet()`), [ - set(ref('discard'), ref(`cols.add($entry)`)), - set(ref('discard'), ref(`vals.add(":$entry")`)), - methodCall( - ref('util.qr'), - methodCall(ref(`${this.variableMapRefName}.put`), str(':$entry'), ref(`ctx.args.create${tableName}Input[$entry]`)), - ), - ]), - set(ref('valStr'), ref('vals.toString().replace("[","(").replace("]",")")')), - set(ref('colStr'), ref('cols.toString().replace("[","(").replace("]",")")')), - RelationalDBMappingTemplate.rdsQuery({ - statements: list([str(createSql), str(selectSql)]), - variableMapRefName: this.variableMapRefName, - }), - ]), - ); - - const resTemplate = print(ref('utils.toJson($utils.parseJson($utils.rds.toJsonString($ctx.result))[1][0])')); - - fs.writeFileSync(`${this.resolverFilePath}/${reqFileName}`, reqTemplate, 'utf8'); - fs.writeFileSync(`${this.resolverFilePath}/${resFileName}`, resTemplate, 'utf8'); - - let resolver = new AppSync.Resolver({ - ApiId: Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), - DataSourceName: Fn.GetAtt(ResourceConstants.RESOURCES.RelationalDatabaseDataSource, 'Name'), - TypeName: mutationTypeName, - FieldName: fieldName, - RequestMappingTemplateS3Location: Fn.Sub(s3BaseUrl, { - [ResourceConstants.PARAMETERS.S3DeploymentBucket]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentBucket), - [ResourceConstants.PARAMETERS.S3DeploymentRootKey]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentRootKey), - [resolverFileName]: reqFileName, - }), - ResponseMappingTemplateS3Location: Fn.Sub(s3BaseUrl, { - [ResourceConstants.PARAMETERS.S3DeploymentBucket]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentBucket), - [ResourceConstants.PARAMETERS.S3DeploymentRootKey]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentRootKey), - [resolverFileName]: resFileName, - }), - }).dependsOn([ResourceConstants.RESOURCES.RelationalDatabaseDataSource]); - return resolver; - } - - /** - * Creates and Returns the CFN Spec for the 'Get' Resolver Resource provided - * a GraphQL type - * - * @param type - the graphql type for which the get resolver will be created - * @param queryTypeName - will be 'Query' - */ - private makeGetRelationalResolver(type: string, queryTypeName: string = 'Query') { - const operationType = GRAPHQL_RESOLVER_OPERATION.Get; - const fieldName = this.getFieldName(type, operationType); - const selectSql = this.generateSelectByPrimaryKeyStatement(type, operationType); - const reqFileName = `${queryTypeName}.${fieldName}.req.vtl`; - const resFileName = `${queryTypeName}.${fieldName}.res.vtl`; - const primaryKey = this.getTablePrimaryKey(type); - const primaryKeyRef = this.getPrimaryKeyRef(type, operationType); - - const reqTemplate = print( - compoundExpression([ - set(ref(this.variableMapRefName), obj({})), - methodCall(ref('util.qr'), methodCall(ref(`${this.variableMapRefName}.put`), str(`:${primaryKey}`), primaryKeyRef)), - RelationalDBMappingTemplate.rdsQuery({ - statements: list([str(selectSql)]), - variableMapRefName: this.variableMapRefName, - }), - ]), - ); - const resTemplate: string = print( - compoundExpression([ - set(ref('output'), ref('utils.rds.toJsonObject($ctx.result)')), - iff( - ref('output.isEmpty()'), - methodCall(ref('util.error'), str(rdsResponseErrorMessage), str(rdsResponseErrorType), obj({}), ref('output')), - ), - set(ref('output'), ref('output[0]')), - iff(ref('output.isEmpty()'), ret()), - methodCall(ref('utils.toJson'), ref('output[0]')), - ]), - ); - - fs.writeFileSync(`${this.resolverFilePath}/${reqFileName}`, reqTemplate, 'utf8'); - fs.writeFileSync(`${this.resolverFilePath}/${resFileName}`, resTemplate, 'utf8'); - - let resolver = new AppSync.Resolver({ - ApiId: Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), - DataSourceName: Fn.GetAtt(ResourceConstants.RESOURCES.RelationalDatabaseDataSource, 'Name'), - FieldName: fieldName, - TypeName: queryTypeName, - RequestMappingTemplateS3Location: Fn.Sub(s3BaseUrl, { - [ResourceConstants.PARAMETERS.S3DeploymentBucket]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentBucket), - [ResourceConstants.PARAMETERS.S3DeploymentRootKey]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentRootKey), - [resolverFileName]: reqFileName, - }), - ResponseMappingTemplateS3Location: Fn.Sub(s3BaseUrl, { - [ResourceConstants.PARAMETERS.S3DeploymentBucket]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentBucket), - [ResourceConstants.PARAMETERS.S3DeploymentRootKey]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentRootKey), - [resolverFileName]: resFileName, - }), - }).dependsOn([ResourceConstants.RESOURCES.RelationalDatabaseDataSource]); - return resolver; - } - - /** - * Creates and Returns the CFN Spec for the 'Update' Resolver Resource provided - * a GraphQL type - * - * @param type - the graphql type for which the update resolver will be created - * @param mutationTypeName - will be 'Mutation' - */ - private makeUpdateRelationalResolver(type: string, mutationTypeName: string = 'Mutation') { - const tableName = this.getTableName(type); - const operationType = GRAPHQL_RESOLVER_OPERATION.Update; - const fieldName = this.getFieldName(type, operationType); - const updateSql = this.generateUpdateStatement(type); - const selectSql = this.generateSelectByPrimaryKeyStatement(type, operationType); - const reqFileName = `${mutationTypeName}.${fieldName}.req.vtl`; - const resFileName = `${mutationTypeName}.${fieldName}.res.vtl`; - - const reqTemplate = print( - compoundExpression([ - set(ref('updateList'), obj({})), - set(ref(this.variableMapRefName), obj({})), - forEach(ref('entry'), ref(`ctx.args.update${tableName}Input.keySet()`), [ - methodCall( - ref('util.qr'), - methodCall(ref(`${this.variableMapRefName}.put`), str(':$entry'), ref(`ctx.args.update${tableName}Input[$entry]`)), - ), - set(ref('discard'), ref(`updateList.put($entry, ":$entry")`)), - ]), - set(ref('update'), ref(`updateList.toString().replace("{","").replace("}","")`)), - RelationalDBMappingTemplate.rdsQuery({ - statements: list([str(updateSql), str(selectSql)]), - variableMapRefName: this.variableMapRefName, - }), - ]), - ); - - const resTemplate: string = print( - compoundExpression([ - set(ref('output'), ref('utils.rds.toJsonObject($ctx.result)')), - iff( - ref('output.length() < 2'), - methodCall(ref('util.error'), str(rdsResponseErrorMessage), str(rdsResponseErrorType), obj({}), ref('output')), - ), - set(ref('output'), ref('output[1]')), - iff(ref('output.isEmpty()'), ret()), - methodCall(ref('utils.toJson'), ref('output[0]')), - ]), - ); - - fs.writeFileSync(`${this.resolverFilePath}/${reqFileName}`, reqTemplate, 'utf8'); - fs.writeFileSync(`${this.resolverFilePath}/${resFileName}`, resTemplate, 'utf8'); - - let resolver = new AppSync.Resolver({ - ApiId: Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), - DataSourceName: Fn.GetAtt(ResourceConstants.RESOURCES.RelationalDatabaseDataSource, 'Name'), - TypeName: mutationTypeName, - FieldName: fieldName, - RequestMappingTemplateS3Location: Fn.Sub(s3BaseUrl, { - [ResourceConstants.PARAMETERS.S3DeploymentBucket]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentBucket), - [ResourceConstants.PARAMETERS.S3DeploymentRootKey]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentRootKey), - [resolverFileName]: reqFileName, - }), - ResponseMappingTemplateS3Location: Fn.Sub(s3BaseUrl, { - [ResourceConstants.PARAMETERS.S3DeploymentBucket]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentBucket), - [ResourceConstants.PARAMETERS.S3DeploymentRootKey]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentRootKey), - [resolverFileName]: resFileName, - }), - }).dependsOn([ResourceConstants.RESOURCES.RelationalDatabaseDataSource]); - return resolver; - } - - /** - * Creates and Returns the CFN Spec for the 'Delete' Resolver Resource provided - * a GraphQL type - * - * @param type - the graphql type for which the delete resolver will be created - * @param mutationTypeName - will be 'Mutation' - */ - private makeDeleteRelationalResolver(type: string, mutationTypeName: string = 'Mutation') { - const operationType = GRAPHQL_RESOLVER_OPERATION.Delete; - const fieldName = this.getFieldName(type, operationType); - const selectSql = this.generateSelectByPrimaryKeyStatement(type, operationType); - const deleteSql = this.generateDeleteStatement(type); - const reqFileName = `${mutationTypeName}.${fieldName}.req.vtl`; - const resFileName = `${mutationTypeName}.${fieldName}.res.vtl`; - const primaryKey = this.getTablePrimaryKey(type); - const primaryKeyRef = this.getPrimaryKeyRef(type, operationType); - - const reqTemplate = print( - compoundExpression([ - set(ref(this.variableMapRefName), obj({})), - methodCall(ref('util.qr'), methodCall(ref(`${this.variableMapRefName}.put`), str(`:${primaryKey}`), primaryKeyRef)), - RelationalDBMappingTemplate.rdsQuery({ - statements: list([str(selectSql), str(deleteSql)]), - variableMapRefName: this.variableMapRefName, - }), - ]), - ); - const resTemplate: string = print( - compoundExpression([ - set(ref('output'), ref('utils.rds.toJsonObject($ctx.result)')), - iff( - ref('output.isEmpty()'), - methodCall(ref('util.error'), str(rdsResponseErrorMessage), str(rdsResponseErrorType), obj({}), ref('output')), - ), - set(ref('output'), ref('output[0]')), - iff(ref('output.isEmpty()'), ret()), - methodCall(ref('utils.toJson'), ref('output[0]')), - ]), - ); - - fs.writeFileSync(`${this.resolverFilePath}/${reqFileName}`, reqTemplate, 'utf8'); - fs.writeFileSync(`${this.resolverFilePath}/${resFileName}`, resTemplate, 'utf8'); - - let resolver = new AppSync.Resolver({ - ApiId: Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), - DataSourceName: Fn.GetAtt(ResourceConstants.RESOURCES.RelationalDatabaseDataSource, 'Name'), - TypeName: mutationTypeName, - FieldName: fieldName, - RequestMappingTemplateS3Location: Fn.Sub(s3BaseUrl, { - [ResourceConstants.PARAMETERS.S3DeploymentBucket]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentBucket), - [ResourceConstants.PARAMETERS.S3DeploymentRootKey]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentRootKey), - [resolverFileName]: reqFileName, - }), - ResponseMappingTemplateS3Location: Fn.Sub(s3BaseUrl, { - [ResourceConstants.PARAMETERS.S3DeploymentBucket]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentBucket), - [ResourceConstants.PARAMETERS.S3DeploymentRootKey]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentRootKey), - [resolverFileName]: resFileName, - }), - }).dependsOn([ResourceConstants.RESOURCES.RelationalDatabaseDataSource]); - - return resolver; - } - - /** - * Creates and Returns the CFN Spec for the 'List' Resolver Resource provided - * a GraphQL type - * - * @param type - the graphql type for which the list resolver will be created - * @param queryTypeName - will be 'Query' - */ - private makeListRelationalResolver(type: string, improvePluralization: boolean, queryTypeName: string = 'Query') { - const fieldName = graphqlName(GRAPHQL_RESOLVER_OPERATION.List + plurality(toUpper(type), improvePluralization)); - const selectSql = this.generateSelectStatement(type); - const reqFileName = `${queryTypeName}.${fieldName}.req.vtl`; - const resFileName = `${queryTypeName}.${fieldName}.res.vtl`; - const reqTemplate = print( - RelationalDBMappingTemplate.rdsQuery({ - statements: list([str(selectSql)]), - }), - ); - const resTemplate = print(ref('utils.toJson($utils.rds.toJsonObject($ctx.result)[0])')); - - fs.writeFileSync(`${this.resolverFilePath}/${reqFileName}`, reqTemplate, 'utf8'); - fs.writeFileSync(`${this.resolverFilePath}/${resFileName}`, resTemplate, 'utf8'); - - let resolver = new AppSync.Resolver({ - ApiId: Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), - DataSourceName: Fn.GetAtt(ResourceConstants.RESOURCES.RelationalDatabaseDataSource, 'Name'), - TypeName: queryTypeName, - FieldName: fieldName, - RequestMappingTemplateS3Location: Fn.Sub(s3BaseUrl, { - [ResourceConstants.PARAMETERS.S3DeploymentBucket]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentBucket), - [ResourceConstants.PARAMETERS.S3DeploymentRootKey]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentRootKey), - [resolverFileName]: reqFileName, - }), - ResponseMappingTemplateS3Location: Fn.Sub(s3BaseUrl, { - [ResourceConstants.PARAMETERS.S3DeploymentBucket]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentBucket), - [ResourceConstants.PARAMETERS.S3DeploymentRootKey]: Fn.Ref(ResourceConstants.PARAMETERS.S3DeploymentRootKey), - [resolverFileName]: resFileName, - }), - }).dependsOn([ResourceConstants.RESOURCES.RelationalDatabaseDataSource]); - - return resolver; - } - - /** - * Generate the table name to use on sql statements - * - * @param type - the graphql type to infer the table name - * @returns string with the table name - */ - private getTableName(type: string): string { - return toUpper(type); - } - - /** - * Using the CRUDL+Q and the graphql type generate the graphql operation name - * - * @param type - the graphql type to infer the table name - * @param operationType The CRUDL+Q (Create, Retrieve, Update, Delete, List + Queries) operation name - * - * @returns string with the graphql operation name - */ - private getFieldName(type: string, operationType: GRAPHQL_RESOLVER_OPERATION): string { - const tableName = this.getTableName(type); - return graphqlName(`${operationType}${tableName}`); - } - - /** - * Generate the primary key column name to use on sql statements - * - * @param type - the graphql type to get the primary key - * @returns string with the table name - */ - private getTablePrimaryKey(type: string): string { - return this.typePrimaryKeyMap.get(type); - } - - /** - * Check if the type of the primary key is string to apply different transformation on sql statements - * - * @param type - the graphql type to check - * @returns boolean true if the primary key is a string type, otherwise false - */ - private isPrimaryKeyAStringType(type: string): boolean { - return this.typePrimaryKeyTypeMap.get(type).includes('String'); - } - - /** - * Generate the select sql statement to retrieve all rows - * - * @param type - the graphql type - * @returns string with the sql statement - */ - private generateSelectStatement(type: string): string { - const tableName = this.getTableName(type); - return `SELECT * FROM ${tableName}`; - } - - /** - * Generate the select sql statement filter by the primary key - * - * @param type - the graphql type - * @param operationType The CRUDL+Q (Create, Retrieve, Update, Delete, List + Queries) operation name - * @returns string with the sql statement - */ - private generateSelectByPrimaryKeyStatement(type: string, operationType: GRAPHQL_RESOLVER_OPERATION): string { - const tableName = this.getTableName(type); - const primaryKey = this.getTablePrimaryKey(type); - return `SELECT * FROM ${tableName} WHERE ${primaryKey}=:${primaryKey}`; - } - - private getPrimaryKeyRef(type: string, operationType: GRAPHQL_RESOLVER_OPERATION): ReferenceNode | StringNode { - const tableName = this.getTableName(type); - const primaryKey = this.getTablePrimaryKey(type); - const hasToAppendOperationInput = ![GRAPHQL_RESOLVER_OPERATION.Get, GRAPHQL_RESOLVER_OPERATION.Delete].includes(operationType); - const operationInput = hasToAppendOperationInput ? `${operationType}${tableName}Input.` : ''; - if (this.isPrimaryKeyAStringType(type)) { - return str(`$ctx.args.${operationInput}${primaryKey}`); - } - return ref(`ctx.args.${operationInput}${primaryKey}`); - } - - /** - * Generate the insert sql statement - * - * @param type - the graphql type - * @returns string with the sql statement - */ - private generateInsertStatement(type: string): string { - const tableName = this.getTableName(type); - return `INSERT INTO ${tableName} $colStr VALUES $valStr`; - } - - /** - * Generate the update sql statement - * - * @param type - the graphql type - * @returns string with the sql statement - */ - private generateUpdateStatement(type: string): string { - const primaryKey = this.getTablePrimaryKey(type); - return `UPDATE ${type} SET $update WHERE ${primaryKey}=:${primaryKey}`; - } - - /** - * Generate the delete sql statement - * - * @param type - the graphql type - * @returns string with the sql statement - */ - private generateDeleteStatement(type: string): string { - const primaryKey = this.getTablePrimaryKey(type); - return `DELETE FROM ${type} WHERE ${primaryKey}=:${primaryKey}`; - } -} - -enum GRAPHQL_RESOLVER_OPERATION { - Create = 'create', - Delete = 'delete', - Get = 'get', - List = 'list', - Update = 'update', -} diff --git a/packages/graphql-relational-schema-transformer/src/RelationalDBSchemaTransformer.ts b/packages/graphql-relational-schema-transformer/src/RelationalDBSchemaTransformer.ts deleted file mode 100644 index 6f1f740890..0000000000 --- a/packages/graphql-relational-schema-transformer/src/RelationalDBSchemaTransformer.ts +++ /dev/null @@ -1,314 +0,0 @@ -import { Kind, ObjectTypeDefinitionNode, SchemaDefinitionNode, InputObjectTypeDefinitionNode, DocumentNode } from 'graphql'; -import { plurality, toUpper } from 'graphql-transformer-common'; -import { - getSingletonListTypeNode, - getNamedType, - getOperationFieldDefinition, - getNonNullType, - getInputValueDefinition, - getTypeDefinition, - getFieldDefinition, - getDirectiveNode, - getOperationTypeDefinition, -} from './RelationalDBSchemaTransformerUtils'; -import { RelationalDBParsingException } from './RelationalDBParsingException'; -import { IRelationalDBReader } from './IRelationalDBReader'; - -/** - * This class is used to transition all of the columns and key metadata from a table for use - * in generating appropriate GraphQL schema structures. It will track type definitions for - * the base table, update mutation inputs, create mutation inputs, and primary key metadata. - */ -export class TableContext { - tableTypeDefinition: ObjectTypeDefinitionNode; - - createTypeDefinition: InputObjectTypeDefinitionNode; - - updateTypeDefinition: InputObjectTypeDefinitionNode; - - // Table primary key metadata, to help properly key queries and mutations. - tableKeyField: string; - - tableKeyFieldType: string; - - stringFieldList: string[]; - - intFieldList: string[]; - - constructor( - typeDefinition: ObjectTypeDefinitionNode, - createDefinition: InputObjectTypeDefinitionNode, - updateDefinition: InputObjectTypeDefinitionNode, - primaryKeyField: string, - primaryKeyType: string, - stringFieldList: string[], - intFieldList: string[], - ) { - this.tableTypeDefinition = typeDefinition; - this.tableKeyField = primaryKeyField; - this.createTypeDefinition = createDefinition; - this.updateTypeDefinition = updateDefinition; - this.tableKeyFieldType = primaryKeyType; - this.stringFieldList = stringFieldList; - this.intFieldList = intFieldList; - } -} - -/** - * This class is used to transition all of the information needed to generate the - * CloudFormation template. This is the class that is outputted by the SchemaTransformer and the one that - * RelationalDBTemplateGenerator takes in for the constructor. It tracks the graphql schema document, - * map of the primary keys for each of the types. It is also being used to track the CLI inputs needed - * for DataSource Creation, as data source creation is apart of the cfn template generation. - */ -export class TemplateContext { - schemaDoc: DocumentNode; - - typePrimaryKeyMap: Map; - - typePrimaryKeyTypeMap: Map; - - stringFieldMap: Map; - - intFieldMap: Map; - - secretStoreArn: string; - - rdsClusterIdentifier: string; - - databaseName: string; - - databaseSchema: string; - - region: string; - - constructor( - schemaDoc: DocumentNode, - typePrimaryKeyMap: Map, - stringFieldMap: Map, - intFieldMap: Map, - typePrimaryKeyTypeMap?: Map, - ) { - this.schemaDoc = schemaDoc; - this.typePrimaryKeyMap = typePrimaryKeyMap; - this.stringFieldMap = stringFieldMap; - this.intFieldMap = intFieldMap; - this.typePrimaryKeyTypeMap = typePrimaryKeyTypeMap; - } -} - -export class RelationalDBSchemaTransformer { - dbReader: IRelationalDBReader; - - database: string; - - improvePluralization: boolean; - - constructor(dbReader: IRelationalDBReader, database: string, improvePluralization: boolean) { - this.dbReader = dbReader; - this.database = database; - this.improvePluralization = improvePluralization; - } - - public introspectDatabaseSchema = async (): Promise => { - // Get all of the tables within the provided db - let tableNames = null; - - try { - tableNames = await this.dbReader.listTables(); - } catch (err) { - throw new RelationalDBParsingException(`Failed to list tables in ${this.database}`, err.stack); - } - - // Return early if there are no tables in the database - if (tableNames.length === 0) { - return null; - } - - const typeContexts = new Array(); - const types = new Array(); - const pkeyMap = new Map(); - const pkeyTypeMap = new Map(); - const stringFieldMap = new Map(); - const intFieldMap = new Map(); - - for (const tableName of tableNames) { - let type: TableContext = null; - - try { - type = await this.dbReader.describeTable(tableName); - } catch (err) { - throw new RelationalDBParsingException(`Failed to describe table ${tableName}`, err.stack); - } - - // NOTE from @mikeparisstuff. The GraphQL schema generation breaks - // when the table does not have an explicit primary key. - if (type.tableKeyField) { - typeContexts.push(type); - // Generate the 'connection' type for each table type definition - // TODO: Determine if Connection is needed as Data API doesn't provide pagination - // TODO: As we add different db sources, we should conditionally do this even if we don't for Aurora serverless. - // types.push(this.getConnectionType(tableName)) - // Generate the create operation input for each table type definition - types.push(type.createTypeDefinition); - // Generate the default shape for the table's structure - types.push(type.tableTypeDefinition); - // Generate the update operation input for each table type definition - types.push(type.updateTypeDefinition); - - // Update the field map with the new field lists for the current table - stringFieldMap.set(tableName, type.stringFieldList); - intFieldMap.set(tableName, type.intFieldList); - pkeyMap.set(tableName, type.tableKeyField); - pkeyTypeMap.set(tableName, type.tableKeyFieldType); - } else { - console.warn(`Skipping table ${type.tableTypeDefinition.name.value} because it does not have a single PRIMARY KEY.`); - } - } - - if (typeContexts.length > 0) { - // Generate the mutations and queries based on the table structures - types.push(this.getMutations(typeContexts)); - types.push(this.getQueries(typeContexts)); - types.push(this.getSubscriptions(typeContexts)); - types.push(this.getSchemaType()); - } - - let context = this.dbReader.hydrateTemplateContext( - new TemplateContext({ kind: Kind.DOCUMENT, definitions: types }, pkeyMap, stringFieldMap, intFieldMap, pkeyTypeMap), - ); - - return context; - }; - - /** - * Creates a schema type definition node, including operations for each of query, mutation, and subscriptions. - * - * @returns a basic schema definition node. - */ - getSchemaType(): SchemaDefinitionNode { - return { - kind: Kind.SCHEMA_DEFINITION, - directives: [], - operationTypes: [ - getOperationTypeDefinition('query', getNamedType('Query')), - getOperationTypeDefinition('mutation', getNamedType('Mutation')), - getOperationTypeDefinition('subscription', getNamedType('Subscription')), - ], - }; - } - - /** - * Generates the basic mutation operations, given the provided table contexts. This will - * create a create, delete, and update operation for each table. - * - * @param types the table contexts from which the mutations are to be generated. - * @returns the type definition for mutations, including a create, delete, and update for each table. - */ - private getMutations(types: TableContext[]): ObjectTypeDefinitionNode { - const fields = []; - - for (const typeContext of types) { - const type = typeContext.tableTypeDefinition; - const formattedTypeValue = toUpper(type.name.value); - - fields.push( - getOperationFieldDefinition( - `delete${formattedTypeValue}`, - [getInputValueDefinition(getNonNullType(getNamedType(typeContext.tableKeyFieldType)), typeContext.tableKeyField)], - getNamedType(`${type.name.value}`), - null, - ), - ); - - fields.push( - getOperationFieldDefinition( - `create${formattedTypeValue}`, - [getInputValueDefinition(getNonNullType(getNamedType(`Create${formattedTypeValue}Input`)), `create${formattedTypeValue}Input`)], - getNamedType(`${type.name.value}`), - null, - ), - ); - - fields.push( - getOperationFieldDefinition( - `update${formattedTypeValue}`, - [getInputValueDefinition(getNonNullType(getNamedType(`Update${formattedTypeValue}Input`)), `update${formattedTypeValue}Input`)], - getNamedType(`${type.name.value}`), - null, - ), - ); - } - - return getTypeDefinition(fields, 'Mutation'); - } - - /** - * Generates the basic subscription operations, given the provided table contexts. This will - * create an onCreate subscription for each table. - * - * @param types the table contexts from which the subscriptions are to be generated. - * @returns the type definition for subscriptions, including an onCreate for each table. - */ - private getSubscriptions(types: TableContext[]): ObjectTypeDefinitionNode { - const fields = []; - - for (const typeContext of types) { - const type = typeContext.tableTypeDefinition; - const formattedTypeValue = toUpper(type.name.value); - - fields.push( - getOperationFieldDefinition(`onCreate${formattedTypeValue}`, [], getNamedType(`${type.name.value}`), [ - getDirectiveNode(`create${formattedTypeValue}`), - ]), - ); - } - - return getTypeDefinition(fields, 'Subscription'); - } - - /** - * Generates the basic query operations, given the provided table contexts. This will - * create a get and list operation for each table. - * - * @param types the table contexts from which the queries are to be generated. - * @returns the type definition for queries, including a get and list for each table. - */ - private getQueries(types: TableContext[]): ObjectTypeDefinitionNode { - const fields = []; - - for (const typeContext of types) { - const type = typeContext.tableTypeDefinition; - const formattedTypeValue = toUpper(type.name.value); - - fields.push( - getOperationFieldDefinition( - `get${formattedTypeValue}`, - [getInputValueDefinition(getNonNullType(getNamedType(typeContext.tableKeyFieldType)), typeContext.tableKeyField)], - getNamedType(`${type.name.value}`), - null, - ), - ); - - // use list type node to match the ast of current schema built by graphql.parse - const nameListType = getSingletonListTypeNode(type.name.value); - - fields.push(getOperationFieldDefinition(`list${plurality(formattedTypeValue, this.improvePluralization)}`, [], nameListType, null)); - } - - return getTypeDefinition(fields, 'Query'); - } - - /** - * Creates a GraphQL connection type for a given GraphQL type, corresponding to a SQL table name. - * - * @param tableName the name of the SQL table (and GraphQL type). - * @returns a type definition node defining the connection type for the provided type name. - */ - getConnectionType(tableName: string): ObjectTypeDefinitionNode { - return getTypeDefinition( - [getFieldDefinition('items', getNamedType(`[${tableName}]`)), getFieldDefinition('nextToken', getNamedType('String'))], - `${tableName}Connection`, - ); - } -} diff --git a/packages/graphql-relational-schema-transformer/src/RelationalDBSchemaTransformerUtils.ts b/packages/graphql-relational-schema-transformer/src/RelationalDBSchemaTransformerUtils.ts deleted file mode 100644 index d26cbe4e0e..0000000000 --- a/packages/graphql-relational-schema-transformer/src/RelationalDBSchemaTransformerUtils.ts +++ /dev/null @@ -1,276 +0,0 @@ -import { - Kind, - ObjectTypeDefinitionNode, - NonNullTypeNode, - DirectiveNode, - NameNode, - OperationTypeNode, - FieldDefinitionNode, - NamedTypeNode, - InputValueDefinitionNode, - ValueNode, - OperationTypeDefinitionNode, - ArgumentNode, - ListValueNode, - ListTypeNode, - StringValueNode, - InputObjectTypeDefinitionNode, -} from 'graphql'; - -const intTypes = [`INTEGER`, `INT`, `SMALLINT`, `TINYINT`, `MEDIUMINT`, `BIGINT`, `BIT`]; -const floatTypes = [`FLOAT`, `DOUBLE`, `REAL`, `REAL_AS_FLOAT`, `DOUBLE PRECISION`, `DEC`, `DECIMAL`, `FIXED`, `NUMERIC`]; - -/** - * Creates a non-null type, which is a node wrapped around another type that simply defines it is non-nullable. - * - * @param typeNode the type to be marked as non-nullable. - * @returns a non-null wrapper around the provided type. - */ -export function getNonNullType(typeNode: NamedTypeNode): NonNullTypeNode { - return { - kind: Kind.NON_NULL_TYPE, - type: typeNode, - }; -} - -/** - * Creates a named type for the schema. - * - * @param name the name of the type. - * @returns a named type with the provided name. - */ -export function getNamedType(name: string): NamedTypeNode { - return { - kind: Kind.NAMED_TYPE, - name: { - kind: Kind.NAME, - value: name, - }, - }; -} - -/** - * Creates an input value definition for the schema. - * - * @param typeNode the type of the input node. - * @param name the name of the input. - * @returns an input value definition node with the provided type and name. - */ -export function getInputValueDefinition(typeNode: NamedTypeNode | NonNullTypeNode, name: string): InputValueDefinitionNode { - return { - kind: Kind.INPUT_VALUE_DEFINITION, - name: { - kind: Kind.NAME, - value: name, - }, - type: typeNode, - directives: [], - }; -} - -/** - * Creates an operation field definition for the schema. - * - * @param name the name of the operation. - * @param args the arguments for the operation. - * @param type the type of the operation. - * @param directives the directives (if any) applied to this field. In this context, only subscriptions will have this. - * @returns an operation field definition with the provided name, args, type, and optionally directives. - */ -export function getOperationFieldDefinition( - name: string, - args: InputValueDefinitionNode[], - type: NamedTypeNode | ListTypeNode, - directives: ReadonlyArray, -): FieldDefinitionNode { - return { - kind: Kind.FIELD_DEFINITION, - name: { - kind: Kind.NAME, - value: name, - }, - arguments: args, - type: type, - directives: directives || [], - }; -} - -/** - * Creates a field definition node for the schema. - * - * @param fieldName the name of the field to be created. - * @param type the type of the field to be created. - * @returns a field definition node with the provided name and type. - */ -export function getFieldDefinition(fieldName: string, type: NonNullTypeNode | NamedTypeNode): FieldDefinitionNode { - return { - kind: Kind.FIELD_DEFINITION, - name: { - kind: Kind.NAME, - value: fieldName, - }, - type, - directives: [], - }; -} - -/** - * Creates a type definition node for the schema. - * - * @param fields the field set to be included in the type. - * @param typeName the name of the type. - * @returns a type definition node defined by the provided fields and name. - */ -export function getTypeDefinition(fields: ReadonlyArray, typeName: string): ObjectTypeDefinitionNode { - return { - kind: Kind.OBJECT_TYPE_DEFINITION, - name: { - kind: Kind.NAME, - value: typeName, - }, - fields: fields, - directives: [], - interfaces: [], - }; -} - -/** - * Creates an input type definition node for the schema. - * - * @param fields the fields in the input type. - * @param typeName the name of the input type - * @returns an input type definition node defined by the provided fields and - */ -export function getInputTypeDefinition(fields: ReadonlyArray, typeName: string): InputObjectTypeDefinitionNode { - return { - kind: Kind.INPUT_OBJECT_TYPE_DEFINITION, - name: { - kind: Kind.NAME, - value: typeName, - }, - fields: fields, - directives: [], - }; -} - -/** - * Creates a name node for the schema. - * - * @param name the name of the name node. - * @returns the name node defined by the provided name. - */ -export function getNameNode(name: string): NameNode { - return { - kind: Kind.NAME, - value: name, - }; -} -/** - * Create a singleton list type node for queries - * - * @param name the singleton named type for the list - * @return singleton ListTypeNode - */ -export function getSingletonListTypeNode(name: string): ListTypeNode { - return { - kind: Kind.LIST_TYPE, - type: getNamedType(name), - }; -} - -/** - * Creates a list value node for the schema. - * - * @param values the list of values to be in the list node. - * @returns a list value node containing the provided values. - */ -export function getListValueNode(values: ReadonlyArray): ListValueNode { - return { - kind: Kind.LIST, - values: values, - }; -} - -/** - * Creates a simple string value node for the schema. - * - * @param value the value to be set in the string value node. - * @returns a fleshed-out string value node. - */ -export function getStringValueNode(value: string): StringValueNode { - return { - kind: Kind.STRING, - value: value, - }; -} - -/** - * Creates a directive node for a subscription in the schema. - * - * @param mutationName the name of the mutation the subscription directive is for. - * @returns a directive node defining the subscription. - */ -export function getDirectiveNode(mutationName: string): DirectiveNode { - return { - kind: Kind.DIRECTIVE, - name: getNameNode('aws_subscribe'), - arguments: [getArgumentNode(mutationName)], - }; -} - -/** - * Creates an operation type definition (subscription, query, mutation) for the schema. - * - * @param operationType the type node defining the operation type. - * @param operation the named type node defining the operation type. - */ -export function getOperationTypeDefinition(operationType: OperationTypeNode, operation: NamedTypeNode): OperationTypeDefinitionNode { - return { - kind: Kind.OPERATION_TYPE_DEFINITION, - operation: operationType, - type: operation, - }; -} - -/** - * Creates an argument node for a subscription directive within the schema. - * - * @param argument the argument string. - * @returns the argument node. - */ -export function getArgumentNode(argument: string): ArgumentNode { - return { - kind: Kind.ARGUMENT, - name: getNameNode('mutations'), - value: getListValueNode([getStringValueNode(argument)]), - }; -} - -/** - * Given the DB type for a column, make a best effort to select the appropriate GraphQL type for - * the corresponding field. - * - * @param dbType the SQL column type. - * @returns the GraphQL field type. - */ -export function getGraphQLTypeFromMySQLType(dbType: string): string { - const normalizedType = dbType.toUpperCase().split('(')[0]; - if (normalizedType == `BOOL`) { - return `Boolean`; - } else if (normalizedType == `JSON`) { - return `AWSJSON`; - } else if (normalizedType == `TIME`) { - return `AWSTime`; - } else if (normalizedType == `DATE`) { - return `AWSDate`; - } else if (normalizedType == `DATETIME`) { - return `AWSDateTime`; - } else if (normalizedType == `TIMESTAMP`) { - return `AWSTimestamp`; - } else if (intTypes.indexOf(normalizedType) > -1) { - return `Int`; - } else if (floatTypes.indexOf(normalizedType) > -1) { - return `Float`; - } - return `String`; -} diff --git a/packages/graphql-relational-schema-transformer/src/RelationalDBTemplateGenerator.ts b/packages/graphql-relational-schema-transformer/src/RelationalDBTemplateGenerator.ts deleted file mode 100644 index 5dfa9644a4..0000000000 --- a/packages/graphql-relational-schema-transformer/src/RelationalDBTemplateGenerator.ts +++ /dev/null @@ -1,189 +0,0 @@ -import DataSource from 'cloudform-types/types/appSync/dataSource'; -import IAM from 'cloudform-types/types/iam'; -import { Fn, StringParameter } from 'cloudform-types'; -import Template from 'cloudform-types/types/template'; -import { TemplateContext } from './RelationalDBSchemaTransformer'; -import { RelationalDBResolverGenerator } from './RelationalDBResolverGenerator'; -import { ResourceConstants } from './ResourceConstants'; - -/** - * This is the Class responsible for generating and managing the CloudForm template - * provided a TemplateContext object, which is generated by the RelationalDBSchemaTransformer. - * - * It will generate the basic CloudForm template needed for getting the AppSync API and - * RDS DataSource provisioned. It also allows for adding the CRUDL+Q Resolvers upon need. - */ -export class RelationalDBTemplateGenerator { - context: TemplateContext; - - constructor(context: TemplateContext) { - this.context = context; - } - - /** - * Creates and returns the basic Cloudform template needed for setting - * up an AppSync API pointing at the RDS DataSource. - * - * @returns the created CloudFormation template. - */ - public createTemplate(context: any): Template { - const template = { - AWSTemplateFormatVersion: '2010-09-09', - Parameters: this.makeParameters(this.context.databaseName), - Resources: { - [ResourceConstants.RESOURCES.RelationalDatabaseDataSource]: this.makeRelationalDataSource(context), - [ResourceConstants.RESOURCES.RelationalDatabaseAccessRole]: this.makeIAMDataSourceRole(), - }, - }; - - return template; - } - - /** - * Provided a Cloudform Template, this method adds Resolver Resources to the - * Template. - * - * @param template - the Cloudform template - * @returns the given template, updated with new resolvers. - */ - public addRelationalResolvers(template: Template, resolverFilePath: string, improvePluralization: boolean): Template { - let resolverGenerator = new RelationalDBResolverGenerator(this.context); - template.Resources = { ...template.Resources, ...resolverGenerator.createRelationalResolvers(resolverFilePath, improvePluralization) }; - return template; - } - - /** - * Provided a Cloudform Template, this method returns the cfn json template as a string - * - * @param template - the Cloudform template - * @returns the json, string form of the template given. - */ - public printCloudformationTemplate(template: Template): string { - return JSON.stringify(template, undefined, 2); - } - - /* - * Private Helper Methods for Generating the Necessary CFN Specs for the CFN Template - */ - - /** - * Creates any Parmaters needed for the CFN Template - * - * @param databaseName - the name of the database being parsed. - * @returns the parameters for the template. - */ - private makeParameters(databaseName: string) { - return { - [ResourceConstants.PARAMETERS.AppSyncApiName]: new StringParameter({ - Description: `The name of the AppSync API generated from database ${databaseName}`, - Default: `AppSyncSimpleTransform`, - }), - [ResourceConstants.PARAMETERS.Env]: new StringParameter({ - Description: 'The environment name. e.g. Dev, Test, or Production', - Default: 'NONE', - }), - [ResourceConstants.PARAMETERS.S3DeploymentBucket]: new StringParameter({ - Description: 'The S3 bucket containing all deployment assets for the project.', - }), - [ResourceConstants.PARAMETERS.S3DeploymentRootKey]: new StringParameter({ - Description: 'An S3 key relative to the S3DeploymentBucket that points to the root of the deployment directory.', - }), - [ResourceConstants.PARAMETERS.AppSyncApiId]: new StringParameter({ - Description: 'The id of the AppSync API associated with this project.', - }), - [ResourceConstants.PARAMETERS.rdsRegion]: new StringParameter({ - Description: 'The region that the RDS Cluster is located in.', - }), - [ResourceConstants.PARAMETERS.rdsClusterIdentifier]: new StringParameter({ - Description: 'The ARN identifier denoting the RDS cluster.', - }), - [ResourceConstants.PARAMETERS.rdsSecretStoreArn]: new StringParameter({ - Description: 'The ARN for the Secret containing the access for the RDS cluster.', - }), - [ResourceConstants.PARAMETERS.rdsDatabaseName]: new StringParameter({ - Description: 'The name of the database within the RDS cluster to use.', - }), - }; - } - - /* - * Resources - */ - - /** - * Creates the IAM Role CFN Spec to allow AppSync to interact with the RDS cluster - * - * @returns the IAM role CloudFormation resource. - */ - private makeIAMDataSourceRole() { - return new IAM.Role({ - RoleName: Fn.Join('-', ['role', Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), Fn.Ref(ResourceConstants.PARAMETERS.Env)]), - - AssumeRolePolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Principal: { - Service: 'appsync.amazonaws.com', - }, - Action: 'sts:AssumeRole', - }, - ], - }, - Policies: [ - new IAM.Role.Policy({ - PolicyName: 'RelationalDatabaseAccessPolicy', - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Action: [ - 'rds-data:ExecuteSql', - 'rds-data:ExecuteStatement', - 'rds-data:DeleteItems', - 'rds-data:GetItems', - 'rds-data:InsertItems', - 'rds-data:UpdateItems', - ], - Resource: [Fn.Ref(ResourceConstants.PARAMETERS.rdsClusterIdentifier)], - }, - { - Effect: 'Allow', - Action: ['secretsmanager:GetSecretValue'], - Resource: [Fn.Ref(ResourceConstants.PARAMETERS.rdsSecretStoreArn)], - }, - ], - }, - }), - ], - }); - } - - /** - * Creates the AppSync DataSource CFN Spec pointing at the provided RDS Cluster - * - * @param cliContext - the Amplify context, used to load environment variables. - * @returns the data source CloudFormation resource. - */ - private makeRelationalDataSource(cliContext: any): DataSource { - return new DataSource({ - Type: 'RELATIONAL_DATABASE', - Name: `${this.context.databaseName}_rds_DataSource`, - Description: `RDS Data Source Provisioned for ${this.context.databaseName}`, - ApiId: Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId), - ServiceRoleArn: Fn.GetAtt(ResourceConstants.RESOURCES.RelationalDatabaseAccessRole, 'Arn'), - RelationalDatabaseConfig: { - RelationalDatabaseSourceType: 'RDS_HTTP_ENDPOINT', - RdsHttpEndpointConfig: { - AwsRegion: Fn.Ref(ResourceConstants.PARAMETERS.rdsRegion), - DbClusterIdentifier: Fn.Ref(ResourceConstants.PARAMETERS.rdsClusterIdentifier), - DatabaseName: Fn.Ref(ResourceConstants.PARAMETERS.rdsDatabaseName), - Schema: this.context.databaseSchema, - AwsSecretStoreArn: Fn.Ref(ResourceConstants.PARAMETERS.rdsSecretStoreArn), - }, - }, - }).dependsOn([ResourceConstants.RESOURCES.RelationalDatabaseAccessRole]); - } -} diff --git a/packages/graphql-relational-schema-transformer/src/ResourceConstants.ts b/packages/graphql-relational-schema-transformer/src/ResourceConstants.ts deleted file mode 100644 index fcbd8bf1df..0000000000 --- a/packages/graphql-relational-schema-transformer/src/ResourceConstants.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Resource Constants that are specific to the Relation Database Transform - */ -export class ResourceConstants { - public static readonly ENVIRONMENT_CONTEXT_KEYS = { - // Aurora Serverless Imports - RDSRegion: 'rdsRegion', - RDSClusterIdentifier: 'rdsClusterIdentifier', - RDSSecretStoreArn: 'rdsSecretStoreArn', - RDSDatabaseName: 'rdsDatabaseName', - }; - - public static readonly RESOURCES = { - // AppSync - GraphQLAPILogicalID: 'GraphQLAPI', - GraphQLSchemaLogicalID: 'GraphQLSchema', - APIKeyLogicalID: 'GraphQLAPIKey', - - // Relational Database - ResolverFileName: 'ResolverFileName', - RelationalDatabaseDataSource: 'RelationalDatabaseDataSource', - RelationalDatabaseAccessRole: 'RelationalDatabaseAccessRole', - }; - - public static PARAMETERS = { - // cli - Env: 'env', - S3DeploymentBucket: 'S3DeploymentBucket', - S3DeploymentRootKey: 'S3DeploymentRootKey', - - // AppSync - AppSyncApiName: 'AppSyncApiName', - AppSyncApiId: 'AppSyncApiId', - APIKeyExpirationEpoch: 'APIKeyExpirationEpoch', - - // Aurora Serverless - rdsRegion: 'rdsRegion', - rdsClusterIdentifier: 'rdsClusterIdentifier', - rdsSecretStoreArn: 'rdsSecretStoreArn', - rdsDatabaseName: 'rdsDatabaseName', - }; -} diff --git a/packages/graphql-relational-schema-transformer/src/__tests__/AuroraDataAPIClient.test.ts b/packages/graphql-relational-schema-transformer/src/__tests__/AuroraDataAPIClient.test.ts deleted file mode 100644 index 072632478b..0000000000 --- a/packages/graphql-relational-schema-transformer/src/__tests__/AuroraDataAPIClient.test.ts +++ /dev/null @@ -1,464 +0,0 @@ -import { DataApiParams, AuroraDataAPIClient } from '../AuroraDataAPIClient'; - -const region = 'us-east-1'; -const secretStoreArn = 'secretStoreArn'; -const clusterArn = 'clusterArn'; -const databaseName = 'Animals'; -const tableAName = 'Dog'; -const tableBName = 'Owners'; - -test('list tables', async () => { - const rdsPromise = { - promise: jest.fn().mockImplementation(() => { - return new Promise((resolve, reject) => { - const response = { - numberOfRecordsUpdated: -1, - records: [ - [ - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: null, - realValue: null, - stringValue: `${tableAName}`, - }, - ], - ], - columnMetadata: [ - { - arrayBaseColumnType: 0, - isAutoIncrement: false, - isCaseSensitive: false, - isCurrency: false, - isSigned: false, - label: `Tables_in_${databaseName}`, - name: 'TABLE_NAME', - nullable: 0, - precision: 64, - scale: 0, - schemaName: '', - tableName: 'TABLE_NAMES', - type: 12, - typeName: 'VARCHAR', - }, - ], - }; - resolve(response); - }); - }), - }; - const MockRDSClient = jest.fn(() => ({ - executeStatement: jest.fn((params: DataApiParams) => { - if (params.sql == 'SHOW TABLES') { - return rdsPromise; - } - throw new Error('Incorrect SQL given.'); - }), - })); - - const aws = require('aws-sdk'); - - const testClient = new AuroraDataAPIClient(region, secretStoreArn, clusterArn, databaseName, aws); - const mockRDS = new MockRDSClient(); - testClient.setRDSClient(mockRDS); - - const tables = await testClient.listTables(); - const Params = new DataApiParams(); - Params.secretArn = secretStoreArn; - Params.resourceArn = clusterArn; - Params.database = databaseName; - Params.sql = 'SHOW TABLES'; - expect(mockRDS.executeStatement).toHaveBeenCalledWith(Params); - expect(tables.length).toEqual(1); - expect(tables[0]).toEqual(tableAName); -}); - -test('foreign key lookup', async () => { - const rdsPromise = { - promise: jest.fn().mockImplementation(() => { - return new Promise((resolve, reject) => { - const response = { - numberOfRecordsUpdated: -1, - records: [ - [ - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: null, - realValue: null, - stringValue: `${tableAName}`, - }, - ], - ], - columnMetadata: [ - { - arrayBaseColumnType: 0, - isAutoIncrement: false, - isCaseSensitive: false, - isCurrency: false, - isSigned: false, - label: `Tables_in_${databaseName}`, - name: 'TABLE_NAME', - nullable: 0, - precision: 64, - scale: 0, - schemaName: '', - tableName: 'TABLE_NAMES', - type: 12, - typeName: 'VARCHAR', - }, - ], - }; - resolve(response); - }); - }), - }; - - const MockRDSClient = jest.fn(() => ({ - executeStatement: jest.fn((params: DataApiParams) => { - if (params.sql.indexOf(`AND REFERENCED_TABLE_NAME = '${tableBName}'`) > -1) { - return rdsPromise; - } - throw new Error('Incorrect SQL given.'); - }), - })); - - const aws = require('aws-sdk'); - const testClient = new AuroraDataAPIClient(region, secretStoreArn, clusterArn, databaseName, aws); - const mockRDS = new MockRDSClient(); - testClient.setRDSClient(mockRDS); - - const tables = await testClient.getTableForeignKeyReferences(tableBName); - expect(tables.length).toEqual(1); - expect(tables[0]).toEqual(tableAName); -}); - -test('describe table', async () => { - const rdsPromise = { - promise: jest.fn().mockImplementation(() => { - return new Promise((resolve, reject) => { - const response = { - numberOfRecordsUpdated: -1, - records: [ - [ - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: null, - realValue: null, - stringValue: 'id', - }, - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: null, - realValue: null, - stringValue: 'int(11)', - }, - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: null, - realValue: null, - stringValue: 'NO', - }, - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: null, - realValue: null, - stringValue: 'PRI', - }, - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: true, - realValue: null, - stringValue: null, - }, - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: null, - realValue: null, - stringValue: '', - }, - ], - [ - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: null, - realValue: null, - stringValue: 'name', - }, - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: null, - realValue: null, - stringValue: 'varchar(255)', - }, - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: null, - realValue: null, - stringValue: 'NO', - }, - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: null, - realValue: null, - stringValue: '', - }, - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: true, - realValue: null, - stringValue: null, - }, - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: null, - realValue: null, - stringValue: '', - }, - ], - [ - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: null, - realValue: null, - stringValue: 'age', - }, - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: null, - realValue: null, - stringValue: 'int(11)', - }, - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: null, - realValue: null, - stringValue: 'NO', - }, - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: null, - realValue: null, - stringValue: '', - }, - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: true, - realValue: null, - stringValue: null, - }, - { - bigIntValue: null, - bitValue: null, - blobValue: null, - doubleValue: null, - intValue: null, - isNull: null, - realValue: null, - stringValue: '', - }, - ], - ], - - columnMetadata: [ - { - arrayBaseColumnType: 0, - isAutoIncrement: false, - isCaseSensitive: false, - isCurrency: false, - isSigned: false, - label: 'Field', - name: 'COLUMN_NAME', - nullable: 0, - precision: 64, - scale: 0, - schemaName: '', - tableName: 'COLUMNS', - type: 12, - typeName: 'VARCHAR', - }, - { - arrayBaseColumnType: 0, - isAutoIncrement: false, - isCaseSensitive: false, - isCurrency: false, - isSigned: false, - label: 'Type', - name: 'COLUMN_TYPE', - nullable: 0, - precision: 65535, - scale: 0, - schemaName: '', - tableName: 'COLUMNS', - type: -1, - typeName: 'MEDIUMTEXT', - }, - { - arrayBaseColumnType: 0, - isAutoIncrement: false, - isCaseSensitive: false, - isCurrency: false, - isSigned: false, - label: 'Null', - name: 'IS_NULLABLE', - nullable: 0, - precision: 3, - scale: 0, - schemaName: '', - tableName: 'COLUMNS', - type: 12, - typeName: 'VARCHAR', - }, - { - arrayBaseColumnType: 0, - isAutoIncrement: false, - isCaseSensitive: false, - isCurrency: false, - isSigned: false, - label: 'Key', - name: 'COLUMN_KEY', - nullable: 0, - precision: 3, - scale: 0, - schemaName: '', - tableName: 'COLUMNS', - type: 12, - typeName: 'VARCHAR', - }, - { - arrayBaseColumnType: 0, - isAutoIncrement: false, - isCaseSensitive: false, - isCurrency: false, - isSigned: false, - label: 'Default', - name: 'COLUMN_DEFAULT', - nullable: 1, - precision: 65535, - scale: 0, - schemaName: '', - tableName: 'COLUMNS', - type: -1, - typeName: 'MEDIUMTEXT', - }, - { - arrayBaseColumnType: 0, - isAutoIncrement: false, - isCaseSensitive: false, - isCurrency: false, - isSigned: false, - label: 'Extra', - name: 'EXTRA', - nullable: 0, - precision: 30, - scale: 0, - schemaName: '', - tableName: 'COLUMNS', - type: 12, - typeName: 'VARCHAR', - }, - ], - }; - resolve(response); - }); - }), - }; - - const MockRDSClient = jest.fn(() => ({ - executeStatement: jest.fn((params: DataApiParams) => { - if (params.sql == `DESCRIBE \`${tableAName}\``) { - return rdsPromise; - } - throw new Error('Incorrect SQL given.'); - }), - })); - - const aws = require('aws-sdk'); - const testClient = new AuroraDataAPIClient(region, secretStoreArn, clusterArn, databaseName, aws); - const mockRDS = new MockRDSClient(); - testClient.setRDSClient(mockRDS); - - const columnDescriptions = await testClient.describeTable(tableAName); - const Params = new DataApiParams(); - Params.secretArn = secretStoreArn; - Params.resourceArn = clusterArn; - Params.database = databaseName; - Params.sql = `DESCRIBE \`${tableAName}\``; - expect(mockRDS.executeStatement).toHaveBeenCalledWith(Params); - expect(columnDescriptions.length).toEqual(3); - // TODO: the rest of these tests -}); diff --git a/packages/graphql-relational-schema-transformer/src/__tests__/AuroraServerlessMySQLDBReader.test.ts b/packages/graphql-relational-schema-transformer/src/__tests__/AuroraServerlessMySQLDBReader.test.ts deleted file mode 100644 index 1a842ba775..0000000000 --- a/packages/graphql-relational-schema-transformer/src/__tests__/AuroraServerlessMySQLDBReader.test.ts +++ /dev/null @@ -1,160 +0,0 @@ -import { Kind } from 'graphql'; -import { toUpper } from 'graphql-transformer-common'; -import { TemplateContext, TableContext } from '../RelationalDBSchemaTransformer'; -import { AuroraServerlessMySQLDatabaseReader } from '../AuroraServerlessMySQLDatabaseReader'; -import { AuroraDataAPIClient, ColumnDescription } from '../AuroraDataAPIClient'; - -const dbRegion = 'us-east-1'; -const secretStoreArn = 'secretStoreArn'; -const clusterArn = 'clusterArn'; -const testDBName = 'testdb'; -const tableAName = 'a'; -const tableBName = 'b'; -const tableCName = 'c'; -const tableDName = 'd'; -const aws = require('aws-sdk'); - -const dummyReader = new AuroraServerlessMySQLDatabaseReader(dbRegion, secretStoreArn, clusterArn, testDBName, aws); - -test('describe table', async () => { - const MockAuroraClient = jest.fn(() => ({ - describeTable: jest.fn((tableName: string) => { - const tableColumns = []; - const idColDescription = new ColumnDescription(); - const nameColDescription = new ColumnDescription(); - - idColDescription.Field = 'id'; - idColDescription.Type = 'int'; - idColDescription.Null = 'NO'; - idColDescription.Key = 'PRI'; - idColDescription.Default = null; - idColDescription.Extra = ''; - - nameColDescription.Field = 'name'; - nameColDescription.Type = 'varchar(100)'; - nameColDescription.Null = 'YES'; - nameColDescription.Key = ''; - nameColDescription.Default = null; - nameColDescription.Extra = ''; - - tableColumns.push(idColDescription); - tableColumns.push(nameColDescription); - if (tableName == tableBName) { - const foreignKeyId = new ColumnDescription(); - foreignKeyId.Field = 'aId'; - foreignKeyId.Type = 'int'; - foreignKeyId.Null = 'YES'; - foreignKeyId.Key = 'MUL'; - foreignKeyId.Default = null; - foreignKeyId.Extra = ''; - - tableColumns.push(foreignKeyId); - } - return tableColumns; - }), - getTableForeignKeyReferences: jest.fn((tableName: string) => { - if (tableName == tableBName) { - return [tableAName]; - } - return []; - }), - })); - const mockClient = new MockAuroraClient(); - dummyReader.setAuroraClient(mockClient); - - describeTableTestCommon(tableAName, 2, false, await dummyReader.describeTable(tableAName)); - describeTableTestCommon(tableBName, 3, true, await dummyReader.describeTable(tableBName)); - describeTableTestCommon(tableCName, 2, false, await dummyReader.describeTable(tableCName)); - describeTableTestCommon(tableDName, 2, false, await dummyReader.describeTable(tableDName)); -}); - -function describeTableTestCommon(tableName: string, fieldLength: number, isForeignKey: boolean, tableContext: TableContext) { - const formattedTableName = toUpper(tableName); - expect(tableContext.tableKeyField).toEqual('id'); - expect(tableContext.tableKeyFieldType).toEqual('Int'); - expect(tableContext.createTypeDefinition).toBeDefined(); - expect(tableContext.updateTypeDefinition).toBeDefined(); - expect(tableContext.tableTypeDefinition).toBeDefined(); - expect(tableContext.tableTypeDefinition.kind).toEqual(Kind.OBJECT_TYPE_DEFINITION); - expect(tableContext.updateTypeDefinition.kind).toEqual(Kind.INPUT_OBJECT_TYPE_DEFINITION); - expect(tableContext.createTypeDefinition.kind).toEqual(Kind.INPUT_OBJECT_TYPE_DEFINITION); - expect(tableContext.tableTypeDefinition.name.value).toEqual(tableName); - expect(tableContext.tableTypeDefinition.name.kind).toEqual(Kind.NAME); - expect(tableContext.updateTypeDefinition.name.value).toEqual(`Update${formattedTableName}Input`); - expect(tableContext.updateTypeDefinition.name.kind).toEqual(Kind.NAME); - expect(tableContext.createTypeDefinition.name.value).toEqual(`Create${formattedTableName}Input`); - expect(tableContext.createTypeDefinition.name.kind).toEqual(Kind.NAME); - /** - * If it's a table with a foreign key constraint, the base type will have one additional element - * for the nested type. e.g. if type Posts had fields of id/int, content/string, and author/string - * but comments had a foreign key constraint on it, then it would look like this (whereas the - * create and update inputs would not have the additional field): - * type Post { - * id: Int! - * author: String! - * content: String! - * comments: CommentConnection - * } - */ - expect(tableContext.tableTypeDefinition.fields.length).toEqual(fieldLength); - expect(tableContext.updateTypeDefinition.fields.length).toEqual(fieldLength); - expect(tableContext.createTypeDefinition.fields.length).toEqual(fieldLength); -} - -test('hydrate template context', async () => { - const context = await dummyReader.hydrateTemplateContext(new TemplateContext(null, null, null, null)); - expect(context.secretStoreArn).toEqual(secretStoreArn); - expect(context.databaseName).toEqual(testDBName); - expect(context.rdsClusterIdentifier).toEqual(clusterArn); - expect(context.region).toEqual(dbRegion); - expect(context.databaseSchema).toEqual('mysql'); -}); - -test('list tables', async () => { - const MockAuroraClient = jest.fn(() => ({ - listTables: jest.fn(() => { - return [tableAName, tableBName, tableCName, tableDName]; - }), - })); - const mockClient = new MockAuroraClient(); - dummyReader.setAuroraClient(mockClient); - - const tableNames = await dummyReader.listTables(); - expect(mockClient.listTables).toHaveBeenCalled(); - expect(tableNames.length).toBe(4); - expect(tableNames.indexOf(tableAName) > -1).toBe(true); - expect(tableNames.indexOf(tableBName) > -1).toBe(true); - expect(tableNames.indexOf(tableCName) > -1).toBe(true); - expect(tableNames.indexOf(tableDName) > -1).toBe(true); -}); - -test('lookup foreign key', async () => { - const MockAuroraClient = jest.fn(() => ({ - getTableForeignKeyReferences: jest.fn((tableName: string) => { - if (tableName == tableBName) { - return [tableAName]; - } - return []; - }), - })); - const mockClient = new MockAuroraClient(); - dummyReader.setAuroraClient(mockClient); - - const aKeys = await dummyReader.getTableForeignKeyReferences(tableAName); - const bKeys = await dummyReader.getTableForeignKeyReferences(tableBName); - const cKeys = await dummyReader.getTableForeignKeyReferences(tableCName); - const dKeys = await dummyReader.getTableForeignKeyReferences(tableDName); - expect(aKeys).toBeDefined(); - expect(bKeys).toBeDefined(); - expect(cKeys).toBeDefined(); - expect(dKeys).toBeDefined(); - expect(aKeys.length).toBe(0); - expect(bKeys.length).toBe(1); - expect(cKeys.length).toBe(0); - expect(dKeys.length).toBe(0); - expect(bKeys[0]).toBe(tableAName); - expect(mockClient.getTableForeignKeyReferences).toHaveBeenCalledWith(tableAName); - expect(mockClient.getTableForeignKeyReferences).toHaveBeenCalledWith(tableBName); - expect(mockClient.getTableForeignKeyReferences).toHaveBeenCalledWith(tableCName); - expect(mockClient.getTableForeignKeyReferences).toHaveBeenCalledWith(tableDName); -}); diff --git a/packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBMappingTemplate.test.ts b/packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBMappingTemplate.test.ts deleted file mode 100644 index e425a06322..0000000000 --- a/packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBMappingTemplate.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { list, str, ObjectNode, print } from 'graphql-mapping-template'; -import { RelationalDBMappingTemplate } from '../RelationalDBMappingTemplate'; - -const sql = 'SELECT * FROM Pets'; - -/** - * Test for verifying that provided a sql statement, we successfully create - * the rds query mapping template - */ -test('RDS Query Mapping Template Creation', () => { - const queryObj: ObjectNode = RelationalDBMappingTemplate.rdsQuery({ - statements: list([str(sql)]), - }); - - expect(queryObj).toBeDefined(); - expect(queryObj.kind).toBe('Object'); - expect(queryObj.attributes).toBeDefined(); - - // Verify the Version was created successfully - const versionAttr = queryObj.attributes[0]; - expect(versionAttr).toBeDefined(); - expect(versionAttr[0]).toBe('version'); - expect(versionAttr[1].kind).toBe('String'); - expect(print(versionAttr[1])).toBe('"2018-05-29"'); - - // Verify the sql statement was created successfully - const statementsAttr = queryObj.attributes[1]; - expect(statementsAttr).toBeDefined(); - expect(statementsAttr[0]).toBe('statements'); - expect(statementsAttr[1].kind).toBe('List'); - expect(print(statementsAttr[1])).toBe('["SELECT * FROM Pets"]'); -}); diff --git a/packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBResolverGenerator.test.ts b/packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBResolverGenerator.test.ts deleted file mode 100644 index d6b95990e6..0000000000 --- a/packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBResolverGenerator.test.ts +++ /dev/null @@ -1,169 +0,0 @@ -import * as fs from 'fs-extra'; -import { parse } from 'graphql'; -import { RelationalDBResolverGenerator } from '../RelationalDBResolverGenerator'; -import { TemplateContext } from '../RelationalDBSchemaTransformer'; - -jest.mock('fs-extra', () => ({ - writeFileSync: jest.fn(), -})); -const writeFileSync_mock = fs.writeFileSync as jest.MockedFunction; -afterEach(() => jest.clearAllMocks()); - -/** - * Test for verifying that provided a template context, the resolver generator - * creates the CRUDL AppSync Resolver resources. - */ -test('Basic CRUDL Resolver Generation', () => { - // SETUP - const schema = parse(` - type Pet { - id: String - name: String - } - - type Owner { - id: String - name: String - } - `); - let simpleStringFieldMap = new Map(); - let simpleIntFieldMap = new Map(); - let simplePrimaryKeyMap = new Map(); - let simplePrimaryKeyTypeMap = new Map(); - - simplePrimaryKeyMap.set('Pet', 'Id'); - simplePrimaryKeyMap.set('Owner', 'Id'); - simplePrimaryKeyTypeMap.set('Pet', 'String'); - simplePrimaryKeyTypeMap.set('Owner', 'Int'); - const context = new TemplateContext(schema, simplePrimaryKeyMap, simpleStringFieldMap, simpleIntFieldMap, simplePrimaryKeyTypeMap); - const generator = new RelationalDBResolverGenerator(context); - - // TEST - const resources: { [key: string]: any } = generator.createRelationalResolvers('someFilePath', true); - - // VERIFY - expect(resources).toBeDefined(); - - // Verify all CRUDL resolvers were created for the Pet Type - expect(resources).toHaveProperty('PetCreateResolver'); - expect(resources).toHaveProperty('PetGetResolver'); - expect(resources).toHaveProperty('PetUpdateResolver'); - expect(resources).toHaveProperty('PetDeleteResolver'); - expect(resources).toHaveProperty('PetListResolver'); - - // Verify for the GetResolver the elements are present - let resolverMap = Object.keys(resources).map((key) => resources[key]); - expect(resolverMap[1]).toHaveProperty('Type'); - expect(resolverMap[1]).toHaveProperty('Properties'); - - // Verify a resolver was created for the owner type as well - expect(resources).toHaveProperty('OwnerCreateResolver'); -}); - -test('verify generated templates', () => { - // SETUP - const schema = parse(` - type Tomatoes { - id: String - name: String - } - `); - let simpleStringFieldMap = new Map(); - let simpleIntFieldMap = new Map(); - let simplePrimaryKeyMap = new Map(); - let simplePrimaryKeyTypeMap = new Map(); - - simplePrimaryKeyMap.set('Tomatoes', 'Id'); - simplePrimaryKeyTypeMap.set('Tomatoes', 'String'); - const context = new TemplateContext(schema, simplePrimaryKeyMap, simpleStringFieldMap, simpleIntFieldMap, simplePrimaryKeyTypeMap); - const generator = new RelationalDBResolverGenerator(context); - generator.createRelationalResolvers('testFilePath', true); - expect(writeFileSync_mock.mock.calls.length).toBe(10); - writeFileSync_mock.mock.calls.forEach((call) => { - expect(call.length).toBe(3); - expect(call[0]).toMatchSnapshot(); - expect(call[1]).toMatchSnapshot(); - expect(call[2]).toBe('utf8'); - }); -}); - -test('verify generated templates with non-id named primary key', () => { - // SETUP - const schema = parse(` - type Tomatoes { - tomatoId: String - name: String - } - `); - let simpleStringFieldMap = new Map(); - let simpleIntFieldMap = new Map(); - let simplePrimaryKeyMap = new Map(); - let simplePrimaryKeyTypeMap = new Map(); - - simplePrimaryKeyMap.set('Tomatoes', 'tomatoId'); - simplePrimaryKeyTypeMap.set('Tomatoes', 'String'); - const context = new TemplateContext(schema, simplePrimaryKeyMap, simpleStringFieldMap, simpleIntFieldMap, simplePrimaryKeyTypeMap); - const generator = new RelationalDBResolverGenerator(context); - generator.createRelationalResolvers('testFilePath', true); - expect(writeFileSync_mock.mock.calls.length).toBe(10); - writeFileSync_mock.mock.calls.forEach((call) => { - expect(call.length).toBe(3); - expect(call[0]).toMatchSnapshot(); - expect(call[1]).toMatchSnapshot(); - expect(call[2]).toBe('utf8'); - }); -}); - -test('verify generated templates using a Int primary key', () => { - // SETUP - const schema = parse(` - type Apples { - id: Int - name: String - } - `); - let simpleStringFieldMap = new Map(); - let simpleIntFieldMap = new Map(); - let simplePrimaryKeyMap = new Map(); - let simplePrimaryKeyTypeMap = new Map(); - - simplePrimaryKeyMap.set('Apples', 'Id'); - simplePrimaryKeyTypeMap.set('Apples', 'Int'); - const context = new TemplateContext(schema, simplePrimaryKeyMap, simpleStringFieldMap, simpleIntFieldMap, simplePrimaryKeyTypeMap); - const generator = new RelationalDBResolverGenerator(context); - generator.createRelationalResolvers('testFilePath', true); - expect(writeFileSync_mock.mock.calls.length).toBe(10); - writeFileSync_mock.mock.calls.forEach((call) => { - expect(call.length).toBe(3); - expect(call[0]).toMatchSnapshot(); - expect(call[1]).toMatchSnapshot(); - expect(call[2]).toBe('utf8'); - }); -}); - -test('verify generated templates with old pluralization', () => { - // SETUP - const schema = parse(` - type Apples { - id: Int - name: String - } - `); - let simpleStringFieldMap = new Map(); - let simpleIntFieldMap = new Map(); - let simplePrimaryKeyMap = new Map(); - let simplePrimaryKeyTypeMap = new Map(); - - simplePrimaryKeyMap.set('Apples', 'Id'); - simplePrimaryKeyTypeMap.set('Apples', 'Int'); - const context = new TemplateContext(schema, simplePrimaryKeyMap, simpleStringFieldMap, simpleIntFieldMap, simplePrimaryKeyTypeMap); - const generator = new RelationalDBResolverGenerator(context); - generator.createRelationalResolvers('testFilePath', false); - expect(writeFileSync_mock.mock.calls.length).toBe(10); - writeFileSync_mock.mock.calls.forEach((call) => { - expect(call.length).toBe(3); - expect(call[0]).toMatchSnapshot(); - expect(call[1]).toMatchSnapshot(); - expect(call[2]).toBe('utf8'); - }); -}); diff --git a/packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBSchemaTransformer.test.ts b/packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBSchemaTransformer.test.ts deleted file mode 100644 index d5db696ce7..0000000000 --- a/packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBSchemaTransformer.test.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { Kind, print } from 'graphql'; -import { toUpper } from 'graphql-transformer-common'; -import { TemplateContext, RelationalDBSchemaTransformer, TableContext } from '../RelationalDBSchemaTransformer'; -import { RelationalDBParsingException } from '../RelationalDBParsingException'; -import { IRelationalDBReader } from '../IRelationalDBReader'; -import { - getNamedType, - getNonNullType, - getInputValueDefinition, - getGraphQLTypeFromMySQLType, - getTypeDefinition, - getFieldDefinition, - getInputTypeDefinition, -} from '../RelationalDBSchemaTransformerUtils'; - -const testDBName = 'testdb'; -const mockTableAName = 'a'; -const mockTableBName = 'b'; -const mockTableCName = 'c'; -const mockTableDName = 'd'; -const region = 'us-east-1'; -const secretStoreArn = 'secretStoreArn'; -const clusterArn = 'clusterArn'; - -function getTableContext(tableName: string): TableContext { - const fields = new Array(); - const updateFields = new Array(); - const createFields = new Array(); - const primaryKey = 'id'; - const primaryKeyType = 'VarChar(128)'; - const stringFieldList = ['name', 'description']; - const formattedTableName = toUpper(tableName); - - for (const fieldName of stringFieldList) { - const baseType = getNamedType(getGraphQLTypeFromMySQLType(primaryKeyType)); - - const type = getNonNullType(baseType); - fields.push(getFieldDefinition(fieldName, type)); - - createFields.push(getInputValueDefinition(type, fieldName)); - - let updateType = null; - if (primaryKey === fieldName) { - updateType = getNonNullType(baseType); - } else { - updateType = baseType; - } - updateFields.push(getInputValueDefinition(updateType, fieldName)); - } - return new TableContext( - getTypeDefinition(fields, tableName), - getInputTypeDefinition(createFields, `Create${formattedTableName}Input`), - getInputTypeDefinition(updateFields, `Update${formattedTableName}Input`), - primaryKey, - primaryKeyType, - stringFieldList, - [], - ); -} - -test('schema generation end to end', async () => { - const MockRelationalDBReader = jest.fn(() => ({ - listTables: jest.fn(() => { - return [mockTableAName, mockTableBName, mockTableCName, mockTableDName]; - }), - describeTable: jest.fn((tableName: string) => { - return getTableContext(tableName); - }), - hydrateTemplateContext: jest.fn((contextShell: TemplateContext) => { - contextShell.secretStoreArn = secretStoreArn; - contextShell.rdsClusterIdentifier = clusterArn; - contextShell.databaseSchema = 'mysql'; - contextShell.databaseName = testDBName; - contextShell.region = region; - return contextShell; - }), - })); - - const mockReader = new MockRelationalDBReader(); - const dummyTransformer = new RelationalDBSchemaTransformer(mockReader, testDBName); - - const templateContext = await dummyTransformer.introspectDatabaseSchema(); - - expect(mockReader.listTables).toHaveBeenCalled(); - expect(mockReader.describeTable).toHaveBeenCalledWith(mockTableAName); - expect(mockReader.describeTable).toHaveBeenCalledWith(mockTableBName); - expect(mockReader.describeTable).toHaveBeenCalledWith(mockTableCName); - expect(mockReader.describeTable).toHaveBeenCalledWith(mockTableDName); - expect(templateContext.schemaDoc).toBeDefined(); - expect(templateContext.schemaDoc.kind).toBe(Kind.DOCUMENT); - // 4 tables * (base, update input, and create input) + schema, queries, mutations, and subs - // (4 * 3) + 4 = 16 - expect(templateContext.schemaDoc.definitions.length).toBe(16); - let objectTypeCount = 0; - let inputTypeCount = 0; - let schemaTypeCount = 0; - for (const node of templateContext.schemaDoc.definitions) { - if (node.kind === Kind.OBJECT_TYPE_DEFINITION) { - objectTypeCount++; - } else if (node.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION) { - inputTypeCount++; - } else if (node.kind === Kind.SCHEMA_DEFINITION) { - schemaTypeCount++; - } - } - expect(schemaTypeCount).toEqual(1); // Singular schema node - expect(inputTypeCount).toEqual(8); // 4 tables * (update input + create input) - expect(objectTypeCount).toEqual(7); // (4 tables * base shape) + queries + mutations + subs - const schemaString = print(templateContext.schemaDoc); - expect(schemaString).toBeDefined(); - console.log(schemaString); -}); - -test('list tables fails', async () => { - const MockRelationalDBReader = jest.fn(() => ({ - listTables: jest.fn(() => { - throw new Error('Mocked failure on list tables.'); - }), - describeTable: jest.fn(() => { - throw new Error('Mocked failure on describe. THIS SHOULD NOT HAPPEN.'); - }), - })); - const mockReader = new MockRelationalDBReader(); - const dummyTransformer = new RelationalDBSchemaTransformer(mockReader, testDBName); - - try { - await dummyTransformer.introspectDatabaseSchema(); - throw new Error('Request should have failed.'); - } catch (err) { - if (err instanceof RelationalDBParsingException) { - // expected - } else { - throw new Error('Unexpected exception thrown.'); - } - } - expect(mockReader.listTables).toHaveBeenCalled(); - expect(mockReader.describeTable).not.toHaveBeenCalled(); -}); - -test('describe table fails', async () => { - const MockRelationalDBReader = jest.fn(() => ({ - listTables: jest.fn(() => { - return [mockTableAName, mockTableBName, mockTableCName, mockTableDName]; - }), - describeTable: jest.fn(() => { - throw new Error('Mocked failure on describe.'); - }), - })); - const mockReader = new MockRelationalDBReader(); - const dummyTransformer = new RelationalDBSchemaTransformer(mockReader, testDBName); - - try { - await dummyTransformer.introspectDatabaseSchema(); - throw new Error('Request should have failed.'); - } catch (err) { - if (err instanceof RelationalDBParsingException) { - // expected - } else { - throw new Error('Unexpected exception thrown.'); - } - } - - expect(mockReader.listTables).toHaveBeenCalled(); - expect(mockReader.describeTable).toHaveBeenCalledWith(mockTableAName); -}); - -test('connection type shape', () => { - const testType = 'type name'; - const MockRelationalDBReader = jest.fn(() => ({})); - const mockReader = new MockRelationalDBReader(); - const dummyTransformer = new RelationalDBSchemaTransformer(mockReader, testDBName); - const connectionType = dummyTransformer.getConnectionType(testType); - expect(connectionType.fields.length).toEqual(2); - expect(connectionType.name.value).toEqual(`${testType}Connection`); -}); - -test('schema type node creation', () => { - const MockRelationalDBReader = jest.fn(() => ({})); - const mockReader = new MockRelationalDBReader(); - const dummyTransformer = new RelationalDBSchemaTransformer(mockReader, testDBName); - const schemaNode = dummyTransformer.getSchemaType(); - expect(schemaNode.kind).toEqual(Kind.SCHEMA_DEFINITION); - expect(schemaNode.operationTypes.length).toEqual(3); -}); diff --git a/packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBSchemaTransformerUtils.test.ts b/packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBSchemaTransformerUtils.test.ts deleted file mode 100644 index 691767ef4b..0000000000 --- a/packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBSchemaTransformerUtils.test.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { Kind } from 'graphql'; -import { - getNamedType, - getOperationFieldDefinition, - getNonNullType, - getInputValueDefinition, - getTypeDefinition, - getFieldDefinition, - getDirectiveNode, - getOperationTypeDefinition, - getNameNode, - getListValueNode, - getStringValueNode, - getInputTypeDefinition, - getArgumentNode, - getGraphQLTypeFromMySQLType, - getSingletonListTypeNode, -} from '../RelationalDBSchemaTransformerUtils'; - -test('operation type node creation', () => { - const operationType = 'query'; - const namedNode = getNamedType('Query'); - const operationTypeNode = getOperationTypeDefinition(operationType, namedNode); - expect(operationTypeNode.kind).toEqual(Kind.OPERATION_TYPE_DEFINITION); - expect(operationTypeNode.operation).toEqual(operationType); - expect(operationTypeNode.type).toEqual(namedNode); -}); - -test('non null type node creation', () => { - const namedTypeNode = getNamedType('test name'); - const nonNullNamedTypeNode = getNonNullType(namedTypeNode); - expect(nonNullNamedTypeNode.kind).toEqual(Kind.NON_NULL_TYPE); - expect(nonNullNamedTypeNode.type).toEqual(namedTypeNode); -}); - -test('named type node creation', () => { - const name = 'test name'; - const namedTypeNode = getNamedType(name); - expect(namedTypeNode.kind).toEqual(Kind.NAMED_TYPE); - expect(namedTypeNode.name.value).toEqual(name); -}); - -test('input value definition node creation', () => { - const name = 'input name'; - const nameNode = getNamedType('type name'); - const inputDefinitionNode = getInputValueDefinition(nameNode, name); - expect(inputDefinitionNode.kind).toEqual(Kind.INPUT_VALUE_DEFINITION); - expect(inputDefinitionNode.type).toEqual(nameNode); - expect(inputDefinitionNode.directives).toEqual([]); - expect(inputDefinitionNode.name.value).toEqual(name); -}); - -test('operation field definition node creation', () => { - const name = 'field name'; - const args = [getInputValueDefinition(null, 'test name')]; - const namedNode = getNamedType('test name'); - const operationFieldDefinitionNode = getOperationFieldDefinition(name, args, namedNode, null); - expect(operationFieldDefinitionNode.kind).toEqual(Kind.FIELD_DEFINITION); - expect(operationFieldDefinitionNode.type).toEqual(namedNode); - expect(operationFieldDefinitionNode.arguments).toEqual(args); - expect(operationFieldDefinitionNode.directives).toEqual([]); -}); - -test('field definition node creation', () => { - const fieldName = 'field name'; - const namedNode = getNamedType('type name'); - const fieldDefinitionNode = getFieldDefinition(fieldName, namedNode); - expect(fieldDefinitionNode.kind).toEqual(Kind.FIELD_DEFINITION); - expect(fieldDefinitionNode.type).toEqual(namedNode); - expect(fieldDefinitionNode.directives).toEqual([]); - expect(fieldDefinitionNode.name.value).toEqual(fieldName); -}); - -test('type definition node creation', () => { - const fieldList = [getFieldDefinition('field name', null)]; - const typeName = 'type name'; - const typeDefinitionNode = getTypeDefinition(fieldList, typeName); - expect(typeDefinitionNode.kind).toEqual(Kind.OBJECT_TYPE_DEFINITION); - expect(typeDefinitionNode.directives).toEqual([]); - expect(typeDefinitionNode.interfaces).toEqual([]); - expect(typeDefinitionNode.name.value).toEqual(typeName); - expect(typeDefinitionNode.fields).toEqual(fieldList); -}); - -test('name node creaton', () => { - const name = 'name string'; - const nameNode = getNameNode(name); - expect(nameNode.kind).toEqual(Kind.NAME); - expect(nameNode.value).toEqual(name); -}); - -test('list value node creation', () => { - const valueList = [getStringValueNode('string a'), getStringValueNode('string b')]; - const listValueNode = getListValueNode(valueList); - expect(listValueNode.kind).toEqual(Kind.LIST); - expect(listValueNode.values).toEqual(valueList); -}); - -test('singleton list type node creation', () => { - const value = 'singleton'; - const listTypeNode = getSingletonListTypeNode(value); - expect(listTypeNode.kind).toEqual(Kind.LIST_TYPE); - expect(listTypeNode.type).toEqual(getNamedType('singleton')); -}); - -test('object type node creation', () => { - const name = 'name'; - const inputNode = getInputTypeDefinition([], name); - expect(inputNode.kind).toEqual(Kind.INPUT_OBJECT_TYPE_DEFINITION); - expect(inputNode.fields.length).toEqual(0); - expect(inputNode.name.value).toEqual(name); -}); - -test('string value node creation', () => { - const stringValue = 'string value'; - const stringValueNode = getStringValueNode(stringValue); - expect(stringValueNode.kind).toEqual(Kind.STRING); - expect(stringValueNode.value).toEqual(stringValue); -}); - -test('directive node creation', () => { - const directiveNode = getDirectiveNode('directive name'); - expect(directiveNode.kind).toEqual(Kind.DIRECTIVE); - expect(directiveNode.name).toBeDefined(); - expect(directiveNode.arguments.length).toEqual(1); -}); - -test('argument node creation', () => { - const argumentNode = getArgumentNode('argument name'); - expect(argumentNode.kind).toEqual(Kind.ARGUMENT); - expect(argumentNode.name).toBeDefined(); - expect(argumentNode.value).toBeDefined(); - expect(argumentNode.value.kind).toEqual(Kind.LIST); -}); - -test('type conversion to AWSDateTime', () => { - expect(getGraphQLTypeFromMySQLType('datetime')).toEqual('AWSDateTime'); -}); - -test('type conversion to AWSDate', () => { - expect(getGraphQLTypeFromMySQLType('date')).toEqual('AWSDate'); -}); - -test('type conversion to AWSTime', () => { - expect(getGraphQLTypeFromMySQLType('time')).toEqual('AWSTime'); -}); - -test('type conversion to AWSTimestamp', () => { - expect(getGraphQLTypeFromMySQLType('timestamp')).toEqual('AWSTimestamp'); -}); - -test('type conversion to AWSJSON', () => { - expect(getGraphQLTypeFromMySQLType('jSoN')).toEqual('AWSJSON'); -}); - -test('type conversion to Boolean', () => { - expect(getGraphQLTypeFromMySQLType('BOOl')).toEqual('Boolean'); -}); - -test('type conversion to Int', () => { - expect(getGraphQLTypeFromMySQLType('Int')).toEqual('Int'); - expect(getGraphQLTypeFromMySQLType('Int(100)')).toEqual('Int'); - expect(getGraphQLTypeFromMySQLType('inteGER')).toEqual('Int'); - expect(getGraphQLTypeFromMySQLType('SmaLLInT')).toEqual('Int'); - expect(getGraphQLTypeFromMySQLType('TINYint')).toEqual('Int'); - expect(getGraphQLTypeFromMySQLType('mediumInt')).toEqual('Int'); - expect(getGraphQLTypeFromMySQLType('BIGINT')).toEqual('Int'); - expect(getGraphQLTypeFromMySQLType('BIT')).toEqual('Int'); -}); - -test('type conversion to Float', () => { - expect(getGraphQLTypeFromMySQLType('FloAT')).toEqual('Float'); - expect(getGraphQLTypeFromMySQLType('DOUBle')).toEqual('Float'); - expect(getGraphQLTypeFromMySQLType('REAL')).toEqual('Float'); - expect(getGraphQLTypeFromMySQLType('REAL_as_FLOAT')).toEqual('Float'); - expect(getGraphQLTypeFromMySQLType('DOUBLE precision')).toEqual('Float'); - expect(getGraphQLTypeFromMySQLType('DEC')).toEqual('Float'); - expect(getGraphQLTypeFromMySQLType('DeciMAL')).toEqual('Float'); - expect(getGraphQLTypeFromMySQLType('FIXED')).toEqual('Float'); - expect(getGraphQLTypeFromMySQLType('Numeric')).toEqual('Float'); -}); - -test('type conversion defaults to String', () => { - expect(getGraphQLTypeFromMySQLType('gibberish random stuff')).toEqual('String'); - expect(getGraphQLTypeFromMySQLType('timesta')).toEqual('String'); - expect(getGraphQLTypeFromMySQLType('boo')).toEqual('String'); - expect(getGraphQLTypeFromMySQLType('jso')).toEqual('String'); - expect(getGraphQLTypeFromMySQLType('tim')).toEqual('String'); - expect(getGraphQLTypeFromMySQLType('ate')).toEqual('String'); - expect(getGraphQLTypeFromMySQLType('atetime')).toEqual('String'); - expect(getGraphQLTypeFromMySQLType('Inte')).toEqual('String'); - expect(getGraphQLTypeFromMySQLType('Bigin')).toEqual('String'); - expect(getGraphQLTypeFromMySQLType('DECI')).toEqual('String'); - expect(getGraphQLTypeFromMySQLType('floatt')).toEqual('String'); - expect(getGraphQLTypeFromMySQLType('FIXE')).toEqual('String'); -}); diff --git a/packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBTemplateGenerator.test.ts b/packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBTemplateGenerator.test.ts deleted file mode 100644 index 5624220e33..0000000000 --- a/packages/graphql-relational-schema-transformer/src/__tests__/RelationalDBTemplateGenerator.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -jest.mock('../RelationalDBResolverGenerator'); - -import { parse } from 'graphql'; -import { ResourceConstants as CommonResourceConstants } from 'graphql-transformer-common'; -import { RelationalDBTemplateGenerator } from '../RelationalDBTemplateGenerator'; -import { TemplateContext } from '../RelationalDBSchemaTransformer'; -import { ResourceConstants } from '../ResourceConstants'; - -const schema = parse(` - type User { - id: String - name: String - } - - type Query { - user(id: String): User - } -`); - -let simplePrimaryKeyMap = new Map(); -let simpleStringFieldMap = new Map(); -let simpleIntFieldMap = new Map(); -let context = new TemplateContext(schema, simplePrimaryKeyMap, simpleStringFieldMap, simpleIntFieldMap); -context.secretStoreArn = - 'arn:aws:secretsmanager:us-east-1:123456789012:secret:rds-db-credentials/cluster-ABCDEFXHGNMSRTNK2A75532FKL/ashwin-aqwery'; -context.rdsClusterIdentifier = 'arn:aws:rds:us-east-1:123456789012:cluster:pets'; -context.databaseSchema = 'mysql'; -context.databaseName = 'pets'; -context.region = 'us-east-1'; - -const emptyCliContext = { - amplify: { - loadEnvResourceParameters(context: any, category: string, service: string) { - return {}; - }, - }, -}; - -const templateGenerator = new RelationalDBTemplateGenerator(context); - -/** - * Test for verifying that provided a valid TemplateContext, we are - * generating the base cloudform template (the cfn specs sans resolvers) - */ -test('Base CloudForm Template Generation', () => { - const template = templateGenerator.createTemplate(emptyCliContext); - - expect(template).toBeDefined(); - expect(template.AWSTemplateFormatVersion).toBeDefined(); - expect(template.AWSTemplateFormatVersion).toBe('2010-09-09'); - expect(template.Parameters).toBeDefined(); - expect(template.Parameters).toHaveProperty(ResourceConstants.PARAMETERS.AppSyncApiName); - - // Verify Resources were created as expected - expect(template.Resources).toBeDefined(); - expect(template.Resources).toHaveProperty(ResourceConstants.RESOURCES.RelationalDatabaseAccessRole); - expect(template.Resources).toHaveProperty(ResourceConstants.RESOURCES.RelationalDatabaseAccessRole); -}); - -/** - * Test for verifying that provided a base template, we are generating - * a template with the Relational Resolvers attached. - */ -test('Adding Resolvers to CloudForm Template', () => { - const baseTemplate = templateGenerator.createTemplate(emptyCliContext); - expect(baseTemplate).toBeDefined(); - expect(baseTemplate.Resources).toBeDefined(); - expect(baseTemplate.Resources).not.toHaveProperty(''); - - const finalTemplate = templateGenerator.addRelationalResolvers(baseTemplate, 'someFilePath', true); - expect(finalTemplate).toBeDefined(); -}); - -/** - * Test for verifying that provided a base template, we are generating the - * cfn template as a JSON string. - */ -test('Printing the cloudform template as a JSON', () => { - const baseTemplate = templateGenerator.createTemplate(emptyCliContext); - expect(baseTemplate).toBeDefined(); - - const templateJSON = templateGenerator.printCloudformationTemplate(baseTemplate); - expect(templateJSON).toBeDefined(); -}); diff --git a/packages/graphql-relational-schema-transformer/src/__tests__/__snapshots__/RelationalDBResolverGenerator.test.ts.snap b/packages/graphql-relational-schema-transformer/src/__tests__/__snapshots__/RelationalDBResolverGenerator.test.ts.snap deleted file mode 100644 index c850f24efb..0000000000 --- a/packages/graphql-relational-schema-transformer/src/__tests__/__snapshots__/RelationalDBResolverGenerator.test.ts.snap +++ /dev/null @@ -1,485 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`verify generated templates 1`] = `"testFilePath/Mutation.createTomatoes.req.vtl"`; - -exports[`verify generated templates 2`] = ` -"#set( $cols = [] ) -#set( $vals = [] ) -#set( $variableMap = {} ) -#foreach( $entry in $ctx.args.createTomatoesInput.keySet() ) - #set( $discard = $cols.add($entry) ) - #set( $discard = $vals.add(\\":$entry\\") ) - $util.qr($variableMap.put(\\":$entry\\", $ctx.args.createTomatoesInput[$entry])) -#end -#set( $valStr = $vals.toString().replace(\\"[\\",\\"(\\").replace(\\"]\\",\\")\\") ) -#set( $colStr = $cols.toString().replace(\\"[\\",\\"(\\").replace(\\"]\\",\\")\\") ) -{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"INSERT INTO Tomatoes $colStr VALUES $valStr\\", \\"SELECT * FROM Tomatoes WHERE Id=:Id\\"], - \\"variableMap\\": $util.toJson($variableMap) -}" -`; - -exports[`verify generated templates 3`] = `"testFilePath/Mutation.createTomatoes.res.vtl"`; - -exports[`verify generated templates 4`] = `"$utils.toJson($utils.parseJson($utils.rds.toJsonString($ctx.result))[1][0])"`; - -exports[`verify generated templates 5`] = `"testFilePath/Query.getTomatoes.req.vtl"`; - -exports[`verify generated templates 6`] = ` -"#set( $variableMap = {} ) -$util.qr($variableMap.put(\\":Id\\", \\"$ctx.args.Id\\")) -{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"SELECT * FROM Tomatoes WHERE Id=:Id\\"], - \\"variableMap\\": $util.toJson($variableMap) -}" -`; - -exports[`verify generated templates 7`] = `"testFilePath/Query.getTomatoes.res.vtl"`; - -exports[`verify generated templates 8`] = ` -"#set( $output = $utils.rds.toJsonObject($ctx.result) ) -#if( $output.isEmpty() ) - $util.error(\\"Invalid response from RDS DataSource. See info for the full response.\\", \\"InvalidResponse\\", {}, $output) -#end -#set( $output = $output[0] ) -#if( $output.isEmpty() ) - #return -#end -$utils.toJson($output[0])" -`; - -exports[`verify generated templates 9`] = `"testFilePath/Mutation.updateTomatoes.req.vtl"`; - -exports[`verify generated templates 10`] = ` -"#set( $updateList = {} ) -#set( $variableMap = {} ) -#foreach( $entry in $ctx.args.updateTomatoesInput.keySet() ) - $util.qr($variableMap.put(\\":$entry\\", $ctx.args.updateTomatoesInput[$entry])) - #set( $discard = $updateList.put($entry, \\":$entry\\") ) -#end -#set( $update = $updateList.toString().replace(\\"{\\",\\"\\").replace(\\"}\\",\\"\\") ) -{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"UPDATE Tomatoes SET $update WHERE Id=:Id\\", \\"SELECT * FROM Tomatoes WHERE Id=:Id\\"], - \\"variableMap\\": $util.toJson($variableMap) -}" -`; - -exports[`verify generated templates 11`] = `"testFilePath/Mutation.updateTomatoes.res.vtl"`; - -exports[`verify generated templates 12`] = ` -"#set( $output = $utils.rds.toJsonObject($ctx.result) ) -#if( $output.length() < 2 ) - $util.error(\\"Invalid response from RDS DataSource. See info for the full response.\\", \\"InvalidResponse\\", {}, $output) -#end -#set( $output = $output[1] ) -#if( $output.isEmpty() ) - #return -#end -$utils.toJson($output[0])" -`; - -exports[`verify generated templates 13`] = `"testFilePath/Mutation.deleteTomatoes.req.vtl"`; - -exports[`verify generated templates 14`] = ` -"#set( $variableMap = {} ) -$util.qr($variableMap.put(\\":Id\\", \\"$ctx.args.Id\\")) -{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"SELECT * FROM Tomatoes WHERE Id=:Id\\", \\"DELETE FROM Tomatoes WHERE Id=:Id\\"], - \\"variableMap\\": $util.toJson($variableMap) -}" -`; - -exports[`verify generated templates 15`] = `"testFilePath/Mutation.deleteTomatoes.res.vtl"`; - -exports[`verify generated templates 16`] = ` -"#set( $output = $utils.rds.toJsonObject($ctx.result) ) -#if( $output.isEmpty() ) - $util.error(\\"Invalid response from RDS DataSource. See info for the full response.\\", \\"InvalidResponse\\", {}, $output) -#end -#set( $output = $output[0] ) -#if( $output.isEmpty() ) - #return -#end -$utils.toJson($output[0])" -`; - -exports[`verify generated templates 17`] = `"testFilePath/Query.listTomatoes.req.vtl"`; - -exports[`verify generated templates 18`] = ` -"{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"SELECT * FROM Tomatoes\\"], - \\"variableMap\\": {} -}" -`; - -exports[`verify generated templates 19`] = `"testFilePath/Query.listTomatoes.res.vtl"`; - -exports[`verify generated templates 20`] = `"$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])"`; - -exports[`verify generated templates using a Int primary key 1`] = `"testFilePath/Mutation.createApples.req.vtl"`; - -exports[`verify generated templates using a Int primary key 2`] = ` -"#set( $cols = [] ) -#set( $vals = [] ) -#set( $variableMap = {} ) -#foreach( $entry in $ctx.args.createApplesInput.keySet() ) - #set( $discard = $cols.add($entry) ) - #set( $discard = $vals.add(\\":$entry\\") ) - $util.qr($variableMap.put(\\":$entry\\", $ctx.args.createApplesInput[$entry])) -#end -#set( $valStr = $vals.toString().replace(\\"[\\",\\"(\\").replace(\\"]\\",\\")\\") ) -#set( $colStr = $cols.toString().replace(\\"[\\",\\"(\\").replace(\\"]\\",\\")\\") ) -{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"INSERT INTO Apples $colStr VALUES $valStr\\", \\"SELECT * FROM Apples WHERE Id=:Id\\"], - \\"variableMap\\": $util.toJson($variableMap) -}" -`; - -exports[`verify generated templates using a Int primary key 3`] = `"testFilePath/Mutation.createApples.res.vtl"`; - -exports[`verify generated templates using a Int primary key 4`] = `"$utils.toJson($utils.parseJson($utils.rds.toJsonString($ctx.result))[1][0])"`; - -exports[`verify generated templates using a Int primary key 5`] = `"testFilePath/Query.getApples.req.vtl"`; - -exports[`verify generated templates using a Int primary key 6`] = ` -"#set( $variableMap = {} ) -$util.qr($variableMap.put(\\":Id\\", $ctx.args.Id)) -{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"SELECT * FROM Apples WHERE Id=:Id\\"], - \\"variableMap\\": $util.toJson($variableMap) -}" -`; - -exports[`verify generated templates using a Int primary key 7`] = `"testFilePath/Query.getApples.res.vtl"`; - -exports[`verify generated templates using a Int primary key 8`] = ` -"#set( $output = $utils.rds.toJsonObject($ctx.result) ) -#if( $output.isEmpty() ) - $util.error(\\"Invalid response from RDS DataSource. See info for the full response.\\", \\"InvalidResponse\\", {}, $output) -#end -#set( $output = $output[0] ) -#if( $output.isEmpty() ) - #return -#end -$utils.toJson($output[0])" -`; - -exports[`verify generated templates using a Int primary key 9`] = `"testFilePath/Mutation.updateApples.req.vtl"`; - -exports[`verify generated templates using a Int primary key 10`] = ` -"#set( $updateList = {} ) -#set( $variableMap = {} ) -#foreach( $entry in $ctx.args.updateApplesInput.keySet() ) - $util.qr($variableMap.put(\\":$entry\\", $ctx.args.updateApplesInput[$entry])) - #set( $discard = $updateList.put($entry, \\":$entry\\") ) -#end -#set( $update = $updateList.toString().replace(\\"{\\",\\"\\").replace(\\"}\\",\\"\\") ) -{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"UPDATE Apples SET $update WHERE Id=:Id\\", \\"SELECT * FROM Apples WHERE Id=:Id\\"], - \\"variableMap\\": $util.toJson($variableMap) -}" -`; - -exports[`verify generated templates using a Int primary key 11`] = `"testFilePath/Mutation.updateApples.res.vtl"`; - -exports[`verify generated templates using a Int primary key 12`] = ` -"#set( $output = $utils.rds.toJsonObject($ctx.result) ) -#if( $output.length() < 2 ) - $util.error(\\"Invalid response from RDS DataSource. See info for the full response.\\", \\"InvalidResponse\\", {}, $output) -#end -#set( $output = $output[1] ) -#if( $output.isEmpty() ) - #return -#end -$utils.toJson($output[0])" -`; - -exports[`verify generated templates using a Int primary key 13`] = `"testFilePath/Mutation.deleteApples.req.vtl"`; - -exports[`verify generated templates using a Int primary key 14`] = ` -"#set( $variableMap = {} ) -$util.qr($variableMap.put(\\":Id\\", $ctx.args.Id)) -{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"SELECT * FROM Apples WHERE Id=:Id\\", \\"DELETE FROM Apples WHERE Id=:Id\\"], - \\"variableMap\\": $util.toJson($variableMap) -}" -`; - -exports[`verify generated templates using a Int primary key 15`] = `"testFilePath/Mutation.deleteApples.res.vtl"`; - -exports[`verify generated templates using a Int primary key 16`] = ` -"#set( $output = $utils.rds.toJsonObject($ctx.result) ) -#if( $output.isEmpty() ) - $util.error(\\"Invalid response from RDS DataSource. See info for the full response.\\", \\"InvalidResponse\\", {}, $output) -#end -#set( $output = $output[0] ) -#if( $output.isEmpty() ) - #return -#end -$utils.toJson($output[0])" -`; - -exports[`verify generated templates using a Int primary key 17`] = `"testFilePath/Query.listApples.req.vtl"`; - -exports[`verify generated templates using a Int primary key 18`] = ` -"{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"SELECT * FROM Apples\\"], - \\"variableMap\\": {} -}" -`; - -exports[`verify generated templates using a Int primary key 19`] = `"testFilePath/Query.listApples.res.vtl"`; - -exports[`verify generated templates using a Int primary key 20`] = `"$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])"`; - -exports[`verify generated templates with non-id named primary key 1`] = `"testFilePath/Mutation.createTomatoes.req.vtl"`; - -exports[`verify generated templates with non-id named primary key 2`] = ` -"#set( $cols = [] ) -#set( $vals = [] ) -#set( $variableMap = {} ) -#foreach( $entry in $ctx.args.createTomatoesInput.keySet() ) - #set( $discard = $cols.add($entry) ) - #set( $discard = $vals.add(\\":$entry\\") ) - $util.qr($variableMap.put(\\":$entry\\", $ctx.args.createTomatoesInput[$entry])) -#end -#set( $valStr = $vals.toString().replace(\\"[\\",\\"(\\").replace(\\"]\\",\\")\\") ) -#set( $colStr = $cols.toString().replace(\\"[\\",\\"(\\").replace(\\"]\\",\\")\\") ) -{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"INSERT INTO Tomatoes $colStr VALUES $valStr\\", \\"SELECT * FROM Tomatoes WHERE tomatoId=:tomatoId\\"], - \\"variableMap\\": $util.toJson($variableMap) -}" -`; - -exports[`verify generated templates with non-id named primary key 3`] = `"testFilePath/Mutation.createTomatoes.res.vtl"`; - -exports[`verify generated templates with non-id named primary key 4`] = `"$utils.toJson($utils.parseJson($utils.rds.toJsonString($ctx.result))[1][0])"`; - -exports[`verify generated templates with non-id named primary key 5`] = `"testFilePath/Query.getTomatoes.req.vtl"`; - -exports[`verify generated templates with non-id named primary key 6`] = ` -"#set( $variableMap = {} ) -$util.qr($variableMap.put(\\":tomatoId\\", \\"$ctx.args.tomatoId\\")) -{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"SELECT * FROM Tomatoes WHERE tomatoId=:tomatoId\\"], - \\"variableMap\\": $util.toJson($variableMap) -}" -`; - -exports[`verify generated templates with non-id named primary key 7`] = `"testFilePath/Query.getTomatoes.res.vtl"`; - -exports[`verify generated templates with non-id named primary key 8`] = ` -"#set( $output = $utils.rds.toJsonObject($ctx.result) ) -#if( $output.isEmpty() ) - $util.error(\\"Invalid response from RDS DataSource. See info for the full response.\\", \\"InvalidResponse\\", {}, $output) -#end -#set( $output = $output[0] ) -#if( $output.isEmpty() ) - #return -#end -$utils.toJson($output[0])" -`; - -exports[`verify generated templates with non-id named primary key 9`] = `"testFilePath/Mutation.updateTomatoes.req.vtl"`; - -exports[`verify generated templates with non-id named primary key 10`] = ` -"#set( $updateList = {} ) -#set( $variableMap = {} ) -#foreach( $entry in $ctx.args.updateTomatoesInput.keySet() ) - $util.qr($variableMap.put(\\":$entry\\", $ctx.args.updateTomatoesInput[$entry])) - #set( $discard = $updateList.put($entry, \\":$entry\\") ) -#end -#set( $update = $updateList.toString().replace(\\"{\\",\\"\\").replace(\\"}\\",\\"\\") ) -{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"UPDATE Tomatoes SET $update WHERE tomatoId=:tomatoId\\", \\"SELECT * FROM Tomatoes WHERE tomatoId=:tomatoId\\"], - \\"variableMap\\": $util.toJson($variableMap) -}" -`; - -exports[`verify generated templates with non-id named primary key 11`] = `"testFilePath/Mutation.updateTomatoes.res.vtl"`; - -exports[`verify generated templates with non-id named primary key 12`] = ` -"#set( $output = $utils.rds.toJsonObject($ctx.result) ) -#if( $output.length() < 2 ) - $util.error(\\"Invalid response from RDS DataSource. See info for the full response.\\", \\"InvalidResponse\\", {}, $output) -#end -#set( $output = $output[1] ) -#if( $output.isEmpty() ) - #return -#end -$utils.toJson($output[0])" -`; - -exports[`verify generated templates with non-id named primary key 13`] = `"testFilePath/Mutation.deleteTomatoes.req.vtl"`; - -exports[`verify generated templates with non-id named primary key 14`] = ` -"#set( $variableMap = {} ) -$util.qr($variableMap.put(\\":tomatoId\\", \\"$ctx.args.tomatoId\\")) -{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"SELECT * FROM Tomatoes WHERE tomatoId=:tomatoId\\", \\"DELETE FROM Tomatoes WHERE tomatoId=:tomatoId\\"], - \\"variableMap\\": $util.toJson($variableMap) -}" -`; - -exports[`verify generated templates with non-id named primary key 15`] = `"testFilePath/Mutation.deleteTomatoes.res.vtl"`; - -exports[`verify generated templates with non-id named primary key 16`] = ` -"#set( $output = $utils.rds.toJsonObject($ctx.result) ) -#if( $output.isEmpty() ) - $util.error(\\"Invalid response from RDS DataSource. See info for the full response.\\", \\"InvalidResponse\\", {}, $output) -#end -#set( $output = $output[0] ) -#if( $output.isEmpty() ) - #return -#end -$utils.toJson($output[0])" -`; - -exports[`verify generated templates with non-id named primary key 17`] = `"testFilePath/Query.listTomatoes.req.vtl"`; - -exports[`verify generated templates with non-id named primary key 18`] = ` -"{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"SELECT * FROM Tomatoes\\"], - \\"variableMap\\": {} -}" -`; - -exports[`verify generated templates with non-id named primary key 19`] = `"testFilePath/Query.listTomatoes.res.vtl"`; - -exports[`verify generated templates with non-id named primary key 20`] = `"$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])"`; - -exports[`verify generated templates with old pluralization 1`] = `"testFilePath/Mutation.createApples.req.vtl"`; - -exports[`verify generated templates with old pluralization 2`] = ` -"#set( $cols = [] ) -#set( $vals = [] ) -#set( $variableMap = {} ) -#foreach( $entry in $ctx.args.createApplesInput.keySet() ) - #set( $discard = $cols.add($entry) ) - #set( $discard = $vals.add(\\":$entry\\") ) - $util.qr($variableMap.put(\\":$entry\\", $ctx.args.createApplesInput[$entry])) -#end -#set( $valStr = $vals.toString().replace(\\"[\\",\\"(\\").replace(\\"]\\",\\")\\") ) -#set( $colStr = $cols.toString().replace(\\"[\\",\\"(\\").replace(\\"]\\",\\")\\") ) -{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"INSERT INTO Apples $colStr VALUES $valStr\\", \\"SELECT * FROM Apples WHERE Id=:Id\\"], - \\"variableMap\\": $util.toJson($variableMap) -}" -`; - -exports[`verify generated templates with old pluralization 3`] = `"testFilePath/Mutation.createApples.res.vtl"`; - -exports[`verify generated templates with old pluralization 4`] = `"$utils.toJson($utils.parseJson($utils.rds.toJsonString($ctx.result))[1][0])"`; - -exports[`verify generated templates with old pluralization 5`] = `"testFilePath/Query.getApples.req.vtl"`; - -exports[`verify generated templates with old pluralization 6`] = ` -"#set( $variableMap = {} ) -$util.qr($variableMap.put(\\":Id\\", $ctx.args.Id)) -{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"SELECT * FROM Apples WHERE Id=:Id\\"], - \\"variableMap\\": $util.toJson($variableMap) -}" -`; - -exports[`verify generated templates with old pluralization 7`] = `"testFilePath/Query.getApples.res.vtl"`; - -exports[`verify generated templates with old pluralization 8`] = ` -"#set( $output = $utils.rds.toJsonObject($ctx.result) ) -#if( $output.isEmpty() ) - $util.error(\\"Invalid response from RDS DataSource. See info for the full response.\\", \\"InvalidResponse\\", {}, $output) -#end -#set( $output = $output[0] ) -#if( $output.isEmpty() ) - #return -#end -$utils.toJson($output[0])" -`; - -exports[`verify generated templates with old pluralization 9`] = `"testFilePath/Mutation.updateApples.req.vtl"`; - -exports[`verify generated templates with old pluralization 10`] = ` -"#set( $updateList = {} ) -#set( $variableMap = {} ) -#foreach( $entry in $ctx.args.updateApplesInput.keySet() ) - $util.qr($variableMap.put(\\":$entry\\", $ctx.args.updateApplesInput[$entry])) - #set( $discard = $updateList.put($entry, \\":$entry\\") ) -#end -#set( $update = $updateList.toString().replace(\\"{\\",\\"\\").replace(\\"}\\",\\"\\") ) -{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"UPDATE Apples SET $update WHERE Id=:Id\\", \\"SELECT * FROM Apples WHERE Id=:Id\\"], - \\"variableMap\\": $util.toJson($variableMap) -}" -`; - -exports[`verify generated templates with old pluralization 11`] = `"testFilePath/Mutation.updateApples.res.vtl"`; - -exports[`verify generated templates with old pluralization 12`] = ` -"#set( $output = $utils.rds.toJsonObject($ctx.result) ) -#if( $output.length() < 2 ) - $util.error(\\"Invalid response from RDS DataSource. See info for the full response.\\", \\"InvalidResponse\\", {}, $output) -#end -#set( $output = $output[1] ) -#if( $output.isEmpty() ) - #return -#end -$utils.toJson($output[0])" -`; - -exports[`verify generated templates with old pluralization 13`] = `"testFilePath/Mutation.deleteApples.req.vtl"`; - -exports[`verify generated templates with old pluralization 14`] = ` -"#set( $variableMap = {} ) -$util.qr($variableMap.put(\\":Id\\", $ctx.args.Id)) -{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"SELECT * FROM Apples WHERE Id=:Id\\", \\"DELETE FROM Apples WHERE Id=:Id\\"], - \\"variableMap\\": $util.toJson($variableMap) -}" -`; - -exports[`verify generated templates with old pluralization 15`] = `"testFilePath/Mutation.deleteApples.res.vtl"`; - -exports[`verify generated templates with old pluralization 16`] = ` -"#set( $output = $utils.rds.toJsonObject($ctx.result) ) -#if( $output.isEmpty() ) - $util.error(\\"Invalid response from RDS DataSource. See info for the full response.\\", \\"InvalidResponse\\", {}, $output) -#end -#set( $output = $output[0] ) -#if( $output.isEmpty() ) - #return -#end -$utils.toJson($output[0])" -`; - -exports[`verify generated templates with old pluralization 17`] = `"testFilePath/Query.listAppless.req.vtl"`; - -exports[`verify generated templates with old pluralization 18`] = ` -"{ - \\"version\\": \\"2018-05-29\\", - \\"statements\\": [\\"SELECT * FROM Apples\\"], - \\"variableMap\\": {} -}" -`; - -exports[`verify generated templates with old pluralization 19`] = `"testFilePath/Query.listAppless.res.vtl"`; - -exports[`verify generated templates with old pluralization 20`] = `"$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])"`; diff --git a/packages/graphql-relational-schema-transformer/src/index.ts b/packages/graphql-relational-schema-transformer/src/index.ts deleted file mode 100644 index 6bca6c7361..0000000000 --- a/packages/graphql-relational-schema-transformer/src/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './RelationalDBSchemaTransformer'; -export * from './RelationalDBTemplateGenerator'; -export * from './AuroraServerlessMySQLDatabaseReader'; -export * from './AuroraDataAPIClient'; diff --git a/packages/graphql-relational-schema-transformer/tsconfig.json b/packages/graphql-relational-schema-transformer/tsconfig.json deleted file mode 100644 index 02f3ff8297..0000000000 --- a/packages/graphql-relational-schema-transformer/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "strict": false, // TODO enable - "rootDir": "src", - "outDir": "lib" - }, - "references": [ - { "path": "../amplify-graphql-directives" }, - { "path": "../graphql-mapping-template" }, - { "path": "../graphql-transformer-common" } - ] -} diff --git a/packages/graphql-versioned-transformer/.npmignore b/packages/graphql-versioned-transformer/.npmignore deleted file mode 100644 index 3ee5d55b0b..0000000000 --- a/packages/graphql-versioned-transformer/.npmignore +++ /dev/null @@ -1,5 +0,0 @@ -**/__mocks__/** -**/__tests__/** -src -tsconfig.json -tsconfig.tsbuildinfo diff --git a/packages/graphql-versioned-transformer/API.md b/packages/graphql-versioned-transformer/API.md deleted file mode 100644 index db2ba6fab1..0000000000 --- a/packages/graphql-versioned-transformer/API.md +++ /dev/null @@ -1,21 +0,0 @@ -## API Report File for "graphql-versioned-transformer" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { DirectiveNode } from 'graphql'; -import { ObjectTypeDefinitionNode } from 'graphql'; -import { Transformer as Transformer_2 } from 'graphql-transformer-core'; -import { TransformerContext } from 'graphql-transformer-core'; - -// @public (undocumented) -export class VersionedModelTransformer extends Transformer_2 { - constructor(); - // (undocumented) - object: (def: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => void; -} - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/graphql-versioned-transformer/CHANGELOG.md b/packages/graphql-versioned-transformer/CHANGELOG.md deleted file mode 100644 index d8adea86c4..0000000000 --- a/packages/graphql-versioned-transformer/CHANGELOG.md +++ /dev/null @@ -1,983 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [5.2.80](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.79...graphql-versioned-transformer@5.2.80) (2024-07-15) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.79](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.78...graphql-versioned-transformer@5.2.79) (2024-07-02) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.78](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.77...graphql-versioned-transformer@5.2.78) (2024-06-25) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.77](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.76...graphql-versioned-transformer@5.2.77) (2024-04-26) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.76](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.75...graphql-versioned-transformer@5.2.76) (2024-04-11) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.75](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.74...graphql-versioned-transformer@5.2.75) (2024-03-28) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.74](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.73...graphql-versioned-transformer@5.2.74) (2024-02-28) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.73](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.72...graphql-versioned-transformer@5.2.73) (2024-02-05) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.72](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.71...graphql-versioned-transformer@5.2.72) (2024-01-22) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.71](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.70...graphql-versioned-transformer@5.2.71) (2023-12-18) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.70](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.69...graphql-versioned-transformer@5.2.70) (2023-12-06) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.69](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.68...graphql-versioned-transformer@5.2.69) (2023-11-18) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.68](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.67...graphql-versioned-transformer@5.2.68) (2023-11-16) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.67](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.66...graphql-versioned-transformer@5.2.67) (2023-11-15) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.66](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.65...graphql-versioned-transformer@5.2.66) (2023-10-21) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.65](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.64...graphql-versioned-transformer@5.2.65) (2023-08-30) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.64](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.63...graphql-versioned-transformer@5.2.64) (2023-08-28) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.63](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.62...graphql-versioned-transformer@5.2.63) (2023-08-09) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.62](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.61...graphql-versioned-transformer@5.2.62) (2023-07-21) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.61](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.60...graphql-versioned-transformer@5.2.61) (2023-07-17) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.60](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.59...graphql-versioned-transformer@5.2.60) (2023-07-07) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.59](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.58...graphql-versioned-transformer@5.2.59) (2023-07-07) - -### Bug Fixes - -- trigger republish of dependencies that failed in https://app.circleci.com/pipelines/github/aws-amplify/amplify-category-api/7981/workflows/e7366f04-6f0a-4ee4-9cc2-1772089e8005/jobs/163571 ([f2c7151](https://github.com/aws-amplify/amplify-category-api/commit/f2c7151005e4a9fd29d91ac1af1f3e482a06a5cc)) - -## [5.2.58](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.57...graphql-versioned-transformer@5.2.58) (2023-07-07) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.57](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.56...graphql-versioned-transformer@5.2.57) (2023-06-29) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.56](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.55...graphql-versioned-transformer@5.2.56) (2023-06-20) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.55](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.54...graphql-versioned-transformer@5.2.55) (2023-06-05) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.54](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.53...graphql-versioned-transformer@5.2.54) (2023-05-23) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.53](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.52...graphql-versioned-transformer@5.2.53) (2023-05-17) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.52](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.51...graphql-versioned-transformer@5.2.52) (2023-04-25) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.51](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.50...graphql-versioned-transformer@5.2.51) (2023-03-30) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.50](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.49...graphql-versioned-transformer@5.2.50) (2023-03-15) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.49](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.48...graphql-versioned-transformer@5.2.49) (2023-03-01) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.48](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.47...graphql-versioned-transformer@5.2.48) (2023-02-27) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.47](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.46...graphql-versioned-transformer@5.2.47) (2023-01-26) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.46](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.45...graphql-versioned-transformer@5.2.46) (2023-01-12) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.45](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.44...graphql-versioned-transformer@5.2.45) (2023-01-12) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.44](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.43...graphql-versioned-transformer@5.2.44) (2022-12-03) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.43](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.42...graphql-versioned-transformer@5.2.43) (2022-09-14) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.42](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.40...graphql-versioned-transformer@5.2.42) (2022-07-20) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.41](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.40...graphql-versioned-transformer@5.2.41) (2022-07-14) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.40](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.39...graphql-versioned-transformer@5.2.40) (2022-07-01) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.39](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.38...graphql-versioned-transformer@5.2.39) (2022-06-23) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.38](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.37...graphql-versioned-transformer@5.2.38) (2022-06-13) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.37](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.36...graphql-versioned-transformer@5.2.37) (2022-06-10) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.36](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.35...graphql-versioned-transformer@5.2.36) (2022-06-10) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.35](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.32...graphql-versioned-transformer@5.2.35) (2022-06-07) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.34](https://github.com/aws-amplify/amplify-category-api/compare/graphql-versioned-transformer@5.2.32...graphql-versioned-transformer@5.2.34) (2022-05-31) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.33](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.32...graphql-versioned-transformer@5.2.33) (2022-05-02) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.32](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.31...graphql-versioned-transformer@5.2.32) (2022-04-29) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.31](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.30...graphql-versioned-transformer@5.2.31) (2022-04-27) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.30](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.29...graphql-versioned-transformer@5.2.30) (2022-04-11) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.29](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.28...graphql-versioned-transformer@5.2.29) (2022-04-07) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.28](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.27...graphql-versioned-transformer@5.2.28) (2022-03-23) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.27](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.26...graphql-versioned-transformer@5.2.27) (2022-03-17) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.26](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.25...graphql-versioned-transformer@5.2.26) (2022-03-14) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.24...graphql-versioned-transformer@5.2.25) (2022-03-07) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.23...graphql-versioned-transformer@5.2.24) (2022-02-25) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.22...graphql-versioned-transformer@5.2.23) (2022-02-15) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.18...graphql-versioned-transformer@5.2.22) (2022-02-10) - -## 7.6.19 (2022-02-08) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.17...graphql-versioned-transformer@5.2.18) (2022-02-03) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.16...graphql-versioned-transformer@5.2.17) (2022-01-31) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.15...graphql-versioned-transformer@5.2.16) (2022-01-27) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.14...graphql-versioned-transformer@5.2.15) (2022-01-23) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.13...graphql-versioned-transformer@5.2.14) (2022-01-13) - -### Bug Fixes - -- clean up missing and unused GraphQL v1 dependencies ([#9496](https://github.com/aws-amplify/amplify-cli/issues/9496)) ([fe8201b](https://github.com/aws-amplify/amplify-cli/commit/fe8201be17f42db233fce0bb366ff4d0c8358ec0)) - -## [5.2.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.11...graphql-versioned-transformer@5.2.13) (2022-01-10) - -## 7.6.7 (2022-01-10) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.10...graphql-versioned-transformer@5.2.11) (2021-12-21) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.9...graphql-versioned-transformer@5.2.10) (2021-12-17) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.8...graphql-versioned-transformer@5.2.9) (2021-12-03) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.7...graphql-versioned-transformer@5.2.8) (2021-12-02) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.6...graphql-versioned-transformer@5.2.7) (2021-12-01) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.5...graphql-versioned-transformer@5.2.6) (2021-11-26) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.4...graphql-versioned-transformer@5.2.5) (2021-11-23) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.3...graphql-versioned-transformer@5.2.4) (2021-11-21) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.2...graphql-versioned-transformer@5.2.3) (2021-11-20) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@5.2.1...graphql-versioned-transformer@5.2.2) (2021-11-17) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [5.2.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.26...graphql-versioned-transformer@5.2.1) (2021-11-15) - -**Note:** Version bump only for package graphql-versioned-transformer - -# [5.0.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.26...graphql-versioned-transformer@5.0.0) (2021-11-13) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.26](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.25...graphql-versioned-transformer@4.17.26) (2021-11-11) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.24...graphql-versioned-transformer@4.17.25) (2021-10-10) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.23...graphql-versioned-transformer@4.17.24) (2021-10-06) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.22...graphql-versioned-transformer@4.17.23) (2021-09-27) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.21...graphql-versioned-transformer@4.17.22) (2021-09-18) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.21](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.20...graphql-versioned-transformer@4.17.21) (2021-09-14) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.20](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.19...graphql-versioned-transformer@4.17.20) (2021-09-09) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.19](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.18...graphql-versioned-transformer@4.17.19) (2021-09-02) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.17...graphql-versioned-transformer@4.17.18) (2021-08-24) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.16...graphql-versioned-transformer@4.17.17) (2021-08-06) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.15...graphql-versioned-transformer@4.17.16) (2021-07-30) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.14...graphql-versioned-transformer@4.17.15) (2021-07-27) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.13...graphql-versioned-transformer@4.17.14) (2021-07-16) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.12...graphql-versioned-transformer@4.17.13) (2021-06-30) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.11...graphql-versioned-transformer@4.17.12) (2021-06-24) - -### Bug Fixes - -- **graphql-transformer-common:** improve generated graphql pluralization ([#7258](https://github.com/aws-amplify/amplify-cli/issues/7258)) ([fc3ad0d](https://github.com/aws-amplify/amplify-cli/commit/fc3ad0dd5a12a7912c59ae12024f593b4cdf7f2d)), closes [#4224](https://github.com/aws-amplify/amplify-cli/issues/4224) - -## [4.17.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.10...graphql-versioned-transformer@4.17.11) (2021-06-15) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.9...graphql-versioned-transformer@4.17.10) (2021-05-29) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.8...graphql-versioned-transformer@4.17.9) (2021-05-26) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.7...graphql-versioned-transformer@4.17.8) (2021-05-18) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.6...graphql-versioned-transformer@4.17.7) (2021-05-14) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.4...graphql-versioned-transformer@4.17.6) (2021-05-03) - -## 4.50.1 (2021-05-03) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.4...graphql-versioned-transformer@4.17.5) (2021-05-03) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.3...graphql-versioned-transformer@4.17.4) (2021-04-27) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.2...graphql-versioned-transformer@4.17.3) (2021-04-19) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.17.1...graphql-versioned-transformer@4.17.2) (2021-04-14) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.17.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.16.12...graphql-versioned-transformer@4.17.1) (2021-04-09) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.16.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.16.11...graphql-versioned-transformer@4.16.12) (2021-03-23) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.16.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.16.10...graphql-versioned-transformer@4.16.11) (2021-03-11) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.16.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.16.9...graphql-versioned-transformer@4.16.10) (2021-03-05) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.16.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.16.8...graphql-versioned-transformer@4.16.9) (2021-02-26) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.16.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.16.7...graphql-versioned-transformer@4.16.8) (2021-02-24) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.16.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.16.6...graphql-versioned-transformer@4.16.7) (2021-02-17) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.16.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.16.5...graphql-versioned-transformer@4.16.6) (2021-02-11) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.16.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.16.4...graphql-versioned-transformer@4.16.5) (2021-02-10) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.16.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.16.3...graphql-versioned-transformer@4.16.4) (2020-12-16) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.16.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.16.2...graphql-versioned-transformer@4.16.3) (2020-12-07) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.16.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.16.1...graphql-versioned-transformer@4.16.2) (2020-11-30) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.16.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.25...graphql-versioned-transformer@4.16.1) (2020-11-22) - -**Note:** Version bump only for package graphql-versioned-transformer - -# [4.16.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.4.12...graphql-versioned-transformer@4.16.0) (2020-11-22) - -### Bug Fixes - -- build break, chore: typescript, lerna update ([#2640](https://github.com/aws-amplify/amplify-cli/issues/2640)) ([29fae36](https://github.com/aws-amplify/amplify-cli/commit/29fae366f4cab054feefa58c7dc733002d19570c)) -- export Typescript definitions and fix resulting type errors ([#2452](https://github.com/aws-amplify/amplify-cli/issues/2452)) ([7de3845](https://github.com/aws-amplify/amplify-cli/commit/7de384594d3b9cbf22cdaa85107fc8df26c141ec)), closes [#2451](https://github.com/aws-amplify/amplify-cli/issues/2451) -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c1927da10f8c54f38a523021187361131c)) - -## [4.15.28](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.25...graphql-versioned-transformer@4.15.28) (2020-11-20) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.27](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.25...graphql-versioned-transformer@4.15.27) (2020-11-20) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.26](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.25...graphql-versioned-transformer@4.15.26) (2020-11-19) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.25](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.24...graphql-versioned-transformer@4.15.25) (2020-11-08) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.24](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.23...graphql-versioned-transformer@4.15.24) (2020-10-30) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.23](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.22...graphql-versioned-transformer@4.15.23) (2020-10-22) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.22](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.21...graphql-versioned-transformer@4.15.22) (2020-10-17) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.21](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.20...graphql-versioned-transformer@4.15.21) (2020-10-01) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.20](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.19...graphql-versioned-transformer@4.15.20) (2020-09-16) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.19](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.18...graphql-versioned-transformer@4.15.19) (2020-09-02) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.18](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.17...graphql-versioned-transformer@4.15.18) (2020-08-31) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.17](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.16...graphql-versioned-transformer@4.15.17) (2020-08-14) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.16](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.15...graphql-versioned-transformer@4.15.16) (2020-08-11) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.15](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.13...graphql-versioned-transformer@4.15.15) (2020-07-29) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.14](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.13...graphql-versioned-transformer@4.15.14) (2020-07-23) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.13](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.12...graphql-versioned-transformer@4.15.13) (2020-07-18) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.11...graphql-versioned-transformer@4.15.12) (2020-07-15) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.10...graphql-versioned-transformer@4.15.11) (2020-06-25) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.9...graphql-versioned-transformer@4.15.10) (2020-06-18) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.8...graphql-versioned-transformer@4.15.9) (2020-06-11) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.7...graphql-versioned-transformer@4.15.8) (2020-06-10) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.6...graphql-versioned-transformer@4.15.7) (2020-06-02) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.5...graphql-versioned-transformer@4.15.6) (2020-05-26) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.4...graphql-versioned-transformer@4.15.5) (2020-05-15) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.3...graphql-versioned-transformer@4.15.4) (2020-05-08) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.2...graphql-versioned-transformer@4.15.3) (2020-04-23) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.15.1...graphql-versioned-transformer@4.15.2) (2020-03-22) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.15.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.13.4...graphql-versioned-transformer@4.15.1) (2020-03-07) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.14.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.13.6-beta.0...graphql-versioned-transformer@4.14.1) (2020-03-05) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.13.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.13.3...graphql-versioned-transformer@4.13.4) (2020-02-18) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.13.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.13.2...graphql-versioned-transformer@4.13.3) (2020-02-13) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.13.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.13.1...graphql-versioned-transformer@4.13.2) (2020-02-07) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [4.13.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@4.13.0...graphql-versioned-transformer@4.13.1) (2020-01-24) - -**Note:** Version bump only for package graphql-versioned-transformer - -# [4.13.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.28.0...graphql-versioned-transformer@4.13.0) (2020-01-23) - -### Bug Fixes - -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.12.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.28.0...graphql-versioned-transformer@4.12.0) (2020-01-09) - -### Bug Fixes - -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.11.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.28.0...graphql-versioned-transformer@4.11.0) (2019-12-31) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.10.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.28.0...graphql-versioned-transformer@4.10.0) (2019-12-28) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.9.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.28.0...graphql-versioned-transformer@4.9.0) (2019-12-26) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.8.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.28.0...graphql-versioned-transformer@4.8.0) (2019-12-25) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.7.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.28.0...graphql-versioned-transformer@4.7.0) (2019-12-20) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.6.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.28.0...graphql-versioned-transformer@4.6.0) (2019-12-10) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.4.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.28.0...graphql-versioned-transformer@4.4.0) (2019-12-03) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.3.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.28.0...graphql-versioned-transformer@4.3.0) (2019-12-01) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.2.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.28.0...graphql-versioned-transformer@4.2.0) (2019-11-27) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [4.1.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.28.0...graphql-versioned-transformer@4.1.0) (2019-11-27) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [3.10.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.4.12...graphql-versioned-transformer@3.10.0) (2019-08-30) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.9.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.4.12...graphql-versioned-transformer@3.9.0) (2019-08-28) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.8.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.4.12...graphql-versioned-transformer@3.8.0) (2019-08-13) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.7.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.4.12...graphql-versioned-transformer@3.7.0) (2019-08-07) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.6.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.4.12...graphql-versioned-transformer@3.6.0) (2019-08-02) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -# [3.5.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.4.12...graphql-versioned-transformer@3.5.0) (2019-07-31) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) - -## [3.4.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.4.11...graphql-versioned-transformer@3.4.12) (2019-07-24) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.4.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.4.9...graphql-versioned-transformer@3.4.11) (2019-06-30) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.4.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.4.8...graphql-versioned-transformer@3.4.9) (2019-06-26) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.4.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.4.7...graphql-versioned-transformer@3.4.8) (2019-06-12) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.4.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.4.6...graphql-versioned-transformer@3.4.7) (2019-05-29) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.4.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.4.5...graphql-versioned-transformer@3.4.6) (2019-05-21) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.4.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.4.4...graphql-versioned-transformer@3.4.5) (2019-05-17) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.4.4](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.4.2...graphql-versioned-transformer@3.4.4) (2019-05-07) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.4.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.4.2...graphql-versioned-transformer@3.4.3) (2019-05-06) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.4.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.4.1...graphql-versioned-transformer@3.4.2) (2019-04-16) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.4.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.3.1...graphql-versioned-transformer@3.4.1) (2019-04-09) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.3.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.0.9...graphql-versioned-transformer@3.3.1) (2019-04-03) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.0.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.0.8...graphql-versioned-transformer@3.0.9) (2019-03-22) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.0.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.0.7...graphql-versioned-transformer@3.0.8) (2019-03-05) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.0.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.0.6...graphql-versioned-transformer@3.0.7) (2019-02-20) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.0.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.0.5...graphql-versioned-transformer@3.0.6) (2019-02-12) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.0.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.0.3-beta.0...graphql-versioned-transformer@3.0.5) (2019-02-11) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.0.3](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.0.3-beta.0...graphql-versioned-transformer@3.0.3) (2019-02-11) - -**Note:** Version bump only for package graphql-versioned-transformer - -## [3.0.3-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@3.0.2...graphql-versioned-transformer@3.0.3-beta.0) (2019-02-11) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -# [2.0.0-multienv.2](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.34-multienv.1...graphql-versioned-transformer@2.0.0-multienv.2) (2018-12-31) - -### Bug Fixes - -- update grahql transformer package versions for multienv ([8b4b2bd](https://github.com/aws-amplify/amplify-cli/commit/8b4b2bd)) - - - -## [1.0.34-multienv.1](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.34-multienv.0...graphql-versioned-transformer@1.0.34-multienv.1) (2018-12-19) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## [1.0.34-multienv.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.33...graphql-versioned-transformer@1.0.34-multienv.0) (2018-11-16) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## [1.0.33](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.33-beta.0...graphql-versioned-transformer@1.0.33) (2018-11-09) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## [1.0.33-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.12...graphql-versioned-transformer@1.0.33-beta.0) (2018-11-09) - -### Bug Fixes - -- **graphql-versioned-transformer:** Remove unused imports ([0975ad1](https://github.com/aws-amplify/amplify-cli/commit/0975ad1)) - - - -## [1.0.32](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.32-beta.0...graphql-versioned-transformer@1.0.32) (2018-11-05) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## [1.0.32-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.12...graphql-versioned-transformer@1.0.32-beta.0) (2018-11-05) - -### Bug Fixes - -- **graphql-versioned-transformer:** Remove unused imports ([0975ad1](https://github.com/aws-amplify/amplify-cli/commit/0975ad1)) - - - -## [1.0.31](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.12...graphql-versioned-transformer@1.0.31) (2018-11-02) - -### Bug Fixes - -- **graphql-versioned-transformer:** Remove unused imports ([0975ad1](https://github.com/aws-amplify/amplify-cli/commit/0975ad1)) - - - -## [1.0.30](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.30-beta.0...graphql-versioned-transformer@1.0.30) (2018-11-02) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## [1.0.30-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.12...graphql-versioned-transformer@1.0.30-beta.0) (2018-11-02) - -### Bug Fixes - -- **graphql-versioned-transformer:** Remove unused imports ([0975ad1](https://github.com/aws-amplify/amplify-cli/commit/0975ad1)) - - - -## [1.0.29](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.29-beta.0...graphql-versioned-transformer@1.0.29) (2018-10-23) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## [1.0.29-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.12...graphql-versioned-transformer@1.0.29-beta.0) (2018-10-23) - -### Bug Fixes - -- **graphql-versioned-transformer:** Remove unused imports ([0975ad1](https://github.com/aws-amplify/amplify-cli/commit/0975ad1)) - - - -## [1.0.28](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.28-beta.0...graphql-versioned-transformer@1.0.28) (2018-10-18) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## [1.0.28-beta.0](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.12...graphql-versioned-transformer@1.0.28-beta.0) (2018-10-12) - -### Bug Fixes - -- **graphql-versioned-transformer:** Remove unused imports ([0975ad1](https://github.com/aws-amplify/amplify-cli/commit/0975ad1)) - - - -## [1.0.12](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.11...graphql-versioned-transformer@1.0.12) (2018-08-23) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## [1.0.11](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.10...graphql-versioned-transformer@1.0.11) (2018-08-23) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## [1.0.10](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.9...graphql-versioned-transformer@1.0.10) (2018-08-23) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## [1.0.9](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.8...graphql-versioned-transformer@1.0.9) (2018-08-23) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## [1.0.8](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.7...graphql-versioned-transformer@1.0.8) (2018-08-23) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## [1.0.7](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.6...graphql-versioned-transformer@1.0.7) (2018-08-23) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## [1.0.6](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.5...graphql-versioned-transformer@1.0.6) (2018-08-23) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## [1.0.5](https://github.com/aws-amplify/amplify-cli/compare/graphql-versioned-transformer@1.0.4...graphql-versioned-transformer@1.0.5) (2018-08-23) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## 1.0.4 (2018-08-23) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## 1.0.3 (2018-08-23) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## 1.0.2 (2018-08-23) - -**Note:** Version bump only for package graphql-versioned-transformer - - - -## 1.0.1 (2018-08-23) - -**Note:** Version bump only for package graphql-versioned-transformer diff --git a/packages/graphql-versioned-transformer/package.json b/packages/graphql-versioned-transformer/package.json deleted file mode 100644 index e23aca406d..0000000000 --- a/packages/graphql-versioned-transformer/package.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "name": "graphql-versioned-transformer", - "version": "5.2.80", - "description": "A GraphQL transform that enabled object versioning and conflict resolution for a @model type.", - "repository": { - "type": "git", - "url": "https://github.com/aws-amplify/amplify-category-api.git", - "directory": "packages/graphql-versioned-transformer" - }, - "author": "Amazon Web Services", - "license": "Apache-2.0", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "keywords": [ - "graphql", - "appsync", - "aws" - ], - "scripts": { - "test": "jest", - "build": "tsc", - "clean": "rimraf ./lib", - "extract-api": "ts-node ../../scripts/extract-api.ts" - }, - "dependencies": { - "graphql": "^15.5.0", - "graphql-mapping-template": "4.20.16", - "graphql-transformer-common": "4.31.1", - "graphql-transformer-core": "8.2.13" - }, - "devDependencies": { - "graphql-dynamodb-transformer": "7.2.80" - }, - "jest": { - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, - "testURL": "http://localhost", - "testRegex": "(src/__tests__/.*.test.*)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], - "collectCoverage": true, - "coverageProvider": "v8", - "coverageThreshold": { - "global": { - "branches": 85, - "functions": 90, - "lines": 90 - } - }, - "coverageReporters": [ - "clover", - "text" - ], - "collectCoverageFrom": [ - "src/**/*.ts" - ], - "coveragePathIgnorePatterns": [ - "/__tests__/" - ] - } -} diff --git a/packages/graphql-versioned-transformer/src/VersionedModelTransformer.ts b/packages/graphql-versioned-transformer/src/VersionedModelTransformer.ts deleted file mode 100644 index 7cf4b4a87d..0000000000 --- a/packages/graphql-versioned-transformer/src/VersionedModelTransformer.ts +++ /dev/null @@ -1,213 +0,0 @@ -import { Transformer, TransformerContext, InvalidDirectiveError, TransformerContractError } from 'graphql-transformer-core'; -import { VersionedDirectiveV1 } from '@aws-amplify/graphql-directives'; -import { valueFromASTUntyped, ArgumentNode, ObjectTypeDefinitionNode, DirectiveNode, Kind, parse } from 'graphql'; -import { printBlock, compoundExpression, set, ref, qref, obj, str, raw } from 'graphql-mapping-template'; -import { - ResourceConstants, - ModelResourceIDs, - ResolverResourceIDs, - makeInputValueDefinition, - makeNonNullType, - makeNamedType, - getBaseType, - makeField, -} from 'graphql-transformer-common'; - -export class VersionedModelTransformer extends Transformer { - constructor() { - super('VersionedModelTransformer', parse(VersionedDirectiveV1.definition)); - } - - /** - * When a type is annotated with @versioned enable conflict resolution for the type. - * - * Usage: - * - * type Post @model @versioned(versionField: "version", versionInput: "expectedVersion") { - * id: ID! - * title: String - * version: Int! - * } - * - * Enabling conflict resolution automatically manages a "version" attribute in - * the @model type's DynamoDB table and injects a conditional expression into - * the types mutations that actually perform the conflict resolutions by - * checking the "version" attribute in the table with the "expectedVersion" passed - * by the user. - */ - public object = (def: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext): void => { - // @versioned may only be used on types that are also @model - const modelDirective = def.directives.find((dir) => dir.name.value === 'model'); - if (!modelDirective) { - throw new InvalidDirectiveError('Types annotated with @versioned must also be annotated with @model.'); - } - - const isArg = (s: string) => (arg: ArgumentNode) => arg.name.value === s; - const getArg = (arg: string, dflt?: any) => { - const argument = directive.arguments.find(isArg(arg)); - return argument ? valueFromASTUntyped(argument.value) : dflt; - }; - - const versionField = getArg('versionField', 'version'); - const versionInput = getArg('versionInput', 'expectedVersion'); - const typeName = def.name.value; - - // Make the necessary changes to the context - this.augmentCreateMutation(ctx, typeName, versionField, versionInput); - this.augmentUpdateMutation(ctx, typeName, versionField, versionInput); - this.augmentDeleteMutation(ctx, typeName, versionField, versionInput); - this.stripCreateInputVersionedField(ctx, typeName, versionField); - this.addVersionedInputToDeleteInput(ctx, typeName, versionInput); - this.addVersionedInputToUpdateInput(ctx, typeName, versionInput); - this.enforceVersionedFieldOnType(ctx, typeName, versionField); - }; - - /** - * Set the "version" to 1 - * @param ctx - * @param versionField - * @param versionInput - */ - private augmentCreateMutation(ctx: TransformerContext, typeName: string, versionField: string, versionInput: string) { - const snippet = printBlock(`Setting "${versionField}" to 1`)(qref(`$ctx.args.input.put("${versionField}", 1)`)); - const mutationResolverLogicalId = ResolverResourceIDs.DynamoDBCreateResolverResourceID(typeName); - const resolver = ctx.getResource(mutationResolverLogicalId); - if (resolver) { - resolver.Properties.RequestMappingTemplate = snippet + '\n\n' + resolver.Properties.RequestMappingTemplate; - ctx.setResource(mutationResolverLogicalId, resolver); - } - } - - /** - * Prefix the update operation with a conditional expression that checks - * the object versions. - * @param ctx - * @param versionField - * @param versionInput - */ - private augmentDeleteMutation(ctx: TransformerContext, typeName: string, versionField: string, versionInput: string) { - const mutationResolverLogicalId = ResolverResourceIDs.DynamoDBDeleteResolverResourceID(typeName); - const snippet = printBlock(`Inject @versioned condition.`)( - compoundExpression([ - set( - ref(ResourceConstants.SNIPPETS.VersionedCondition), - obj({ - expression: str(`#${versionField} = :${versionInput}`), - expressionValues: obj({ - [`:${versionInput}`]: raw(`$util.dynamodb.toDynamoDB($ctx.args.input.${versionInput})`), - }), - expressionNames: obj({ - [`#${versionField}`]: str(`${versionField}`), - }), - }), - ), - qref(`$ctx.args.input.remove("${versionInput}")`), - ]), - ); - const resolver = ctx.getResource(mutationResolverLogicalId); - if (resolver) { - resolver.Properties.RequestMappingTemplate = snippet + '\n\n' + resolver.Properties.RequestMappingTemplate; - ctx.setResource(mutationResolverLogicalId, resolver); - } - } - - private augmentUpdateMutation(ctx: TransformerContext, typeName: string, versionField: string, versionInput: string) { - const mutationResolverLogicalId = ResolverResourceIDs.DynamoDBUpdateResolverResourceID(typeName); - const snippet = printBlock(`Inject @versioned condition.`)( - compoundExpression([ - set( - ref(ResourceConstants.SNIPPETS.VersionedCondition), - obj({ - expression: str(`#${versionField} = :${versionInput}`), - expressionValues: obj({ - [`:${versionInput}`]: raw(`$util.dynamodb.toDynamoDB($ctx.args.input.${versionInput})`), - }), - expressionNames: obj({ - [`#${versionField}`]: str(`${versionField}`), - }), - }), - ), - set(ref('newVersion'), raw(`$ctx.args.input.${versionInput} + 1`)), - qref(`$ctx.args.input.put("${versionField}", $newVersion)`), - qref(`$ctx.args.input.remove("${versionInput}")`), - ]), - ); - const resolver = ctx.getResource(mutationResolverLogicalId); - if (resolver) { - resolver.Properties.RequestMappingTemplate = snippet + '\n\n' + resolver.Properties.RequestMappingTemplate; - ctx.setResource(mutationResolverLogicalId, resolver); - } - } - - private stripCreateInputVersionedField(ctx: TransformerContext, typeName: string, versionField: string) { - const createInputName = ModelResourceIDs.ModelCreateInputObjectName(typeName); - const input = ctx.getType(createInputName); - if (input && input.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION) { - const updatedFields = input.fields.filter((f) => f.name.value !== versionField); - if (updatedFields.length === 0) { - throw new InvalidDirectiveError( - `After stripping away version field "${versionField}", \ - the create input for type "${typeName}" cannot be created \ - with 0 fields. Add another field to type "${typeName}" to continue.`, - ); - } - const updatedInput = { - ...input, - fields: updatedFields, - }; - ctx.putType(updatedInput); - } - } - - private addVersionedInputToUpdateInput(ctx: TransformerContext, typeName: string, versionInput: string) { - return this.addVersionedInputToInput(ctx, ModelResourceIDs.ModelUpdateInputObjectName(typeName), versionInput); - } - - private addVersionedInputToDeleteInput(ctx: TransformerContext, typeName: string, versionInput: string) { - return this.addVersionedInputToInput(ctx, ModelResourceIDs.ModelDeleteInputObjectName(typeName), versionInput); - } - - private addVersionedInputToInput(ctx: TransformerContext, inputName: string, versionInput: string) { - const input = ctx.getType(inputName); - if (input && input.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION) { - const updatedFields = [...input.fields, makeInputValueDefinition(versionInput, makeNonNullType(makeNamedType('Int')))]; - const updatedInput = { - ...input, - fields: updatedFields, - }; - ctx.putType(updatedInput); - } - } - - private enforceVersionedFieldOnType(ctx: TransformerContext, typeName: string, versionField: string) { - const type = ctx.getType(typeName); - if (type && type.kind === Kind.OBJECT_TYPE_DEFINITION) { - let updatedFields = type.fields; - const versionFieldImpl = type.fields.find((f) => f.name.value === versionField); - let updatedField = versionFieldImpl; - if (versionFieldImpl) { - const baseType = getBaseType(versionFieldImpl.type); - if (baseType === 'Int' || baseType === 'BigInt') { - // ok. - if (versionFieldImpl.type.kind !== Kind.NON_NULL_TYPE) { - updatedField = { - ...updatedField, - type: makeNonNullType(versionFieldImpl.type), - }; - updatedFields = updatedFields.map((f) => (f.name.value === versionField ? updatedField : f)); - } - } else { - throw new TransformerContractError(`The versionField "${versionField}" is required to be of type "Int" or "BigInt".`); - } - } else { - updatedField = makeField(versionField, [], makeNonNullType(makeNamedType('Int'))); - updatedFields = [...updatedFields, updatedField]; - } - const updatedType = { - ...type, - fields: updatedFields, - }; - ctx.putType(updatedType); - } - } -} diff --git a/packages/graphql-versioned-transformer/src/__tests__/VersionedModelTransformer.test.ts b/packages/graphql-versioned-transformer/src/__tests__/VersionedModelTransformer.test.ts deleted file mode 100644 index 4cfaac900c..0000000000 --- a/packages/graphql-versioned-transformer/src/__tests__/VersionedModelTransformer.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { ObjectTypeDefinitionNode, parse, DocumentNode, Kind, InputObjectTypeDefinitionNode } from 'graphql'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { VersionedModelTransformer } from '../VersionedModelTransformer'; - -const getInputType = - (schemaDoc: DocumentNode) => - (name: string): InputObjectTypeDefinitionNode => - schemaDoc.definitions.find( - (d) => d.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION && d.name.value === name, - ) as InputObjectTypeDefinitionNode; -const getInputField = (input: InputObjectTypeDefinitionNode, field: string) => input.fields.find((f) => f.name.value === field); -const getType = - (schemaDoc: DocumentNode) => - (name: string): ObjectTypeDefinitionNode => - schemaDoc.definitions.find((d) => d.kind === Kind.OBJECT_TYPE_DEFINITION && d.name.value === name) as ObjectTypeDefinitionNode; -const getField = (input: ObjectTypeDefinitionNode, field: string) => input.fields.find((f) => f.name.value === field); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -test('VersionedModelTransformer validation happy case', () => { - const validSchema = ` - type Post @model @versioned { - id: ID! - title: String! - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new VersionedModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - // tslint:disable-next-line - const schemaDoc = parse(out.schema); - - expect(out).toBeDefined(); - expect(getField(getType(schemaDoc)('Post'), 'version')).toBeDefined(); - expect(getInputField(getInputType(schemaDoc)('CreatePostInput'), 'version')).toBeUndefined(); - expect(getInputField(getInputType(schemaDoc)('UpdatePostInput'), 'expectedVersion')).toBeDefined(); - expect(getInputField(getInputType(schemaDoc)('DeletePostInput'), 'expectedVersion')).toBeDefined(); - // Use e2e tests to test resolver logic. -}); - -test('VersionedModelTransformer validation fails when provided version field of wrong type.', () => { - const validSchema = ` - type Post @model @versioned { - id: ID! - title: String! - version: String! - createdAt: String - updatedAt: String - } - `; - try { - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new VersionedModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - } catch (e) { - expect(e.name).toEqual('TransformerContractError'); - } -}); - -test('VersionedModelTransformer version field replaced by non-null if provided as nullable.', () => { - const validSchema = ` - type Post @model @versioned { - id: ID! - title: String! - version: Int - createdAt: String - updatedAt: String - } - `; - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new VersionedModelTransformer()], - featureFlags, - }); - const out = transformer.transform(validSchema); - const sdl = out.schema; - const schemaDoc = parse(sdl); - const versionField = getField(getType(schemaDoc)('Post'), 'version'); - expect(versionField).toBeDefined(); - expect(versionField.type.kind).toEqual(Kind.NON_NULL_TYPE); -}); diff --git a/packages/graphql-versioned-transformer/src/index.ts b/packages/graphql-versioned-transformer/src/index.ts deleted file mode 100644 index 7e0fe30f82..0000000000 --- a/packages/graphql-versioned-transformer/src/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './VersionedModelTransformer'; - -// No-op change to trigger publish diff --git a/packages/graphql-versioned-transformer/tsconfig.json b/packages/graphql-versioned-transformer/tsconfig.json deleted file mode 100644 index f3fc268a32..0000000000 --- a/packages/graphql-versioned-transformer/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "strict": false, // TODO enable - "rootDir": "src", - "outDir": "lib" - }, - "references": [ - { "path": "../amplify-graphql-directives" }, - { "path": "../graphql-mapping-template" }, - { "path": "../graphql-transformer-common" }, - { "path": "../graphql-transformer-core" } - ] -} From 2ca1ca88e0ca08933de82d69069f4cc3be5f4396 Mon Sep 17 00:00:00 2001 From: Doesnt Matter Date: Mon, 5 Aug 2024 18:56:05 -0700 Subject: [PATCH 13/23] chore: remove V1 transformer tests --- .gitignore | 3 - .prettierignore | 2 - codebuild_specs/e2e_workflow.yml | 431 +- dependency_licenses.txt | 3829 +++-------------- .../api.connection.migration.test.ts | 63 - .../api.connection.migration2.test.ts | 61 - .../migration/api.key.migration1.test.ts | 100 - .../migration/api.key.migration2.test.ts | 58 - .../migration/api.key.migration3.test.ts | 66 - .../migration/api.key.migration4.test.ts | 57 - .../migration/api.key.migration5.test.ts | 68 - .../src/__tests__/schema-connection.test.ts | 46 - .../src/__tests__/schema-key.test.ts | 44 - .../src/__tests__/schema-versioned.test.ts | 21 - .../auth-migration.test.ts | 275 -- .../function-migration.test.ts | 100 - .../http-migration.test.ts | 44 - .../model-migration.test.ts | 276 -- .../predictions-migration.test.ts | 130 - .../searchable-migration.test.ts | 122 - .../ConnectionsWithAuthTests.e2e.test.ts | 514 --- .../DynamoDBModelTransformer.e2e.test.ts | 845 ---- .../FunctionTransformerTests.e2e.test.ts | 258 -- .../src/__tests__/HttpTransformer.e2e.test.ts | 468 -- .../__tests__/IndexTransformer.e2e.test.ts | 1078 ----- .../IndexWithAutoQueryField.e2e.test.ts | 1094 ----- ...dexWithClaimFieldAsSortKeyAuth.e2e.test.ts | 380 -- .../src/__tests__/KeyTransformer.e2e.test.ts | 955 ---- .../__tests__/KeyTransformerLocal.e2e.test.ts | 511 --- .../src/__tests__/KeyWithAuth.e2e.test.ts | 376 -- .../ModelAuthTransformer.e2e.test.ts | 3333 -------------- .../ModelConnectionTransformer.e2e.test.ts | 594 --- ...elConnectionWithKeyTransformer.e2e.test.ts | 767 ---- .../MultiAuthModelAuthTransformer.e2e.test.ts | 1341 ------ .../__tests__/NestedStacksTest.e2e.test.ts | 110 - .../NewConnectionTransformer.e2e.test.ts | 621 --- .../NewConnectionWithAuth.e2e.test.ts | 530 --- .../NonModelAuthFunction.e2e.test.ts | 473 -- .../PredictionsTransformerTests.e2e.test.ts | 149 - .../RelationalTransformers.e2e.test.ts | 955 ---- ...lWithOwnerFieldAsKeySchemaAuth.e2e.test.ts | 251 -- .../SearchableModelTransformer.e2e.test.ts | 1053 ----- .../SearchableWithAuthTests.e2e.test.ts | 608 --- .../SubscriptionsWithAuthTest.e2e.test.ts | 1430 ------ .../TestComplexStackMappingsLocal.e2e.test.ts | 189 - .../VersionedModelTransformer.e2e.test.ts | 265 -- yarn.lock | 2406 +---------- 47 files changed, 815 insertions(+), 26535 deletions(-) delete mode 100644 packages/amplify-e2e-tests/src/__tests__/migration/api.connection.migration.test.ts delete mode 100644 packages/amplify-e2e-tests/src/__tests__/migration/api.connection.migration2.test.ts delete mode 100644 packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration1.test.ts delete mode 100644 packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration2.test.ts delete mode 100644 packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration3.test.ts delete mode 100644 packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration4.test.ts delete mode 100644 packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration5.test.ts delete mode 100644 packages/amplify-e2e-tests/src/__tests__/schema-connection.test.ts delete mode 100644 packages/amplify-e2e-tests/src/__tests__/schema-key.test.ts delete mode 100644 packages/amplify-e2e-tests/src/__tests__/schema-versioned.test.ts delete mode 100644 packages/amplify-e2e-tests/src/__tests__/transformer-migrations/auth-migration.test.ts delete mode 100644 packages/amplify-e2e-tests/src/__tests__/transformer-migrations/function-migration.test.ts delete mode 100644 packages/amplify-e2e-tests/src/__tests__/transformer-migrations/http-migration.test.ts delete mode 100644 packages/amplify-e2e-tests/src/__tests__/transformer-migrations/model-migration.test.ts delete mode 100644 packages/amplify-e2e-tests/src/__tests__/transformer-migrations/predictions-migration.test.ts delete mode 100644 packages/amplify-e2e-tests/src/__tests__/transformer-migrations/searchable-migration.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/ConnectionsWithAuthTests.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/DynamoDBModelTransformer.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/FunctionTransformerTests.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/HttpTransformer.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/IndexTransformer.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/IndexWithAutoQueryField.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/IndexWithClaimFieldAsSortKeyAuth.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/KeyTransformer.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/KeyTransformerLocal.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/KeyWithAuth.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/ModelAuthTransformer.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/ModelConnectionTransformer.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/ModelConnectionWithKeyTransformer.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/MultiAuthModelAuthTransformer.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/NestedStacksTest.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/NewConnectionTransformer.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/NewConnectionWithAuth.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/NonModelAuthFunction.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/PredictionsTransformerTests.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/RelationalTransformers.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/RelationalWithOwnerFieldAsKeySchemaAuth.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/SearchableModelTransformer.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/SearchableWithAuthTests.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/SubscriptionsWithAuthTest.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/TestComplexStackMappingsLocal.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/VersionedModelTransformer.e2e.test.ts diff --git a/.gitignore b/.gitignore index f3fc4fe475..255df3e152 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ **/.DS_Store build -!packages/amplify-category-api/src/__tests__/graphql-transformer/override/*/build/ node_modules out pkg/node_modules @@ -28,7 +27,6 @@ packages/amplify-e2e-core/lib packagea/amplify-graphiql-explorer/build packages/amplify-graphql*/lib packages/amplify-e2e-tests/lib -packages/amplify-category-api/lib packages/amplify-e2e-tests/amplify-e2e-reports packages/graphql-transformers-e2e-tests/amplify-e2e-reports packages/amplify-schema-validator/dist/ @@ -41,7 +39,6 @@ console-integ*/ packages/**/reports/junit/* test.out.log *.tsbuildinfo -packages/amplify-graphiql-explorer/.eslintcache !packages/amplify-graphql-model-transformer/src/__tests__/overrides/build/override.js codebuild_specs/debug_workflow.yml .npmrc diff --git a/.prettierignore b/.prettierignore index aa654c0d2d..255006e30f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -7,8 +7,6 @@ node_modules API.md CHANGELOG.md client-test-apps -packages/amplify-category-api/resources/ -packages/amplify-category-api/src/__tests__/commands/api/mock-data/invalid_schema.graphql packages/amplify-dynamodb-simulator/emulator/dynamodb-local-metadata.json packages/amplify-e2e-core/dist/index.html packages/amplify-e2e-tests/amplify-e2e-reports diff --git a/codebuild_specs/e2e_workflow.yml b/codebuild_specs/e2e_workflow.yml index a8b39f2807..8ec02944d0 100644 --- a/codebuild_specs/e2e_workflow.yml +++ b/codebuild_specs/e2e_workflow.yml @@ -71,96 +71,76 @@ batch: depend-on: - publish_to_local_registry - identifier: >- - custom_transformers_schema_versioned_invalid_input_arguments_schema_data_access_patterns + custom_transformers_invalid_input_arguments_schema_data_access_patterns_schema_predictions buildspec: codebuild_specs/run_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/graphql-v2/custom-transformers.test.ts|src/__tests__/schema-versioned.test.ts|src/__tests__/graphql-v2/invalid-input-arguments.test.ts|src/__tests__/schema-data-access-patterns.test.ts + src/__tests__/graphql-v2/custom-transformers.test.ts|src/__tests__/graphql-v2/invalid-input-arguments.test.ts|src/__tests__/schema-data-access-patterns.test.ts|src/__tests__/schema-predictions.test.ts CLI_REGION: ap-northeast-2 depend-on: - publish_to_local_registry - - identifier: predictions_migration_schema_predictions_function_10_api_7 + - identifier: function_10_api_7_schema_function_2_global_sandbox buildspec: codebuild_specs/run_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/transformer-migrations/predictions-migration.test.ts|src/__tests__/schema-predictions.test.ts|src/__tests__/function_10.test.ts|src/__tests__/api_7.test.ts - CLI_REGION: ap-southeast-2 - depend-on: - - publish_to_local_registry - - identifier: http_migration_schema_function_2_global_sandbox_api_connection_migration - buildspec: codebuild_specs/run_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_MEDIUM - variables: - TEST_SUITE: >- - src/__tests__/transformer-migrations/http-migration.test.ts|src/__tests__/schema-function-2.test.ts|src/__tests__/global_sandbox.test.ts|src/__tests__/migration/api.connection.migration.test.ts - CLI_REGION: eu-west-2 + src/__tests__/function_10.test.ts|src/__tests__/api_7.test.ts|src/__tests__/schema-function-2.test.ts|src/__tests__/global_sandbox.test.ts + CLI_REGION: ca-central-1 depend-on: - publish_to_local_registry - identifier: >- - schema_iterative_update_3_api_8_auth_migration_schema_iterative_update_locking + schema_iterative_update_3_api_8_schema_iterative_update_locking_schema_iterative_update_1 buildspec: codebuild_specs/run_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/schema-iterative-update-3.test.ts|src/__tests__/api_8.test.ts|src/__tests__/transformer-migrations/auth-migration.test.ts|src/__tests__/schema-iterative-update-locking.test.ts - CLI_REGION: us-east-1 + src/__tests__/schema-iterative-update-3.test.ts|src/__tests__/api_8.test.ts|src/__tests__/schema-iterative-update-locking.test.ts|src/__tests__/schema-iterative-update-1.test.ts + CLI_REGION: eu-west-1 depend-on: - publish_to_local_registry - identifier: >- - schema_iterative_update_1_lambda_conflict_handler_index_with_stack_mappings_schema_iterative_update_2 + lambda_conflict_handler_index_with_stack_mappings_schema_iterative_update_2_custom_policies_container buildspec: codebuild_specs/run_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/schema-iterative-update-1.test.ts|src/__tests__/graphql-v2/lambda-conflict-handler.test.ts|src/__tests__/graphql-v2/index-with-stack-mappings.test.ts|src/__tests__/schema-iterative-update-2.test.ts - CLI_REGION: ap-northeast-1 + src/__tests__/graphql-v2/lambda-conflict-handler.test.ts|src/__tests__/graphql-v2/index-with-stack-mappings.test.ts|src/__tests__/schema-iterative-update-2.test.ts|src/__tests__/custom_policies_container.test.ts + CLI_REGION: us-east-2 depend-on: - publish_to_local_registry - - identifier: >- - custom_policies_container_api_4_api_connection_migration2_containers_api_secrets + - identifier: api_4_containers_api_secrets_api_5_schema_function_1 buildspec: codebuild_specs/run_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/custom_policies_container.test.ts|src/__tests__/api_4.test.ts|src/__tests__/migration/api.connection.migration2.test.ts|src/__tests__/containers-api-secrets.test.ts - CLI_REGION: us-east-1 + src/__tests__/api_4.test.ts|src/__tests__/containers-api-secrets.test.ts|src/__tests__/api_5.test.ts|src/__tests__/schema-function-1.test.ts + CLI_REGION: ap-northeast-2 depend-on: - publish_to_local_registry - - identifier: api_5_schema_function_1_api_3_generate_ts_data_schema + - identifier: api_3_generate_ts_data_schema_resolvers_sync_query_datastore buildspec: codebuild_specs/run_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/api_5.test.ts|src/__tests__/schema-function-1.test.ts|src/__tests__/api_3.test.ts|src/__tests__/generate_ts_data_schema.test.ts - CLI_REGION: ap-east-1 + src/__tests__/api_3.test.ts|src/__tests__/generate_ts_data_schema.test.ts|src/__tests__/resolvers.test.ts|src/__tests__/graphql-v2/sync_query_datastore.test.ts + CLI_REGION: us-west-2 depend-on: - publish_to_local_registry - - identifier: resolvers_sync_query_datastore_api_6_api_lambda_auth + - identifier: api_6_api_lambda_auth_api_9 buildspec: codebuild_specs/run_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/resolvers.test.ts|src/__tests__/graphql-v2/sync_query_datastore.test.ts|src/__tests__/api_6.test.ts|src/__tests__/graphql-v2/api_lambda_auth.test.ts - CLI_REGION: us-east-2 - depend-on: - - publish_to_local_registry - - identifier: api_9 - buildspec: codebuild_specs/run_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_MEDIUM - variables: - TEST_SUITE: src/__tests__/api_9.test.ts - CLI_REGION: us-west-1 + src/__tests__/api_6.test.ts|src/__tests__/graphql-v2/api_lambda_auth.test.ts|src/__tests__/api_9.test.ts + CLI_REGION: ca-central-1 depend-on: - publish_to_local_registry - identifier: rds_v2 @@ -181,51 +161,13 @@ batch: CLI_REGION: ap-southeast-2 depend-on: - publish_to_local_registry - - identifier: function_migration - buildspec: codebuild_specs/run_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_SMALL - variables: - TEST_SUITE: src/__tests__/transformer-migrations/function-migration.test.ts - CLI_REGION: eu-central-1 - depend-on: - - publish_to_local_registry - - identifier: api_key_migration3 - buildspec: codebuild_specs/run_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_SMALL - variables: - TEST_SUITE: src/__tests__/migration/api.key.migration3.test.ts - CLI_REGION: eu-west-1 - USE_PARENT_ACCOUNT: 1 - depend-on: - - publish_to_local_registry - identifier: schema_iterative_update_5 buildspec: codebuild_specs/run_e2e_tests.yml env: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-iterative-update-5.test.ts - CLI_REGION: eu-south-1 - depend-on: - - publish_to_local_registry - - identifier: api_key_migration5 - buildspec: codebuild_specs/run_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_SMALL - variables: - TEST_SUITE: src/__tests__/migration/api.key.migration5.test.ts - CLI_REGION: eu-west-3 - USE_PARENT_ACCOUNT: 1 - depend-on: - - publish_to_local_registry - - identifier: model_migration - buildspec: codebuild_specs/run_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_SMALL - variables: - TEST_SUITE: src/__tests__/transformer-migrations/model-migration.test.ts - CLI_REGION: eu-west-2 + CLI_REGION: ca-central-1 depend-on: - publish_to_local_registry - identifier: schema_auth_2 @@ -234,7 +176,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-auth-2.test.ts - CLI_REGION: me-south-1 + CLI_REGION: eu-north-1 depend-on: - publish_to_local_registry - identifier: schema_auth_10 @@ -243,7 +185,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-auth-10.test.ts - CLI_REGION: sa-east-1 + CLI_REGION: eu-south-1 depend-on: - publish_to_local_registry - identifier: schema_auth_1 @@ -252,7 +194,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-auth-1.test.ts - CLI_REGION: us-east-1 + CLI_REGION: eu-west-1 depend-on: - publish_to_local_registry - identifier: schema_auth_13 @@ -261,7 +203,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-auth-13.test.ts - CLI_REGION: us-west-1 + CLI_REGION: eu-west-3 depend-on: - publish_to_local_registry - identifier: schema_auth_12 @@ -270,7 +212,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-auth-12.test.ts - CLI_REGION: us-west-2 + CLI_REGION: me-south-1 depend-on: - publish_to_local_registry - identifier: schema_auth_3 @@ -279,7 +221,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-auth-3.test.ts - CLI_REGION: ap-east-1 + CLI_REGION: sa-east-1 depend-on: - publish_to_local_registry - identifier: schema_auth_15 @@ -288,7 +230,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-auth-15.test.ts - CLI_REGION: ap-northeast-1 + CLI_REGION: us-east-1 depend-on: - publish_to_local_registry - identifier: schema_iterative_rollback_1 @@ -297,26 +239,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-iterative-rollback-1.test.ts - CLI_REGION: ap-south-1 - depend-on: - - publish_to_local_registry - - identifier: api_key_migration4 - buildspec: codebuild_specs/run_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_SMALL - variables: - TEST_SUITE: src/__tests__/migration/api.key.migration4.test.ts - CLI_REGION: eu-north-1 - USE_PARENT_ACCOUNT: 1 - depend-on: - - publish_to_local_registry - - identifier: schema_key - buildspec: codebuild_specs/run_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_SMALL - variables: - TEST_SUITE: src/__tests__/schema-key.test.ts - CLI_REGION: ap-southeast-2 + CLI_REGION: us-east-2 depend-on: - publish_to_local_registry - identifier: schema_iterative_rollback_2 @@ -325,7 +248,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-iterative-rollback-2.test.ts - CLI_REGION: ca-central-1 + CLI_REGION: us-west-2 depend-on: - publish_to_local_registry - identifier: schema_auth_8 @@ -334,7 +257,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-auth-8.test.ts - CLI_REGION: eu-north-1 + CLI_REGION: ap-east-1 depend-on: - publish_to_local_registry - identifier: schema_auth_4 @@ -343,7 +266,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-auth-4.test.ts - CLI_REGION: eu-south-1 + CLI_REGION: ap-northeast-1 depend-on: - publish_to_local_registry - identifier: containers_api_1 @@ -361,26 +284,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-auth-11.test.ts - CLI_REGION: eu-west-2 - depend-on: - - publish_to_local_registry - - identifier: api_key_migration2 - buildspec: codebuild_specs/run_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_SMALL - variables: - TEST_SUITE: src/__tests__/migration/api.key.migration2.test.ts - CLI_REGION: us-west-2 - USE_PARENT_ACCOUNT: 1 - depend-on: - - publish_to_local_registry - - identifier: api_key_migration1 - buildspec: codebuild_specs/run_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_SMALL - variables: - TEST_SUITE: src/__tests__/migration/api.key.migration1.test.ts - CLI_REGION: me-south-1 + CLI_REGION: ap-southeast-1 depend-on: - publish_to_local_registry - identifier: sql_generate_unauth @@ -389,7 +293,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/sql-generate-unauth.test.ts - CLI_REGION: ap-northeast-2 + CLI_REGION: eu-west-1 depend-on: - publish_to_local_registry - identifier: schema_model @@ -398,7 +302,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-model.test.ts - CLI_REGION: us-east-1 + CLI_REGION: ca-central-1 depend-on: - publish_to_local_registry - identifier: rds_v2_test_utils @@ -407,7 +311,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-v2-test-utils.test.ts - CLI_REGION: ap-southeast-1 + CLI_REGION: eu-west-3 depend-on: - publish_to_local_registry - identifier: rds_relational_directives @@ -416,7 +320,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-relational-directives.test.ts - CLI_REGION: ap-southeast-2 + CLI_REGION: sa-east-1 depend-on: - publish_to_local_registry - identifier: rds_pg_v2_generate_schema @@ -425,7 +329,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-v2-generate-schema.test.ts - CLI_REGION: ca-central-1 + CLI_REGION: us-east-1 depend-on: - publish_to_local_registry - identifier: rds_pg_userpool_auth @@ -434,7 +338,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-userpool-auth.test.ts - CLI_REGION: eu-central-1 + CLI_REGION: us-east-2 depend-on: - publish_to_local_registry - identifier: rds_pg_userpool_auth_fields @@ -443,7 +347,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-userpool-auth-fields.test.ts - CLI_REGION: eu-north-1 + CLI_REGION: us-west-1 depend-on: - publish_to_local_registry - identifier: rds_pg_relational_directives @@ -452,7 +356,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-relational-directives.test.ts - CLI_REGION: eu-west-1 + CLI_REGION: us-west-2 depend-on: - publish_to_local_registry - identifier: rds_pg_refers_to @@ -461,7 +365,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-refers-to.test.ts - CLI_REGION: eu-west-2 + CLI_REGION: ap-northeast-1 depend-on: - publish_to_local_registry - identifier: rds_pg_refers_to_fields @@ -470,7 +374,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-refers-to-fields.test.ts - CLI_REGION: eu-west-3 + CLI_REGION: ap-northeast-2 depend-on: - publish_to_local_registry - identifier: rds_pg_oidc_auth @@ -479,7 +383,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-oidc-auth.test.ts - CLI_REGION: sa-east-1 + CLI_REGION: ap-south-1 depend-on: - publish_to_local_registry - identifier: rds_pg_oidc_auth_fields @@ -488,7 +392,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-oidc-auth-fields.test.ts - CLI_REGION: us-east-1 + CLI_REGION: ap-southeast-1 depend-on: - publish_to_local_registry - identifier: rds_pg_model_v2 @@ -497,7 +401,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-model-v2.test.ts - CLI_REGION: us-east-2 + CLI_REGION: ap-southeast-2 depend-on: - publish_to_local_registry - identifier: rds_pg_import @@ -506,7 +410,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-import.test.ts - CLI_REGION: us-west-1 + CLI_REGION: ca-central-1 depend-on: - publish_to_local_registry - identifier: rds_pg_field_auth_userpool_static_dynamic @@ -515,7 +419,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-field-auth-userpool-static-dynamic.test.ts - CLI_REGION: us-west-2 + CLI_REGION: eu-central-1 depend-on: - publish_to_local_registry - identifier: rds_pg_field_auth_userpool_iam @@ -524,7 +428,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-field-auth-userpool-iam.test.ts - CLI_REGION: ap-northeast-1 + CLI_REGION: eu-north-1 depend-on: - publish_to_local_registry - identifier: rds_pg_field_auth_lambda @@ -533,7 +437,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-field-auth-lambda.test.ts - CLI_REGION: ap-northeast-2 + CLI_REGION: eu-west-1 depend-on: - publish_to_local_registry - identifier: rds_pg_field_auth_identityPool @@ -542,7 +446,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-field-auth-identityPool.test.ts - CLI_REGION: ap-south-1 + CLI_REGION: eu-west-2 depend-on: - publish_to_local_registry - identifier: rds_pg_field_auth_iam @@ -551,7 +455,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-field-auth-iam.test.ts - CLI_REGION: ap-southeast-1 + CLI_REGION: eu-west-3 depend-on: - publish_to_local_registry - identifier: rds_pg_field_auth_apikey @@ -560,7 +464,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-field-auth-apikey.test.ts - CLI_REGION: ap-southeast-2 + CLI_REGION: sa-east-1 depend-on: - publish_to_local_registry - identifier: rds_pg_custom_claims_refersto_auth @@ -569,7 +473,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-custom-claims-refersto-auth.test.ts - CLI_REGION: ca-central-1 + CLI_REGION: us-east-1 depend-on: - publish_to_local_registry - identifier: rds_pg_auth_iam @@ -578,7 +482,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-auth-iam.test.ts - CLI_REGION: eu-central-1 + CLI_REGION: us-east-2 depend-on: - publish_to_local_registry - identifier: rds_pg_auth_iam_apikey_lambda_subscription @@ -587,7 +491,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-auth-iam-apikey-lambda-subscription.test.ts - CLI_REGION: eu-north-1 + CLI_REGION: us-west-1 depend-on: - publish_to_local_registry - identifier: rds_pg_auth_apikey_lambda @@ -596,7 +500,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-auth-apikey-lambda.test.ts - CLI_REGION: eu-west-1 + CLI_REGION: us-west-2 depend-on: - publish_to_local_registry - identifier: rds_pg_array_objects @@ -605,7 +509,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-pg-array-objects.test.ts - CLI_REGION: eu-west-2 + CLI_REGION: ap-northeast-1 depend-on: - publish_to_local_registry - identifier: rds_mysql_v2_generate_schema @@ -614,7 +518,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-v2-generate-schema.test.ts - CLI_REGION: eu-west-3 + CLI_REGION: ap-northeast-2 depend-on: - publish_to_local_registry - identifier: rds_mysql_userpool_auth @@ -623,7 +527,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-userpool-auth.test.ts - CLI_REGION: sa-east-1 + CLI_REGION: ap-south-1 depend-on: - publish_to_local_registry - identifier: rds_mysql_userpool_auth_fields @@ -632,7 +536,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-userpool-auth-fields.test.ts - CLI_REGION: us-east-1 + CLI_REGION: ap-southeast-1 depend-on: - publish_to_local_registry - identifier: rds_mysql_refers_to @@ -641,7 +545,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-refers-to.test.ts - CLI_REGION: us-east-2 + CLI_REGION: ap-southeast-2 depend-on: - publish_to_local_registry - identifier: rds_mysql_refers_to_fields @@ -650,7 +554,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-refers-to-fields.test.ts - CLI_REGION: us-west-1 + CLI_REGION: ca-central-1 depend-on: - publish_to_local_registry - identifier: rds_mysql_oidc_auth @@ -659,7 +563,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-oidc-auth.test.ts - CLI_REGION: us-west-2 + CLI_REGION: eu-central-1 depend-on: - publish_to_local_registry - identifier: rds_mysql_oidc_auth_fields @@ -668,7 +572,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-oidc-auth-fields.test.ts - CLI_REGION: ap-northeast-1 + CLI_REGION: eu-north-1 depend-on: - publish_to_local_registry - identifier: rds_mysql_multi_auth_1 @@ -677,7 +581,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-multi-auth-1.test.ts - CLI_REGION: ap-northeast-2 + CLI_REGION: eu-west-1 depend-on: - publish_to_local_registry - identifier: rds_mysql_model_v2 @@ -686,7 +590,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-model-v2.test.ts - CLI_REGION: ap-south-1 + CLI_REGION: eu-west-2 depend-on: - publish_to_local_registry - identifier: rds_mysql_field_auth_userpool_static_dynamic @@ -695,7 +599,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-field-auth-userpool-static-dynamic.test.ts - CLI_REGION: ap-southeast-1 + CLI_REGION: eu-west-3 depend-on: - publish_to_local_registry - identifier: rds_mysql_field_auth_userpool_iam @@ -704,7 +608,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-field-auth-userpool-iam.test.ts - CLI_REGION: ap-southeast-2 + CLI_REGION: sa-east-1 depend-on: - publish_to_local_registry - identifier: rds_mysql_field_auth_lambda @@ -713,7 +617,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-field-auth-lambda.test.ts - CLI_REGION: ca-central-1 + CLI_REGION: us-east-1 depend-on: - publish_to_local_registry - identifier: rds_mysql_field_auth_identityPool @@ -722,7 +626,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-field-auth-identityPool.test.ts - CLI_REGION: eu-central-1 + CLI_REGION: us-east-2 depend-on: - publish_to_local_registry - identifier: rds_mysql_field_auth_iam @@ -731,7 +635,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-field-auth-iam.test.ts - CLI_REGION: eu-north-1 + CLI_REGION: us-west-1 depend-on: - publish_to_local_registry - identifier: rds_mysql_field_auth_apikey @@ -740,7 +644,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-field-auth-apikey.test.ts - CLI_REGION: eu-west-1 + CLI_REGION: us-west-2 depend-on: - publish_to_local_registry - identifier: rds_mysql_custom_claims_refersto_auth @@ -749,7 +653,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-custom-claims-refersto-auth.test.ts - CLI_REGION: eu-west-2 + CLI_REGION: ap-northeast-1 depend-on: - publish_to_local_registry - identifier: rds_mysql_auth_iam @@ -758,7 +662,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-auth-iam.test.ts - CLI_REGION: eu-west-3 + CLI_REGION: ap-northeast-2 depend-on: - publish_to_local_registry - identifier: rds_mysql_auth_iam_apikey_lambda_subscription @@ -767,7 +671,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-auth-iam-apikey-lambda-subscription.test.ts - CLI_REGION: sa-east-1 + CLI_REGION: ap-south-1 depend-on: - publish_to_local_registry - identifier: rds_mysql_auth_apikey_lambda @@ -776,7 +680,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/rds-mysql-auth-apikey-lambda.test.ts - CLI_REGION: us-east-1 + CLI_REGION: ap-southeast-1 depend-on: - publish_to_local_registry - identifier: api_canary_ap_east_1 @@ -956,7 +860,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/api_11.test.ts - CLI_REGION: ap-northeast-2 + CLI_REGION: eu-west-2 depend-on: - publish_to_local_registry - identifier: apigw @@ -965,7 +869,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/apigw.test.ts - CLI_REGION: ap-south-1 + CLI_REGION: eu-west-3 depend-on: - publish_to_local_registry - identifier: schema_auth_9 @@ -974,7 +878,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-auth-9.test.ts - CLI_REGION: ap-southeast-1 + CLI_REGION: me-south-1 depend-on: - publish_to_local_registry - identifier: schema_auth_7 @@ -983,7 +887,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-auth-7.test.ts - CLI_REGION: ap-southeast-2 + CLI_REGION: sa-east-1 depend-on: - publish_to_local_registry - identifier: schema_auth_14 @@ -992,7 +896,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-auth-14.test.ts - CLI_REGION: ca-central-1 + CLI_REGION: us-east-1 depend-on: - publish_to_local_registry - identifier: containers_api_2 @@ -1010,7 +914,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/api_1.test.ts - CLI_REGION: eu-north-1 + CLI_REGION: us-west-1 depend-on: - publish_to_local_registry - identifier: schema_auth_5 @@ -1019,7 +923,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-auth-5.test.ts - CLI_REGION: eu-south-1 + CLI_REGION: us-west-2 depend-on: - publish_to_local_registry - identifier: schema_searchable @@ -1028,7 +932,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-searchable.test.ts - CLI_REGION: us-east-1 + CLI_REGION: ap-northeast-1 USE_PARENT_ACCOUNT: 1 depend-on: - publish_to_local_registry @@ -1038,7 +942,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-iterative-update-4.test.ts - CLI_REGION: eu-west-2 + CLI_REGION: ap-northeast-2 depend-on: - publish_to_local_registry - identifier: searchable_datastore @@ -1047,26 +951,17 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/graphql-v2/searchable-datastore.test.ts - CLI_REGION: sa-east-1 + CLI_REGION: ap-south-1 USE_PARENT_ACCOUNT: 1 depend-on: - publish_to_local_registry - - identifier: schema_connection - buildspec: codebuild_specs/run_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_SMALL - variables: - TEST_SUITE: src/__tests__/schema-connection.test.ts - CLI_REGION: me-south-1 - depend-on: - - publish_to_local_registry - identifier: schema_auth_6 buildspec: codebuild_specs/run_e2e_tests.yml env: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/schema-auth-6.test.ts - CLI_REGION: sa-east-1 + CLI_REGION: ap-southeast-1 depend-on: - publish_to_local_registry - identifier: searchable_previous_deployment_had_node_to_node @@ -1076,7 +971,7 @@ batch: variables: TEST_SUITE: >- src/__tests__/graphql-v2/searchable-node-to-node-encryption/searchable-previous-deployment-had-node-to-node.test.ts - CLI_REGION: us-west-1 + CLI_REGION: ap-southeast-2 depend-on: - publish_to_local_registry - identifier: searchable_previous_deployment_no_node_to_node @@ -1086,7 +981,7 @@ batch: variables: TEST_SUITE: >- src/__tests__/graphql-v2/searchable-node-to-node-encryption/searchable-previous-deployment-no-node-to-node.test.ts - CLI_REGION: us-west-2 + CLI_REGION: ca-central-1 depend-on: - publish_to_local_registry - identifier: api_2 @@ -1095,17 +990,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/api_2.test.ts - CLI_REGION: us-west-2 - depend-on: - - publish_to_local_registry - - identifier: searchable_migration - buildspec: codebuild_specs/run_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_SMALL - variables: - TEST_SUITE: src/__tests__/transformer-migrations/searchable-migration.test.ts - CLI_REGION: ap-south-1 - USE_PARENT_ACCOUNT: 1 + CLI_REGION: eu-central-1 depend-on: - publish_to_local_registry - identifier: utils_ddb_iam_access_data_construct_custom_logic @@ -1914,199 +1799,132 @@ batch: depend-on: - publish_to_local_registry - identifier: >- - TestComplexStackMappingsLocal_NestedStacksTest_KeyTransformerLocal_CustomRoots + CustomRoots_NonModelAuthV2Function_TransformerOptionsV2_PredictionsTransformerV2Tests buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/TestComplexStackMappingsLocal.e2e.test.ts|src/__tests__/NestedStacksTest.e2e.test.ts|src/__tests__/KeyTransformerLocal.e2e.test.ts|src/__tests__/CustomRoots.e2e.test.ts + src/__tests__/CustomRoots.e2e.test.ts|src/__tests__/NonModelAuthV2Function.e2e.test.ts|src/__tests__/TransformerOptionsV2.e2e.test.ts|src/__tests__/PredictionsTransformerV2Tests.e2e.test.ts CLI_REGION: ap-northeast-1 depend-on: - publish_to_local_registry - identifier: >- - NonModelAuthV2Function_VersionedModelTransformer_TransformerOptionsV2_PredictionsTransformerV2Tests - buildspec: codebuild_specs/graphql_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_MEDIUM - variables: - TEST_SUITE: >- - src/__tests__/NonModelAuthV2Function.e2e.test.ts|src/__tests__/VersionedModelTransformer.e2e.test.ts|src/__tests__/TransformerOptionsV2.e2e.test.ts|src/__tests__/PredictionsTransformerV2Tests.e2e.test.ts - CLI_REGION: ap-northeast-2 - depend-on: - - publish_to_local_registry - - identifier: >- - PredictionsTransformerTests_PerFieldAuthTests_NoneEnvFunctionTransformer_NonModelAuthFunction + PerFieldAuthTests_NoneEnvFunctionTransformer_MutationCondition_DefaultValueTransformer buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/PredictionsTransformerTests.e2e.test.ts|src/__tests__/PerFieldAuthTests.e2e.test.ts|src/__tests__/NoneEnvFunctionTransformer.e2e.test.ts|src/__tests__/NonModelAuthFunction.e2e.test.ts + src/__tests__/PerFieldAuthTests.e2e.test.ts|src/__tests__/NoneEnvFunctionTransformer.e2e.test.ts|src/__tests__/MutationCondition.e2e.test.ts|src/__tests__/DefaultValueTransformer.e2e.test.ts CLI_REGION: ap-south-1 depend-on: - publish_to_local_registry - identifier: >- - MutationCondition_KeyWithAuth_FunctionTransformerTests_DynamoDBModelTransformer + PerFieldAuthV2TransformerWithFF_PerFieldAuthV2Transformer_BelongsToTransformerV2_RelationalWithAuthV2WithFF buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/MutationCondition.e2e.test.ts|src/__tests__/KeyWithAuth.e2e.test.ts|src/__tests__/FunctionTransformerTests.e2e.test.ts|src/__tests__/DynamoDBModelTransformer.e2e.test.ts + src/__tests__/PerFieldAuthV2TransformerWithFF.e2e.test.ts|src/__tests__/PerFieldAuthV2Transformer.e2e.test.ts|src/__tests__/BelongsToTransformerV2.e2e.test.ts|src/__tests__/RelationalWithAuthV2WithFF.e2e.test.ts CLI_REGION: ap-southeast-2 depend-on: - publish_to_local_registry - identifier: >- - DefaultValueTransformer_ConnectionsWithAuthTests_RelationalWithOwnerFieldAsKeySchemaAuth_NewConnectionWithAuth + IndexWithAuthV2_IndexWithAuthV2WithFF_SubscriptionsWithAuthV2WithFF_MultiAuthV2Transformer buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/DefaultValueTransformer.e2e.test.ts|src/__tests__/ConnectionsWithAuthTests.e2e.test.ts|src/__tests__/RelationalWithOwnerFieldAsKeySchemaAuth.e2e.test.ts|src/__tests__/NewConnectionWithAuth.e2e.test.ts + src/__tests__/IndexWithAuthV2.e2e.test.ts|src/__tests__/IndexWithAuthV2WithFF.e2e.test.ts|src/__tests__/SubscriptionsWithAuthV2WithFF.e2e.test.ts|src/__tests__/MultiAuthV2Transformer.e2e.test.ts CLI_REGION: ca-central-1 depend-on: - publish_to_local_registry - identifier: >- - NewConnectionTransformer_ModelConnectionTransformer_SubscriptionsWithAuthTest_PerFieldAuthV2TransformerWithFF - buildspec: codebuild_specs/graphql_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_MEDIUM - variables: - TEST_SUITE: >- - src/__tests__/NewConnectionTransformer.e2e.test.ts|src/__tests__/ModelConnectionTransformer.e2e.test.ts|src/__tests__/SubscriptionsWithAuthTest.e2e.test.ts|src/__tests__/PerFieldAuthV2TransformerWithFF.e2e.test.ts - CLI_REGION: eu-south-1 - depend-on: - - publish_to_local_registry - - identifier: >- - PerFieldAuthV2Transformer_ModelAuthTransformer_KeyTransformer_BelongsToTransformerV2 + ModelTransformer_SubscriptionsWithAuthV2_RelationalWithAuthV2_MapsToTransformer buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/PerFieldAuthV2Transformer.e2e.test.ts|src/__tests__/ModelAuthTransformer.e2e.test.ts|src/__tests__/KeyTransformer.e2e.test.ts|src/__tests__/BelongsToTransformerV2.e2e.test.ts - CLI_REGION: eu-west-1 + src/__tests__/ModelTransformer.e2e.test.ts|src/__tests__/SubscriptionsWithAuthV2.e2e.test.ts|src/__tests__/RelationalWithAuthV2.e2e.test.ts|src/__tests__/MapsToTransformer.e2e.test.ts + CLI_REGION: eu-central-1 depend-on: - publish_to_local_registry - identifier: >- - RelationalWithAuthV2WithFF_ModelConnectionWithKeyTransformer_IndexWithAuthV2_MultiAuthModelAuthTransformer + MultiAuthV2TransformerWithFF_AuthV2Transformer_AuthV2ExhaustiveT1B_AuthV2ExhaustiveT1A buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/RelationalWithAuthV2WithFF.e2e.test.ts|src/__tests__/ModelConnectionWithKeyTransformer.e2e.test.ts|src/__tests__/IndexWithAuthV2.e2e.test.ts|src/__tests__/MultiAuthModelAuthTransformer.e2e.test.ts - CLI_REGION: eu-west-2 + src/__tests__/MultiAuthV2TransformerWithFF.e2e.test.ts|src/__tests__/AuthV2Transformer.e2e.test.ts|src/__tests__/AuthV2ExhaustiveT1B.test.ts|src/__tests__/AuthV2ExhaustiveT1A.test.ts + CLI_REGION: eu-north-1 depend-on: - publish_to_local_registry - identifier: >- - IndexWithAuthV2WithFF_SubscriptionsWithAuthV2WithFF_MultiAuthV2Transformer_ModelTransformer + AuthV2TransformerWithFF_SubscriptionsRuntimeFiltering_AuthV2ExhaustiveT2A_AuthV2ExhaustiveT1C buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/IndexWithAuthV2WithFF.e2e.test.ts|src/__tests__/SubscriptionsWithAuthV2WithFF.e2e.test.ts|src/__tests__/MultiAuthV2Transformer.e2e.test.ts|src/__tests__/ModelTransformer.e2e.test.ts - CLI_REGION: eu-west-3 + src/__tests__/AuthV2TransformerWithFF.e2e.test.ts|src/__tests__/SubscriptionsRuntimeFiltering.e2e.test.ts|src/__tests__/AuthV2ExhaustiveT2A.test.ts|src/__tests__/AuthV2ExhaustiveT1C.test.ts + CLI_REGION: eu-south-1 depend-on: - publish_to_local_registry - identifier: >- - IndexWithClaimFieldAsSortKeyAuth_SubscriptionsWithAuthV2_RelationalWithAuthV2_MapsToTransformer + AuthV2ExhaustiveT1D_AuthV2ExhaustiveT2B_AuthV2ExhaustiveT2D_AuthV2ExhaustiveT2C buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/IndexWithClaimFieldAsSortKeyAuth.e2e.test.ts|src/__tests__/SubscriptionsWithAuthV2.e2e.test.ts|src/__tests__/RelationalWithAuthV2.e2e.test.ts|src/__tests__/MapsToTransformer.e2e.test.ts - CLI_REGION: me-south-1 + src/__tests__/AuthV2ExhaustiveT1D.test.ts|src/__tests__/AuthV2ExhaustiveT2B.test.ts|src/__tests__/AuthV2ExhaustiveT2D.test.ts|src/__tests__/AuthV2ExhaustiveT2C.test.ts + CLI_REGION: eu-west-1 depend-on: - publish_to_local_registry - identifier: >- - MultiAuthV2TransformerWithFF_IndexTransformer_AuthV2Transformer_AuthV2ExhaustiveT1B + RelationalWithAuthV2Redacted_RelationalWithAuthV2NonRedacted_AuthV2TransformerIAM_AuthV2ExhaustiveT3D buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/MultiAuthV2TransformerWithFF.e2e.test.ts|src/__tests__/IndexTransformer.e2e.test.ts|src/__tests__/AuthV2Transformer.e2e.test.ts|src/__tests__/AuthV2ExhaustiveT1B.test.ts - CLI_REGION: sa-east-1 + src/__tests__/RelationalWithAuthV2Redacted.e2e.test.ts|src/__tests__/RelationalWithAuthV2NonRedacted.e2e.test.ts|src/__tests__/AuthV2TransformerIAM.test.ts|src/__tests__/AuthV2ExhaustiveT3D.test.ts + CLI_REGION: eu-west-2 depend-on: - publish_to_local_registry - identifier: >- - AuthV2ExhaustiveT1A_IndexWithAutoQueryField_AuthV2TransformerWithFF_SubscriptionsRuntimeFiltering + AuthV2ExhaustiveT3C_AuthV2ExhaustiveT3B_AuthV2ExhaustiveT3A_SearchableModelTransformerV2 buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/AuthV2ExhaustiveT1A.test.ts|src/__tests__/IndexWithAutoQueryField.e2e.test.ts|src/__tests__/AuthV2TransformerWithFF.e2e.test.ts|src/__tests__/SubscriptionsRuntimeFiltering.e2e.test.ts + src/__tests__/AuthV2ExhaustiveT3C.test.ts|src/__tests__/AuthV2ExhaustiveT3B.test.ts|src/__tests__/AuthV2ExhaustiveT3A.test.ts|src/__tests__/SearchableModelTransformerV2.e2e.test.ts CLI_REGION: us-east-1 depend-on: - publish_to_local_registry - - identifier: >- - RelationalTransformers_AuthV2ExhaustiveT2A_AuthV2ExhaustiveT1C_AuthV2ExhaustiveT1D + - identifier: SearchableWithAuthV2WithFF_SearchableWithAuthV2 buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/RelationalTransformers.e2e.test.ts|src/__tests__/AuthV2ExhaustiveT2A.test.ts|src/__tests__/AuthV2ExhaustiveT1C.test.ts|src/__tests__/AuthV2ExhaustiveT1D.test.ts + src/__tests__/SearchableWithAuthV2WithFF.e2e.test.ts|src/__tests__/SearchableWithAuthV2.e2e.test.ts CLI_REGION: us-east-2 depend-on: - publish_to_local_registry - - identifier: >- - AuthV2ExhaustiveT2B_AuthV2ExhaustiveT2D_AuthV2ExhaustiveT2C_RelationalWithAuthV2Redacted - buildspec: codebuild_specs/graphql_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_MEDIUM - variables: - TEST_SUITE: >- - src/__tests__/AuthV2ExhaustiveT2B.test.ts|src/__tests__/AuthV2ExhaustiveT2D.test.ts|src/__tests__/AuthV2ExhaustiveT2C.test.ts|src/__tests__/RelationalWithAuthV2Redacted.e2e.test.ts - CLI_REGION: us-west-1 - depend-on: - - publish_to_local_registry - - identifier: >- - RelationalWithAuthV2NonRedacted_AuthV2TransformerIAM_AuthV2ExhaustiveT3D_AuthV2ExhaustiveT3C - buildspec: codebuild_specs/graphql_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_MEDIUM - variables: - TEST_SUITE: >- - src/__tests__/RelationalWithAuthV2NonRedacted.e2e.test.ts|src/__tests__/AuthV2TransformerIAM.test.ts|src/__tests__/AuthV2ExhaustiveT3D.test.ts|src/__tests__/AuthV2ExhaustiveT3C.test.ts - CLI_REGION: us-west-2 - depend-on: - - publish_to_local_registry - - identifier: >- - AuthV2ExhaustiveT3B_AuthV2ExhaustiveT3A_SearchableModelTransformerV2_SearchableWithAuthTests - buildspec: codebuild_specs/graphql_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_MEDIUM - variables: - TEST_SUITE: >- - src/__tests__/AuthV2ExhaustiveT3B.test.ts|src/__tests__/AuthV2ExhaustiveT3A.test.ts|src/__tests__/SearchableModelTransformerV2.e2e.test.ts|src/__tests__/SearchableWithAuthTests.e2e.test.ts - CLI_REGION: ap-southeast-1 - depend-on: - - publish_to_local_registry - - identifier: >- - SearchableModelTransformer_SearchableWithAuthV2WithFF_SearchableWithAuthV2 - buildspec: codebuild_specs/graphql_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_MEDIUM - variables: - TEST_SUITE: >- - src/__tests__/SearchableModelTransformer.e2e.test.ts|src/__tests__/SearchableWithAuthV2WithFF.e2e.test.ts|src/__tests__/SearchableWithAuthV2.e2e.test.ts - CLI_REGION: ap-southeast-2 - depend-on: - - publish_to_local_registry - identifier: FunctionTransformerTestsV2 buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/FunctionTransformerTestsV2.e2e.test.ts - CLI_REGION: ca-central-1 + CLI_REGION: ap-southeast-1 USE_PARENT_ACCOUNT: 1 depend-on: - publish_to_local_registry @@ -2116,16 +1934,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/HttpTransformerV2.e2e.test.ts - CLI_REGION: eu-north-1 - depend-on: - - publish_to_local_registry - - identifier: HttpTransformer - buildspec: codebuild_specs/graphql_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_SMALL - variables: - TEST_SUITE: src/__tests__/HttpTransformer.e2e.test.ts - CLI_REGION: eu-south-1 + CLI_REGION: ap-southeast-2 depend-on: - publish_to_local_registry - identifier: cleanup_e2e_resources diff --git a/dependency_licenses.txt b/dependency_licenses.txt index 044d8a4edf..d14904439d 100644 --- a/dependency_licenses.txt +++ b/dependency_licenses.txt @@ -233,73 +233,7 @@ Apache License ----- -The following software may be included in this product: @ardatan/aggregate-error, aggregate-error, ansi-escapes, ansi-regex, ansi-styles, any-observable, array-differ, array-union, arrify, auto-bind, callsites, camelcase, camelcase-keys, chalk, clean-stack, cli-cursor, dargs, decamelize, define-lazy-prop, del, detect-indent, detect-newline, dot-prop, env-paths, escape-string-regexp, execa, find-up, get-port, get-stdin, get-stream, global-dirs, globals, globby, got, hard-rejection, has-flag, import-from, import-global, import-lazy, import-local, indent-string, is-finite, is-fullwidth-code-point, is-generator-fn, is-interactive, is-obj, is-observable, is-path-cwd, is-path-inside, is-plain-obj, is-wsl, leven, load-json-file, locate-path, log-symbols, log-update, make-dir, mimic-fn, normalize-url, npm-run-path, p-finally, p-is-promise, p-limit, p-locate, p-map, p-map-series, p-reduce, p-timeout, p-try, parent-module, parse-json, path-exists, path-key, path-type, pify, pkg-dir, quick-lru, read-pkg, read-pkg-up, redent, remote-git-tags, resolve-cwd, resolve-from, resolve-global, resolve-pkg, restore-cursor, run-node, shebang-regex, slash, sort-keys, string-width, string-width-cjs, strip-ansi, strip-ansi-cjs, strip-bom, strip-final-newline, strip-indent, supports-color, terminal-link, text-extensions, tildify, trim-newlines, type-fest, untildify, wrap-ansi, write-json-file, write-pkg, yn. A copy of the source code may be downloaded from https://github.com/sindresorhus/aggregate-error.git (@ardatan/aggregate-error), https://github.com/sindresorhus/aggregate-error.git (aggregate-error), https://github.com/sindresorhus/ansi-escapes.git (ansi-escapes), https://github.com/chalk/ansi-regex.git (ansi-regex), https://github.com/chalk/ansi-styles.git (ansi-styles), https://github.com/sindresorhus/any-observable.git (any-observable), https://github.com/sindresorhus/array-differ.git (array-differ), https://github.com/sindresorhus/array-union.git (array-union), https://github.com/sindresorhus/arrify.git (arrify), https://github.com/sindresorhus/auto-bind.git (auto-bind), https://github.com/sindresorhus/callsites.git (callsites), https://github.com/sindresorhus/camelcase.git (camelcase), https://github.com/sindresorhus/camelcase-keys.git (camelcase-keys), https://github.com/chalk/chalk.git (chalk), https://github.com/sindresorhus/clean-stack.git (clean-stack), https://github.com/sindresorhus/cli-cursor.git (cli-cursor), https://github.com/sindresorhus/dargs.git (dargs), https://github.com/sindresorhus/decamelize.git (decamelize), https://github.com/sindresorhus/define-lazy-prop.git (define-lazy-prop), https://github.com/sindresorhus/del.git (del), https://github.com/sindresorhus/detect-indent.git (detect-indent), https://github.com/sindresorhus/detect-newline.git (detect-newline), https://github.com/sindresorhus/dot-prop.git (dot-prop), https://github.com/sindresorhus/env-paths.git (env-paths), https://github.com/sindresorhus/escape-string-regexp.git (escape-string-regexp), https://github.com/sindresorhus/execa.git (execa), https://github.com/sindresorhus/find-up.git (find-up), https://github.com/sindresorhus/get-port.git (get-port), https://github.com/sindresorhus/get-stdin.git (get-stdin), https://github.com/sindresorhus/get-stream.git (get-stream), https://github.com/sindresorhus/global-dirs.git (global-dirs), https://github.com/sindresorhus/globals.git (globals), https://github.com/sindresorhus/globby.git (globby), https://github.com/sindresorhus/got.git (got), https://github.com/sindresorhus/hard-rejection.git (hard-rejection), https://github.com/sindresorhus/has-flag.git (has-flag), https://github.com/sindresorhus/import-from.git (import-from), https://github.com/sindresorhus/import-global.git (import-global), https://github.com/sindresorhus/import-lazy.git (import-lazy), https://github.com/sindresorhus/import-local.git (import-local), https://github.com/sindresorhus/indent-string.git (indent-string), https://github.com/sindresorhus/is-finite.git (is-finite), https://github.com/sindresorhus/is-fullwidth-code-point.git (is-fullwidth-code-point), https://github.com/sindresorhus/is-generator-fn.git (is-generator-fn), https://github.com/sindresorhus/is-interactive.git (is-interactive), https://github.com/sindresorhus/is-obj.git (is-obj), https://github.com/sindresorhus/is-observable.git (is-observable), https://github.com/sindresorhus/is-path-cwd.git (is-path-cwd), https://github.com/sindresorhus/is-path-inside.git (is-path-inside), https://github.com/sindresorhus/is-plain-obj.git (is-plain-obj), https://github.com/sindresorhus/is-wsl.git (is-wsl), https://github.com/sindresorhus/leven.git (leven), https://github.com/sindresorhus/load-json-file.git (load-json-file), https://github.com/sindresorhus/locate-path.git (locate-path), https://github.com/sindresorhus/log-symbols.git (log-symbols), https://github.com/sindresorhus/log-update.git (log-update), https://github.com/sindresorhus/make-dir.git (make-dir), https://github.com/sindresorhus/mimic-fn.git (mimic-fn), https://github.com/sindresorhus/normalize-url.git (normalize-url), https://github.com/sindresorhus/npm-run-path.git (npm-run-path), https://github.com/sindresorhus/p-finally.git (p-finally), https://github.com/sindresorhus/p-is-promise.git (p-is-promise), https://github.com/sindresorhus/p-limit.git (p-limit), https://github.com/sindresorhus/p-locate.git (p-locate), https://github.com/sindresorhus/p-map.git (p-map), https://github.com/sindresorhus/p-map-series.git (p-map-series), https://github.com/sindresorhus/p-reduce.git (p-reduce), https://github.com/sindresorhus/p-timeout.git (p-timeout), https://github.com/sindresorhus/p-try.git (p-try), https://github.com/sindresorhus/parent-module.git (parent-module), https://github.com/sindresorhus/parse-json.git (parse-json), https://github.com/sindresorhus/path-exists.git (path-exists), https://github.com/sindresorhus/path-key.git (path-key), https://github.com/sindresorhus/path-type.git (path-type), https://github.com/sindresorhus/pify.git (pify), https://github.com/sindresorhus/pkg-dir.git (pkg-dir), https://github.com/sindresorhus/quick-lru.git (quick-lru), https://github.com/sindresorhus/read-pkg.git (read-pkg), https://github.com/sindresorhus/read-pkg-up.git (read-pkg-up), https://github.com/sindresorhus/redent.git (redent), https://github.com/sindresorhus/remote-git-tags.git (remote-git-tags), https://github.com/sindresorhus/resolve-cwd.git (resolve-cwd), https://github.com/sindresorhus/resolve-from.git (resolve-from), https://github.com/sindresorhus/resolve-global.git (resolve-global), https://github.com/sindresorhus/resolve-pkg.git (resolve-pkg), https://github.com/sindresorhus/restore-cursor.git (restore-cursor), https://github.com/sindresorhus/run-node.git (run-node), https://github.com/sindresorhus/shebang-regex.git (shebang-regex), https://github.com/sindresorhus/slash.git (slash), https://github.com/sindresorhus/sort-keys.git (sort-keys), https://github.com/sindresorhus/string-width.git (string-width), https://github.com/sindresorhus/string-width.git (string-width-cjs), https://github.com/chalk/strip-ansi.git (strip-ansi), https://github.com/chalk/strip-ansi.git (strip-ansi-cjs), https://github.com/sindresorhus/strip-bom.git (strip-bom), https://github.com/sindresorhus/strip-final-newline.git (strip-final-newline), https://github.com/sindresorhus/strip-indent.git (strip-indent), https://github.com/chalk/supports-color.git (supports-color), https://github.com/sindresorhus/terminal-link.git (terminal-link), https://github.com/sindresorhus/text-extensions.git (text-extensions), https://github.com/sindresorhus/tildify.git (tildify), https://github.com/sindresorhus/trim-newlines.git (trim-newlines), https://github.com/sindresorhus/type-fest.git (type-fest), https://github.com/sindresorhus/untildify.git (untildify), https://github.com/chalk/wrap-ansi.git (wrap-ansi), https://github.com/sindresorhus/write-json-file.git (write-json-file), https://github.com/sindresorhus/write-pkg.git (write-pkg), https://github.com/sindresorhus/yn.git (yn). This software contains the following license and notice below: - -MIT License - -Copyright (c) Sindre Sorhus (sindresorhus.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - -The following software may be included in this product: @ardatan/relay-compiler, @jest/console, @jest/core, @jest/environment, @jest/fake-timers, @jest/globals, @jest/reporters, @jest/source-map, @jest/test-result, @jest/test-sequencer, @jest/transform, @jest/types, babel-jest, babel-plugin-jest-hoist, babel-preset-jest, diff-sequences, expect, jest, jest-changed-files, jest-circus, jest-cli, jest-config, jest-diff, jest-docblock, jest-each, jest-environment-jsdom, jest-environment-node, jest-get-type, jest-haste-map, jest-jasmine2, jest-leak-detector, jest-matcher-utils, jest-message-util, jest-mock, jest-regex-util, jest-resolve, jest-resolve-dependencies, jest-runner, jest-runtime, jest-serializer, jest-snapshot, jest-util, jest-validate, jest-watcher, jest-worker, pretty-format, react-is, relay-runtime. A copy of the source code may be downloaded from https://github.com/facebook/relay.git (@ardatan/relay-compiler), https://github.com/facebook/jest.git (@jest/console), https://github.com/facebook/jest (@jest/core), https://github.com/facebook/jest.git (@jest/environment), https://github.com/facebook/jest.git (@jest/fake-timers), https://github.com/facebook/jest.git (@jest/globals), https://github.com/facebook/jest (@jest/reporters), https://github.com/facebook/jest.git (@jest/source-map), https://github.com/facebook/jest.git (@jest/test-result), https://github.com/facebook/jest.git (@jest/test-sequencer), https://github.com/facebook/jest.git (@jest/transform), https://github.com/facebook/jest.git (@jest/types), https://github.com/facebook/jest.git (babel-jest), https://github.com/facebook/jest.git (babel-plugin-jest-hoist), https://github.com/facebook/jest.git (babel-preset-jest), https://github.com/facebook/jest.git (diff-sequences), https://github.com/facebook/jest.git (expect), https://github.com/facebook/jest (jest), https://github.com/facebook/jest.git (jest-changed-files), https://github.com/facebook/jest.git (jest-circus), https://github.com/facebook/jest (jest-cli), https://github.com/facebook/jest.git (jest-config), https://github.com/facebook/jest.git (jest-diff), https://github.com/facebook/jest.git (jest-docblock), https://github.com/facebook/jest.git (jest-each), https://github.com/facebook/jest.git (jest-environment-jsdom), https://github.com/facebook/jest.git (jest-environment-node), https://github.com/facebook/jest.git (jest-get-type), https://github.com/facebook/jest.git (jest-haste-map), https://github.com/facebook/jest.git (jest-jasmine2), https://github.com/facebook/jest.git (jest-leak-detector), https://github.com/facebook/jest.git (jest-matcher-utils), https://github.com/facebook/jest.git (jest-message-util), https://github.com/facebook/jest.git (jest-mock), https://github.com/facebook/jest.git (jest-regex-util), https://github.com/facebook/jest.git (jest-resolve), https://github.com/facebook/jest.git (jest-resolve-dependencies), https://github.com/facebook/jest.git (jest-runner), https://github.com/facebook/jest.git (jest-runtime), https://github.com/facebook/jest.git (jest-serializer), https://github.com/facebook/jest.git (jest-snapshot), https://github.com/facebook/jest.git (jest-util), https://github.com/facebook/jest.git (jest-validate), https://github.com/facebook/jest (jest-watcher), https://github.com/facebook/jest.git (jest-worker), https://github.com/facebook/jest.git (pretty-format), https://github.com/facebook/react.git (react-is), https://github.com/facebook/relay.git (relay-runtime). This software contains the following license and notice below: - -MIT License - -Copyright (c) Facebook, Inc. and its affiliates. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: @ardatan/sync-fetch. A copy of the source code may be downloaded from git+https://github.com/larsgw/sync-fetch.git. This software contains the following license and notice below: - -MIT License - -Copyright (c) 2019 Lars Willighagen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: @aws-amplify/amplify-app, @aws-amplify/amplify-appsync-simulator, @aws-amplify/amplify-category-custom, @aws-amplify/amplify-category-function, @aws-amplify/amplify-cli-core, @aws-amplify/amplify-cli-logger, @aws-amplify/amplify-cli-shared-interfaces, @aws-amplify/amplify-environment-parameters, @aws-amplify/amplify-frontend-android, @aws-amplify/amplify-frontend-flutter, @aws-amplify/amplify-frontend-ios, @aws-amplify/amplify-frontend-javascript, @aws-amplify/amplify-function-plugin-interface, @aws-amplify/amplify-prompts, @aws-amplify/amplify-provider-awscloudformation, @aws-amplify/amplify-util-import, @aws-amplify/appsync-modelgen-plugin, @aws-amplify/cli-extensibility-helper, @aws-amplify/graphql-docs-generator, @aws-amplify/graphql-generator, @aws-amplify/graphql-types-generator, amplify-codegen, amplify-function-plugin-interface, amplify-headless-interface, amplify-nodejs-function-runtime-provider, amplify-storage-simulator, amplify-util-headless-input. A copy of the source code may be downloaded from https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-app), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-appsync-simulator), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-category-custom), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-category-function), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-cli-core), git+https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-cli-logger), git+https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-cli-shared-interfaces), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-environment-parameters), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-frontend-android), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-frontend-flutter), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-frontend-ios), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-frontend-javascript), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-function-plugin-interface), git+https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-prompts), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-provider-awscloudformation), https://github.com/aws-amplify/amplify-codegen.git (@aws-amplify/appsync-modelgen-plugin), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/cli-extensibility-helper), https://github.com/aws-amplify/amplify-codegen.git (@aws-amplify/graphql-docs-generator), https://github.com/aws-amplify/amplify-codegen.git (@aws-amplify/graphql-generator), https://github.com/aws-amplify/amplify-codegen.git (@aws-amplify/graphql-types-generator), https://github.com/aws-amplify/amplify-codegen.git (amplify-codegen), https://github.com/aws-amplify/amplify-cli.git (amplify-function-plugin-interface), https://github.com/aws-amplify/amplify-cli.git (amplify-nodejs-function-runtime-provider), https://github.com/aws-amplify/amplify-cli.git (amplify-storage-simulator). This software contains the following license and notice below: +The following software may be included in this product: @aws-amplify/amplify-app, @aws-amplify/amplify-cli-core, @aws-amplify/amplify-cli-logger, @aws-amplify/amplify-cli-shared-interfaces, @aws-amplify/amplify-frontend-android, @aws-amplify/amplify-frontend-flutter, @aws-amplify/amplify-frontend-ios, @aws-amplify/amplify-frontend-javascript, @aws-amplify/amplify-function-plugin-interface, @aws-amplify/amplify-prompts, amplify-headless-interface. A copy of the source code may be downloaded from https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-app), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-cli-core), git+https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-cli-logger), git+https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-cli-shared-interfaces), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-frontend-android), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-frontend-flutter), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-frontend-ios), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-frontend-javascript), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-function-plugin-interface), git+https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-prompts). This software contains the following license and notice below: Apache License Version 2.0, January 2004 @@ -711,6 +645,211 @@ Apache License ----- + +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2017 - 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +----- + The following software may be included in this product: @aws-cdk/asset-awscli-v1, @aws-cdk/asset-kubectl-v20, @aws-cdk/asset-node-proxy-agent-v6, jsii. A copy of the source code may be downloaded from https://github.com/cdklabs/awscdk-asset-awscli.git (@aws-cdk/asset-awscli-v1), https://github.com/cdklabs/awscdk-asset-kubectl.git (@aws-cdk/asset-kubectl-v20), https://github.com/cdklabs/awscdk-asset-node-proxy-agent.git (@aws-cdk/asset-node-proxy-agent-v6), https://github.com/aws/jsii-compiler.git (jsii). This software contains the following license and notice below: Apache License @@ -922,7 +1061,7 @@ Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. ----- -The following software may be included in this product: @aws-cdk/aws-apigatewayv2-alpha, @aws-cdk/cloudformation-diff. A copy of the source code may be downloaded from https://github.com/aws/aws-cdk.git (@aws-cdk/aws-apigatewayv2-alpha), https://github.com/aws/aws-cdk.git (@aws-cdk/cloudformation-diff). This software contains the following license and notice below: +The following software may be included in this product: @aws-cdk/aws-cognito-identitypool-alpha. A copy of the source code may be downloaded from https://github.com/aws/aws-cdk.git. This software contains the following license and notice below: Apache License Version 2.0, January 2004 @@ -1112,7 +1251,7 @@ Apache License same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -1130,11 +1269,11 @@ Apache License NOTICE AWS Cloud Development Kit (AWS CDK) -Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. +Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. ----- -The following software may be included in this product: @aws-cdk/aws-cognito-identitypool-alpha. A copy of the source code may be downloaded from https://github.com/aws/aws-cdk.git. This software contains the following license and notice below: +The following software may be included in this product: @aws-cdk/cfnspec. A copy of the source code may be downloaded from https://github.com/aws/aws-cdk.git. This software contains the following license and notice below: Apache License Version 2.0, January 2004 @@ -1324,7 +1463,7 @@ Apache License same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. + Copyright 2018-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -1342,11 +1481,11 @@ Apache License NOTICE AWS Cloud Development Kit (AWS CDK) -Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. +Copyright 2018-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. ----- -The following software may be included in this product: @aws-cdk/cfnspec. A copy of the source code may be downloaded from https://github.com/aws/aws-cdk.git. This software contains the following license and notice below: +The following software may be included in this product: @aws-cdk/cloudformation-diff. A copy of the source code may be downloaded from https://github.com/aws/aws-cdk.git. This software contains the following license and notice below: Apache License Version 2.0, January 2004 @@ -1536,7 +1675,7 @@ Apache License same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2018-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -1554,7 +1693,7 @@ Apache License NOTICE AWS Cloud Development Kit (AWS CDK) -Copyright 2018-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. ----- @@ -3618,7 +3757,7 @@ Apache License ----- -The following software may be included in this product: @babel/cli, @babel/code-frame, @babel/compat-data, @babel/core, @babel/generator, @babel/helper-annotate-as-pure, @babel/helper-compilation-targets, @babel/helper-create-class-features-plugin, @babel/helper-environment-visitor, @babel/helper-function-name, @babel/helper-hoist-variables, @babel/helper-member-expression-to-functions, @babel/helper-module-imports, @babel/helper-module-transforms, @babel/helper-optimise-call-expression, @babel/helper-plugin-utils, @babel/helper-replace-supers, @babel/helper-simple-access, @babel/helper-skip-transparent-expression-wrappers, @babel/helper-split-export-declaration, @babel/helper-string-parser, @babel/helper-validator-identifier, @babel/helper-validator-option, @babel/helpers, @babel/highlight, @babel/plugin-proposal-class-properties, @babel/plugin-proposal-numeric-separator, @babel/plugin-proposal-object-rest-spread, @babel/plugin-syntax-async-generators, @babel/plugin-syntax-bigint, @babel/plugin-syntax-class-properties, @babel/plugin-syntax-flow, @babel/plugin-syntax-import-meta, @babel/plugin-syntax-json-strings, @babel/plugin-syntax-jsx, @babel/plugin-syntax-logical-assignment-operators, @babel/plugin-syntax-nullish-coalescing-operator, @babel/plugin-syntax-numeric-separator, @babel/plugin-syntax-object-rest-spread, @babel/plugin-syntax-optional-catch-binding, @babel/plugin-syntax-optional-chaining, @babel/plugin-syntax-top-level-await, @babel/plugin-syntax-typescript, @babel/plugin-transform-arrow-functions, @babel/plugin-transform-block-scoped-functions, @babel/plugin-transform-block-scoping, @babel/plugin-transform-classes, @babel/plugin-transform-computed-properties, @babel/plugin-transform-destructuring, @babel/plugin-transform-flow-strip-types, @babel/plugin-transform-for-of, @babel/plugin-transform-function-name, @babel/plugin-transform-literals, @babel/plugin-transform-member-expression-literals, @babel/plugin-transform-modules-commonjs, @babel/plugin-transform-object-super, @babel/plugin-transform-parameters, @babel/plugin-transform-property-literals, @babel/plugin-transform-react-display-name, @babel/plugin-transform-react-jsx, @babel/plugin-transform-shorthand-properties, @babel/plugin-transform-spread, @babel/plugin-transform-template-literals, @babel/plugin-transform-typescript, @babel/runtime, @babel/template, @babel/traverse, @babel/types. A copy of the source code may be downloaded from https://github.com/babel/babel.git (@babel/cli), https://github.com/babel/babel.git (@babel/code-frame), https://github.com/babel/babel.git (@babel/compat-data), https://github.com/babel/babel.git (@babel/core), https://github.com/babel/babel.git (@babel/generator), https://github.com/babel/babel.git (@babel/helper-annotate-as-pure), https://github.com/babel/babel.git (@babel/helper-compilation-targets), https://github.com/babel/babel.git (@babel/helper-create-class-features-plugin), https://github.com/babel/babel.git (@babel/helper-environment-visitor), https://github.com/babel/babel.git (@babel/helper-function-name), https://github.com/babel/babel.git (@babel/helper-hoist-variables), https://github.com/babel/babel.git (@babel/helper-member-expression-to-functions), https://github.com/babel/babel.git (@babel/helper-module-imports), https://github.com/babel/babel.git (@babel/helper-module-transforms), https://github.com/babel/babel.git (@babel/helper-optimise-call-expression), https://github.com/babel/babel.git (@babel/helper-plugin-utils), https://github.com/babel/babel.git (@babel/helper-replace-supers), https://github.com/babel/babel.git (@babel/helper-simple-access), https://github.com/babel/babel.git (@babel/helper-skip-transparent-expression-wrappers), https://github.com/babel/babel.git (@babel/helper-split-export-declaration), https://github.com/babel/babel.git (@babel/helper-string-parser), https://github.com/babel/babel.git (@babel/helper-validator-identifier), https://github.com/babel/babel.git (@babel/helper-validator-option), https://github.com/babel/babel.git (@babel/helpers), https://github.com/babel/babel.git (@babel/highlight), https://github.com/babel/babel.git (@babel/plugin-proposal-class-properties), https://github.com/babel/babel.git (@babel/plugin-proposal-numeric-separator), https://github.com/babel/babel.git (@babel/plugin-proposal-object-rest-spread), https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-async-generators (@babel/plugin-syntax-async-generators), https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-bigint (@babel/plugin-syntax-bigint), https://github.com/babel/babel.git (@babel/plugin-syntax-class-properties), https://github.com/babel/babel.git (@babel/plugin-syntax-flow), https://github.com/babel/babel.git (@babel/plugin-syntax-import-meta), https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-json-strings (@babel/plugin-syntax-json-strings), https://github.com/babel/babel.git (@babel/plugin-syntax-jsx), https://github.com/babel/babel.git (@babel/plugin-syntax-logical-assignment-operators), https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-nullish-coalescing-operator (@babel/plugin-syntax-nullish-coalescing-operator), https://github.com/babel/babel.git (@babel/plugin-syntax-numeric-separator), https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-object-rest-spread (@babel/plugin-syntax-object-rest-spread), https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-optional-catch-binding (@babel/plugin-syntax-optional-catch-binding), https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-optional-chaining (@babel/plugin-syntax-optional-chaining), https://github.com/babel/babel.git (@babel/plugin-syntax-top-level-await), https://github.com/babel/babel.git (@babel/plugin-syntax-typescript), https://github.com/babel/babel.git (@babel/plugin-transform-arrow-functions), https://github.com/babel/babel.git (@babel/plugin-transform-block-scoped-functions), https://github.com/babel/babel.git (@babel/plugin-transform-block-scoping), https://github.com/babel/babel.git (@babel/plugin-transform-classes), https://github.com/babel/babel.git (@babel/plugin-transform-computed-properties), https://github.com/babel/babel.git (@babel/plugin-transform-destructuring), https://github.com/babel/babel.git (@babel/plugin-transform-flow-strip-types), https://github.com/babel/babel.git (@babel/plugin-transform-for-of), https://github.com/babel/babel.git (@babel/plugin-transform-function-name), https://github.com/babel/babel.git (@babel/plugin-transform-literals), https://github.com/babel/babel.git (@babel/plugin-transform-member-expression-literals), https://github.com/babel/babel.git (@babel/plugin-transform-modules-commonjs), https://github.com/babel/babel.git (@babel/plugin-transform-object-super), https://github.com/babel/babel.git (@babel/plugin-transform-parameters), https://github.com/babel/babel.git (@babel/plugin-transform-property-literals), https://github.com/babel/babel.git (@babel/plugin-transform-react-display-name), https://github.com/babel/babel.git (@babel/plugin-transform-react-jsx), https://github.com/babel/babel.git (@babel/plugin-transform-shorthand-properties), https://github.com/babel/babel.git (@babel/plugin-transform-spread), https://github.com/babel/babel.git (@babel/plugin-transform-template-literals), https://github.com/babel/babel.git (@babel/plugin-transform-typescript), https://github.com/babel/babel.git (@babel/runtime), https://github.com/babel/babel.git (@babel/template), https://github.com/babel/babel.git (@babel/traverse), https://github.com/babel/babel.git (@babel/types). This software contains the following license and notice below: +The following software may be included in this product: @babel/cli, @babel/code-frame, @babel/compat-data, @babel/core, @babel/generator, @babel/helper-annotate-as-pure, @babel/helper-compilation-targets, @babel/helper-create-class-features-plugin, @babel/helper-environment-visitor, @babel/helper-function-name, @babel/helper-hoist-variables, @babel/helper-member-expression-to-functions, @babel/helper-module-imports, @babel/helper-module-transforms, @babel/helper-optimise-call-expression, @babel/helper-plugin-utils, @babel/helper-replace-supers, @babel/helper-simple-access, @babel/helper-skip-transparent-expression-wrappers, @babel/helper-split-export-declaration, @babel/helper-string-parser, @babel/helper-validator-identifier, @babel/helper-validator-option, @babel/helpers, @babel/highlight, @babel/plugin-proposal-numeric-separator, @babel/plugin-syntax-async-generators, @babel/plugin-syntax-bigint, @babel/plugin-syntax-class-properties, @babel/plugin-syntax-import-meta, @babel/plugin-syntax-json-strings, @babel/plugin-syntax-logical-assignment-operators, @babel/plugin-syntax-nullish-coalescing-operator, @babel/plugin-syntax-numeric-separator, @babel/plugin-syntax-object-rest-spread, @babel/plugin-syntax-optional-catch-binding, @babel/plugin-syntax-optional-chaining, @babel/plugin-syntax-top-level-await, @babel/plugin-syntax-typescript, @babel/plugin-transform-modules-commonjs, @babel/plugin-transform-typescript, @babel/runtime, @babel/template, @babel/traverse, @babel/types. A copy of the source code may be downloaded from https://github.com/babel/babel.git (@babel/cli), https://github.com/babel/babel.git (@babel/code-frame), https://github.com/babel/babel.git (@babel/compat-data), https://github.com/babel/babel.git (@babel/core), https://github.com/babel/babel.git (@babel/generator), https://github.com/babel/babel.git (@babel/helper-annotate-as-pure), https://github.com/babel/babel.git (@babel/helper-compilation-targets), https://github.com/babel/babel.git (@babel/helper-create-class-features-plugin), https://github.com/babel/babel.git (@babel/helper-environment-visitor), https://github.com/babel/babel.git (@babel/helper-function-name), https://github.com/babel/babel.git (@babel/helper-hoist-variables), https://github.com/babel/babel.git (@babel/helper-member-expression-to-functions), https://github.com/babel/babel.git (@babel/helper-module-imports), https://github.com/babel/babel.git (@babel/helper-module-transforms), https://github.com/babel/babel.git (@babel/helper-optimise-call-expression), https://github.com/babel/babel.git (@babel/helper-plugin-utils), https://github.com/babel/babel.git (@babel/helper-replace-supers), https://github.com/babel/babel.git (@babel/helper-simple-access), https://github.com/babel/babel.git (@babel/helper-skip-transparent-expression-wrappers), https://github.com/babel/babel.git (@babel/helper-split-export-declaration), https://github.com/babel/babel.git (@babel/helper-string-parser), https://github.com/babel/babel.git (@babel/helper-validator-identifier), https://github.com/babel/babel.git (@babel/helper-validator-option), https://github.com/babel/babel.git (@babel/helpers), https://github.com/babel/babel.git (@babel/highlight), https://github.com/babel/babel.git (@babel/plugin-proposal-numeric-separator), https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-async-generators (@babel/plugin-syntax-async-generators), https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-bigint (@babel/plugin-syntax-bigint), https://github.com/babel/babel.git (@babel/plugin-syntax-class-properties), https://github.com/babel/babel.git (@babel/plugin-syntax-import-meta), https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-json-strings (@babel/plugin-syntax-json-strings), https://github.com/babel/babel.git (@babel/plugin-syntax-logical-assignment-operators), https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-nullish-coalescing-operator (@babel/plugin-syntax-nullish-coalescing-operator), https://github.com/babel/babel.git (@babel/plugin-syntax-numeric-separator), https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-object-rest-spread (@babel/plugin-syntax-object-rest-spread), https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-optional-catch-binding (@babel/plugin-syntax-optional-catch-binding), https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-optional-chaining (@babel/plugin-syntax-optional-chaining), https://github.com/babel/babel.git (@babel/plugin-syntax-top-level-await), https://github.com/babel/babel.git (@babel/plugin-syntax-typescript), https://github.com/babel/babel.git (@babel/plugin-transform-modules-commonjs), https://github.com/babel/babel.git (@babel/plugin-transform-typescript), https://github.com/babel/babel.git (@babel/runtime), https://github.com/babel/babel.git (@babel/template), https://github.com/babel/babel.git (@babel/traverse), https://github.com/babel/babel.git (@babel/types). This software contains the following license and notice below: MIT License @@ -4277,52 +4416,6 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I ----- -The following software may be included in this product: @graphql-typed-document-node/core. A copy of the source code may be downloaded from git@github.com:dotansimha/graphql-typed-document-node.git. This software contains the following license and notice below: - -MIT License - -Copyright (c) 2020-2023 Dotan Simha - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - -The following software may be included in this product: @hapi/hoek. A copy of the source code may be downloaded from git://github.com/hapijs/hoek. This software contains the following license and notice below: - -Copyright (c) 2011-2020, Sideway Inc, and project contributors -Copyright (c) 2011-2014, Walmart -Copyright (c) 2011, Yahoo Inc. - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -* The names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS OFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------ - -The following software may be included in this product: @hapi/topo. A copy of the source code may be downloaded from git://github.com/hapijs/topo. This software contains the following license and notice below: - -Copyright (c) 2012-2020, Sideway Inc, and project contributors -Copyright (c) 2012-2014, Walmart. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -* The names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS OFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------ - The following software may be included in this product: @humanwhocodes/config-array, @humanwhocodes/module-importer, @pkgjs/parseargs. A copy of the source code may be downloaded from git+https://github.com/humanwhocodes/config-array.git (@humanwhocodes/config-array), git+https://github.com/humanwhocodes/module-importer.git (@humanwhocodes/module-importer), git@github.com:pkgjs/parseargs.git (@pkgjs/parseargs). This software contains the following license and notice below: Apache License @@ -4649,6 +4742,32 @@ SOFTWARE. ----- +The following software may be included in this product: @jest/console, @jest/core, @jest/environment, @jest/fake-timers, @jest/globals, @jest/reporters, @jest/source-map, @jest/test-result, @jest/test-sequencer, @jest/transform, @jest/types, babel-jest, babel-plugin-jest-hoist, babel-preset-jest, diff-sequences, expect, jest, jest-changed-files, jest-circus, jest-cli, jest-config, jest-diff, jest-docblock, jest-each, jest-environment-jsdom, jest-environment-node, jest-get-type, jest-haste-map, jest-jasmine2, jest-leak-detector, jest-matcher-utils, jest-message-util, jest-mock, jest-regex-util, jest-resolve, jest-resolve-dependencies, jest-runner, jest-runtime, jest-serializer, jest-snapshot, jest-util, jest-validate, jest-watcher, jest-worker, pretty-format, react-is. A copy of the source code may be downloaded from https://github.com/facebook/jest.git (@jest/console), https://github.com/facebook/jest (@jest/core), https://github.com/facebook/jest.git (@jest/environment), https://github.com/facebook/jest.git (@jest/fake-timers), https://github.com/facebook/jest.git (@jest/globals), https://github.com/facebook/jest (@jest/reporters), https://github.com/facebook/jest.git (@jest/source-map), https://github.com/facebook/jest.git (@jest/test-result), https://github.com/facebook/jest.git (@jest/test-sequencer), https://github.com/facebook/jest.git (@jest/transform), https://github.com/facebook/jest.git (@jest/types), https://github.com/facebook/jest.git (babel-jest), https://github.com/facebook/jest.git (babel-plugin-jest-hoist), https://github.com/facebook/jest.git (babel-preset-jest), https://github.com/facebook/jest.git (diff-sequences), https://github.com/facebook/jest.git (expect), https://github.com/facebook/jest (jest), https://github.com/facebook/jest.git (jest-changed-files), https://github.com/facebook/jest.git (jest-circus), https://github.com/facebook/jest (jest-cli), https://github.com/facebook/jest.git (jest-config), https://github.com/facebook/jest.git (jest-diff), https://github.com/facebook/jest.git (jest-docblock), https://github.com/facebook/jest.git (jest-each), https://github.com/facebook/jest.git (jest-environment-jsdom), https://github.com/facebook/jest.git (jest-environment-node), https://github.com/facebook/jest.git (jest-get-type), https://github.com/facebook/jest.git (jest-haste-map), https://github.com/facebook/jest.git (jest-jasmine2), https://github.com/facebook/jest.git (jest-leak-detector), https://github.com/facebook/jest.git (jest-matcher-utils), https://github.com/facebook/jest.git (jest-message-util), https://github.com/facebook/jest.git (jest-mock), https://github.com/facebook/jest.git (jest-regex-util), https://github.com/facebook/jest.git (jest-resolve), https://github.com/facebook/jest.git (jest-resolve-dependencies), https://github.com/facebook/jest.git (jest-runner), https://github.com/facebook/jest.git (jest-runtime), https://github.com/facebook/jest.git (jest-serializer), https://github.com/facebook/jest.git (jest-snapshot), https://github.com/facebook/jest.git (jest-util), https://github.com/facebook/jest.git (jest-validate), https://github.com/facebook/jest (jest-watcher), https://github.com/facebook/jest.git (jest-worker), https://github.com/facebook/jest.git (pretty-format), https://github.com/facebook/react.git (react-is). This software contains the following license and notice below: + +MIT License + +Copyright (c) Facebook, Inc. and its affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + The following software may be included in this product: @jridgewell/gen-mapping, @jridgewell/set-array. A copy of the source code may be downloaded from https://github.com/jridgewell/gen-mapping (@jridgewell/gen-mapping), https://github.com/jridgewell/set-array (@jridgewell/set-array). This software contains the following license and notice below: Copyright 2022 Justin Ridgewell @@ -5765,7 +5884,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----- -The following software may be included in this product: @sinonjs/fake-timers. A copy of the source code may be downloaded from https://github.com/sinonjs/fake-timers.git. This software contains the following license and notice below: +The following software may be included in this product: @sinonjs/fake-timers. A copy of the source code may be downloaded from http://github.com/sinonjs/fake-timers.git. This software contains the following license and notice below: Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no. All rights reserved. @@ -5781,280 +5900,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ----- -The following software may be included in this product: @sinonjs/samsam. A copy of the source code may be downloaded from https://github.com/sinonjs/samsam.git. This software contains the following license and notice below: - -(The BSD License) - -Copyright (c) 2010-2012, Christian Johansen, christian@cjohansen.no and -August Lilleaas, august.lilleaas@gmail.com. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of Christian Johansen nor the names of his contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------ - -The following software may be included in this product: @sinonjs/text-encoding. A copy of the source code may be downloaded from https://github.com/sinonjs/text-encoding.git. This software contains the following license and notice below: - -The encoding indexes, algorithms, and many comments in the code -derive from the Encoding Standard https://encoding.spec.whatwg.org/ - -Otherwise, the code of this repository is released under the Unlicense -license and is also dual-licensed under an Apache 2.0 license. Both -are included below. - -# Unlicense - -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to - -# Apache 2.0 License - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ------ - The following software may be included in this product: @size-limit/file, @size-limit/preset-small-lib, @size-limit/webpack, ci-job-number, nanoid, size-limit. A copy of the source code may be downloaded from https://github.com/ai/size-limit.git (@size-limit/file), https://github.com/ai/size-limit.git (@size-limit/preset-small-lib), https://github.com/ai/size-limit.git (@size-limit/webpack), https://github.com/ai/ci-job-number.git (ci-job-number), https://github.com/ai/nanoid.git (nanoid), https://github.com/ai/size-limit.git (size-limit). This software contains the following license and notice below: The MIT License (MIT) @@ -6281,7 +6126,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: @types/archy, @types/aws-lambda, @types/babel__core, @types/babel__generator, @types/babel__template, @types/babel__traverse, @types/detect-port, @types/eslint, @types/eslint-scope, @types/estree, @types/fs-extra, @types/glob, @types/graceful-fs, @types/hjson, @types/http-cache-semantics, @types/ini, @types/istanbul-lib-coverage, @types/istanbul-lib-report, @types/istanbul-reports, @types/jest, @types/js-yaml, @types/json-schema, @types/lodash, @types/md5, @types/minimatch, @types/minimist, @types/mock-fs, @types/node, @types/normalize-package-data, @types/object-hash, @types/pako, @types/prettier, @types/semver, @types/stack-utils, @types/triple-beam, @types/uuid, @types/ws, @types/yargs, @types/yargs-parser, @types/zen-observable. A copy of the source code may be downloaded from https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/archy), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/aws-lambda), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/babel__core), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/babel__generator), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/babel__template), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/babel__traverse), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/detect-port), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/eslint), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/eslint-scope), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/estree), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/fs-extra), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/glob), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/graceful-fs), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/hjson), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/http-cache-semantics), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/ini), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/istanbul-lib-coverage), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/istanbul-lib-report), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/istanbul-reports), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/jest), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/js-yaml), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/json-schema), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/lodash), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/md5), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/minimatch), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/minimist), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/mock-fs), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/node), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/normalize-package-data), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/object-hash), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/pako), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/prettier), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/semver), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/stack-utils), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/triple-beam), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/uuid), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/ws), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/yargs), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/yargs-parser), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/zen-observable). This software contains the following license and notice below: +The following software may be included in this product: @types/archy, @types/aws-lambda, @types/babel__core, @types/babel__generator, @types/babel__template, @types/babel__traverse, @types/eslint, @types/eslint-scope, @types/estree, @types/fs-extra, @types/glob, @types/graceful-fs, @types/hjson, @types/http-cache-semantics, @types/ini, @types/istanbul-lib-coverage, @types/istanbul-lib-report, @types/istanbul-reports, @types/jest, @types/js-yaml, @types/json-schema, @types/lodash, @types/md5, @types/minimatch, @types/minimist, @types/mock-fs, @types/node, @types/normalize-package-data, @types/object-hash, @types/pako, @types/prettier, @types/semver, @types/stack-utils, @types/triple-beam, @types/uuid, @types/ws, @types/yargs, @types/yargs-parser, @types/zen-observable. A copy of the source code may be downloaded from https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/archy), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/aws-lambda), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/babel__core), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/babel__generator), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/babel__template), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/babel__traverse), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/eslint), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/eslint-scope), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/estree), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/fs-extra), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/glob), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/graceful-fs), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/hjson), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/http-cache-semantics), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/ini), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/istanbul-lib-coverage), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/istanbul-lib-report), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/istanbul-reports), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/jest), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/js-yaml), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/json-schema), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/lodash), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/md5), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/minimatch), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/minimist), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/mock-fs), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/node), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/normalize-package-data), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/object-hash), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/pako), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/prettier), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/semver), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/stack-utils), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/triple-beam), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/uuid), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/ws), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/yargs), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/yargs-parser), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/zen-observable). This software contains the following license and notice below: MIT License @@ -6307,7 +6152,7 @@ MIT License ----- -The following software may be included in this product: @types/argparse, @types/async, @types/cookie, @types/jest, @types/parse-json, @types/pluralize, @types/which, @types/zen-observable. A copy of the source code may be downloaded from https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/argparse), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/async), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/cookie), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/jest), https://www.github.com/DefinitelyTyped/DefinitelyTyped.git (@types/parse-json), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/pluralize), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/which), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/zen-observable). This software contains the following license and notice below: +The following software may be included in this product: @types/argparse, @types/async, @types/cookie, @types/jest, @types/parse-json, @types/pluralize, @types/zen-observable. A copy of the source code may be downloaded from https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/argparse), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/async), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/cookie), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/jest), https://www.github.com/DefinitelyTyped/DefinitelyTyped.git (@types/parse-json), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/pluralize), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/zen-observable). This software contains the following license and notice below: MIT License @@ -6867,34 +6712,6 @@ OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: accepts, mime-types. A copy of the source code may be downloaded from https://github.com/jshttp/accepts.git (accepts), https://github.com/jshttp/mime-types.git (mime-types). This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2014 Jonathan Ong -Copyright (c) 2015 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: acorn. A copy of the source code may be downloaded from https://github.com/acornjs/acorn.git. This software contains the following license and notice below: MIT License @@ -7045,33 +6862,6 @@ THE SOFTWARE. ----- -The following software may be included in this product: address. A copy of the source code may be downloaded from git://github.com/node-modules/address.git. This software contains the following license and notice below: - -This software is licensed under the MIT License. - -Copyright (C) 2013 - 2014 fengmk2 -Copyright (C) 2015 - present node-modules and other contributors. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - The following software may be included in this product: agentkeepalive. A copy of the source code may be downloaded from git://github.com/node-modules/agentkeepalive.git. This software contains the following license and notice below: The MIT License @@ -7100,6 +6890,20 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- +The following software may be included in this product: aggregate-error, ansi-escapes, ansi-regex, ansi-styles, any-observable, array-differ, array-union, arrify, callsites, camelcase, camelcase-keys, chalk, clean-stack, cli-cursor, dargs, decamelize, define-lazy-prop, del, detect-indent, detect-newline, dot-prop, env-paths, escape-string-regexp, execa, find-up, get-port, get-stdin, get-stream, global-dirs, globals, globby, got, hard-rejection, has-flag, import-lazy, import-local, indent-string, is-fullwidth-code-point, is-generator-fn, is-interactive, is-obj, is-observable, is-path-cwd, is-path-inside, is-plain-obj, is-wsl, leven, load-json-file, locate-path, log-symbols, log-update, make-dir, mimic-fn, normalize-url, npm-run-path, p-finally, p-is-promise, p-limit, p-locate, p-map, p-map-series, p-reduce, p-timeout, p-try, parent-module, parse-json, path-exists, path-key, path-type, pify, pkg-dir, quick-lru, read-pkg, read-pkg-up, redent, remote-git-tags, resolve-cwd, resolve-from, resolve-global, resolve-pkg, restore-cursor, run-node, shebang-regex, slash, sort-keys, string-width, string-width-cjs, strip-ansi, strip-ansi-cjs, strip-bom, strip-final-newline, strip-indent, supports-color, terminal-link, text-extensions, tildify, trim-newlines, type-fest, untildify, wrap-ansi, write-json-file, write-pkg, yn. A copy of the source code may be downloaded from https://github.com/sindresorhus/aggregate-error.git (aggregate-error), https://github.com/sindresorhus/ansi-escapes.git (ansi-escapes), https://github.com/chalk/ansi-regex.git (ansi-regex), https://github.com/chalk/ansi-styles.git (ansi-styles), https://github.com/sindresorhus/any-observable.git (any-observable), https://github.com/sindresorhus/array-differ.git (array-differ), https://github.com/sindresorhus/array-union.git (array-union), https://github.com/sindresorhus/arrify.git (arrify), https://github.com/sindresorhus/callsites.git (callsites), https://github.com/sindresorhus/camelcase.git (camelcase), https://github.com/sindresorhus/camelcase-keys.git (camelcase-keys), https://github.com/chalk/chalk.git (chalk), https://github.com/sindresorhus/clean-stack.git (clean-stack), https://github.com/sindresorhus/cli-cursor.git (cli-cursor), https://github.com/sindresorhus/dargs.git (dargs), https://github.com/sindresorhus/decamelize.git (decamelize), https://github.com/sindresorhus/define-lazy-prop.git (define-lazy-prop), https://github.com/sindresorhus/del.git (del), https://github.com/sindresorhus/detect-indent.git (detect-indent), https://github.com/sindresorhus/detect-newline.git (detect-newline), https://github.com/sindresorhus/dot-prop.git (dot-prop), https://github.com/sindresorhus/env-paths.git (env-paths), https://github.com/sindresorhus/escape-string-regexp.git (escape-string-regexp), https://github.com/sindresorhus/execa.git (execa), https://github.com/sindresorhus/find-up.git (find-up), https://github.com/sindresorhus/get-port.git (get-port), https://github.com/sindresorhus/get-stdin.git (get-stdin), https://github.com/sindresorhus/get-stream.git (get-stream), https://github.com/sindresorhus/global-dirs.git (global-dirs), https://github.com/sindresorhus/globals.git (globals), https://github.com/sindresorhus/globby.git (globby), https://github.com/sindresorhus/got.git (got), https://github.com/sindresorhus/hard-rejection.git (hard-rejection), https://github.com/sindresorhus/has-flag.git (has-flag), https://github.com/sindresorhus/import-lazy.git (import-lazy), https://github.com/sindresorhus/import-local.git (import-local), https://github.com/sindresorhus/indent-string.git (indent-string), https://github.com/sindresorhus/is-fullwidth-code-point.git (is-fullwidth-code-point), https://github.com/sindresorhus/is-generator-fn.git (is-generator-fn), https://github.com/sindresorhus/is-interactive.git (is-interactive), https://github.com/sindresorhus/is-obj.git (is-obj), https://github.com/sindresorhus/is-observable.git (is-observable), https://github.com/sindresorhus/is-path-cwd.git (is-path-cwd), https://github.com/sindresorhus/is-path-inside.git (is-path-inside), https://github.com/sindresorhus/is-plain-obj.git (is-plain-obj), https://github.com/sindresorhus/is-wsl.git (is-wsl), https://github.com/sindresorhus/leven.git (leven), https://github.com/sindresorhus/load-json-file.git (load-json-file), https://github.com/sindresorhus/locate-path.git (locate-path), https://github.com/sindresorhus/log-symbols.git (log-symbols), https://github.com/sindresorhus/log-update.git (log-update), https://github.com/sindresorhus/make-dir.git (make-dir), https://github.com/sindresorhus/mimic-fn.git (mimic-fn), https://github.com/sindresorhus/normalize-url.git (normalize-url), https://github.com/sindresorhus/npm-run-path.git (npm-run-path), https://github.com/sindresorhus/p-finally.git (p-finally), https://github.com/sindresorhus/p-is-promise.git (p-is-promise), https://github.com/sindresorhus/p-limit.git (p-limit), https://github.com/sindresorhus/p-locate.git (p-locate), https://github.com/sindresorhus/p-map.git (p-map), https://github.com/sindresorhus/p-map-series.git (p-map-series), https://github.com/sindresorhus/p-reduce.git (p-reduce), https://github.com/sindresorhus/p-timeout.git (p-timeout), https://github.com/sindresorhus/p-try.git (p-try), https://github.com/sindresorhus/parent-module.git (parent-module), https://github.com/sindresorhus/parse-json.git (parse-json), https://github.com/sindresorhus/path-exists.git (path-exists), https://github.com/sindresorhus/path-key.git (path-key), https://github.com/sindresorhus/path-type.git (path-type), https://github.com/sindresorhus/pify.git (pify), https://github.com/sindresorhus/pkg-dir.git (pkg-dir), https://github.com/sindresorhus/quick-lru.git (quick-lru), https://github.com/sindresorhus/read-pkg.git (read-pkg), https://github.com/sindresorhus/read-pkg-up.git (read-pkg-up), https://github.com/sindresorhus/redent.git (redent), https://github.com/sindresorhus/remote-git-tags.git (remote-git-tags), https://github.com/sindresorhus/resolve-cwd.git (resolve-cwd), https://github.com/sindresorhus/resolve-from.git (resolve-from), https://github.com/sindresorhus/resolve-global.git (resolve-global), https://github.com/sindresorhus/resolve-pkg.git (resolve-pkg), https://github.com/sindresorhus/restore-cursor.git (restore-cursor), https://github.com/sindresorhus/run-node.git (run-node), https://github.com/sindresorhus/shebang-regex.git (shebang-regex), https://github.com/sindresorhus/slash.git (slash), https://github.com/sindresorhus/sort-keys.git (sort-keys), https://github.com/sindresorhus/string-width.git (string-width), https://github.com/sindresorhus/string-width.git (string-width-cjs), https://github.com/chalk/strip-ansi.git (strip-ansi), https://github.com/chalk/strip-ansi.git (strip-ansi-cjs), https://github.com/sindresorhus/strip-bom.git (strip-bom), https://github.com/sindresorhus/strip-final-newline.git (strip-final-newline), https://github.com/sindresorhus/strip-indent.git (strip-indent), https://github.com/chalk/supports-color.git (supports-color), https://github.com/sindresorhus/terminal-link.git (terminal-link), https://github.com/sindresorhus/text-extensions.git (text-extensions), https://github.com/sindresorhus/tildify.git (tildify), https://github.com/sindresorhus/trim-newlines.git (trim-newlines), https://github.com/sindresorhus/type-fest.git (type-fest), https://github.com/sindresorhus/untildify.git (untildify), https://github.com/chalk/wrap-ansi.git (wrap-ansi), https://github.com/sindresorhus/write-json-file.git (write-json-file), https://github.com/sindresorhus/write-pkg.git (write-pkg), https://github.com/sindresorhus/yn.git (yn). This software contains the following license and notice below: + +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: ajv. A copy of the source code may be downloaded from https://github.com/ajv-validator/ajv.git. This software contains the following license and notice below: The MIT License (MIT) @@ -7349,31 +7153,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: amplify-velocity-template. A copy of the source code may be downloaded from https://github.com/aws-amplify/amplify-cli.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2012-2013 Eward Song - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the 'Software'), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: ansi-align, which-module. A copy of the source code may be downloaded from git+https://github.com/nexdrew/ansi-align.git (ansi-align), git+https://github.com/nexdrew/which-module.git (which-module). This software contains the following license and notice below: Copyright (c) 2016, Contributors @@ -7418,7 +7197,7 @@ THE SOFTWARE. ----- -The following software may be included in this product: ansi-regex, ansi-styles, arrify, caller-callsite, caller-path, callsites, chalk, cli-cursor, cli-truncate, code-point-at, decamelize, detect-indent, detect-newline, elegant-spinner, escape-string-regexp, figures, find-up, git-remote-origin-url, has-ansi, import-fresh, is-fullwidth-code-point, is-obj, is-plain-obj, is-stream, is-text-path, load-json-file, locate-path, log-symbols, map-obj, modify-values, npm-run-path, number-is-nan, object-assign, onetime, os-tmpdir, p-finally, p-locate, p-try, path-exists, path-is-absolute, path-key, pify, repeating, resolve-from, restore-cursor, shebang-regex, string-width, strip-ansi, strip-bom, strip-eof, strip-json-comments, supports-color, temp-dir, trim-right. A copy of the source code may be downloaded from https://github.com/chalk/ansi-regex.git (ansi-regex), https://github.com/chalk/ansi-styles.git (ansi-styles), https://github.com/sindresorhus/arrify.git (arrify), https://github.com/sindresorhus/caller-callsite.git (caller-callsite), https://github.com/sindresorhus/caller-path.git (caller-path), https://github.com/sindresorhus/callsites.git (callsites), https://github.com/chalk/chalk.git (chalk), https://github.com/sindresorhus/cli-cursor.git (cli-cursor), https://github.com/sindresorhus/cli-truncate.git (cli-truncate), https://github.com/sindresorhus/code-point-at.git (code-point-at), https://github.com/sindresorhus/decamelize.git (decamelize), https://github.com/sindresorhus/detect-indent.git (detect-indent), https://github.com/sindresorhus/detect-newline.git (detect-newline), https://github.com/sindresorhus/elegant-spinner.git (elegant-spinner), https://github.com/sindresorhus/escape-string-regexp.git (escape-string-regexp), https://github.com/sindresorhus/figures.git (figures), https://github.com/sindresorhus/find-up.git (find-up), https://github.com/sindresorhus/git-remote-origin-url.git (git-remote-origin-url), https://github.com/sindresorhus/has-ansi.git (has-ansi), https://github.com/sindresorhus/import-fresh.git (import-fresh), https://github.com/sindresorhus/is-fullwidth-code-point.git (is-fullwidth-code-point), https://github.com/sindresorhus/is-obj.git (is-obj), https://github.com/sindresorhus/is-plain-obj.git (is-plain-obj), https://github.com/sindresorhus/is-stream.git (is-stream), https://github.com/sindresorhus/is-text-path.git (is-text-path), https://github.com/sindresorhus/load-json-file.git (load-json-file), https://github.com/sindresorhus/locate-path.git (locate-path), https://github.com/sindresorhus/log-symbols.git (log-symbols), https://github.com/sindresorhus/map-obj.git (map-obj), https://github.com/sindresorhus/modify-values.git (modify-values), https://github.com/sindresorhus/npm-run-path.git (npm-run-path), https://github.com/sindresorhus/number-is-nan.git (number-is-nan), https://github.com/sindresorhus/object-assign.git (object-assign), https://github.com/sindresorhus/onetime.git (onetime), https://github.com/sindresorhus/os-tmpdir.git (os-tmpdir), https://github.com/sindresorhus/p-finally.git (p-finally), https://github.com/sindresorhus/p-locate.git (p-locate), https://github.com/sindresorhus/p-try.git (p-try), https://github.com/sindresorhus/path-exists.git (path-exists), https://github.com/sindresorhus/path-is-absolute.git (path-is-absolute), https://github.com/sindresorhus/path-key.git (path-key), https://github.com/sindresorhus/pify.git (pify), https://github.com/sindresorhus/repeating.git (repeating), https://github.com/sindresorhus/resolve-from.git (resolve-from), https://github.com/sindresorhus/restore-cursor.git (restore-cursor), https://github.com/sindresorhus/shebang-regex.git (shebang-regex), https://github.com/sindresorhus/string-width.git (string-width), https://github.com/chalk/strip-ansi.git (strip-ansi), https://github.com/sindresorhus/strip-bom.git (strip-bom), https://github.com/sindresorhus/strip-eof.git (strip-eof), https://github.com/sindresorhus/strip-json-comments.git (strip-json-comments), https://github.com/chalk/supports-color.git (supports-color), https://github.com/sindresorhus/temp-dir.git (temp-dir), https://github.com/sindresorhus/trim-right.git (trim-right). This software contains the following license and notice below: +The following software may be included in this product: ansi-regex, ansi-styles, arrify, caller-callsite, caller-path, callsites, chalk, cli-cursor, cli-truncate, code-point-at, decamelize, detect-indent, detect-newline, elegant-spinner, escape-string-regexp, figures, find-up, git-remote-origin-url, has-ansi, import-fresh, is-fullwidth-code-point, is-obj, is-plain-obj, is-stream, is-text-path, load-json-file, locate-path, log-symbols, map-obj, modify-values, npm-run-path, number-is-nan, object-assign, onetime, os-tmpdir, p-finally, p-locate, p-try, path-exists, path-is-absolute, path-key, pify, resolve-from, restore-cursor, shebang-regex, string-width, strip-ansi, strip-bom, strip-eof, strip-json-comments, supports-color, temp-dir. A copy of the source code may be downloaded from https://github.com/chalk/ansi-regex.git (ansi-regex), https://github.com/chalk/ansi-styles.git (ansi-styles), https://github.com/sindresorhus/arrify.git (arrify), https://github.com/sindresorhus/caller-callsite.git (caller-callsite), https://github.com/sindresorhus/caller-path.git (caller-path), https://github.com/sindresorhus/callsites.git (callsites), https://github.com/chalk/chalk.git (chalk), https://github.com/sindresorhus/cli-cursor.git (cli-cursor), https://github.com/sindresorhus/cli-truncate.git (cli-truncate), https://github.com/sindresorhus/code-point-at.git (code-point-at), https://github.com/sindresorhus/decamelize.git (decamelize), https://github.com/sindresorhus/detect-indent.git (detect-indent), https://github.com/sindresorhus/detect-newline.git (detect-newline), https://github.com/sindresorhus/elegant-spinner.git (elegant-spinner), https://github.com/sindresorhus/escape-string-regexp.git (escape-string-regexp), https://github.com/sindresorhus/figures.git (figures), https://github.com/sindresorhus/find-up.git (find-up), https://github.com/sindresorhus/git-remote-origin-url.git (git-remote-origin-url), https://github.com/sindresorhus/has-ansi.git (has-ansi), https://github.com/sindresorhus/import-fresh.git (import-fresh), https://github.com/sindresorhus/is-fullwidth-code-point.git (is-fullwidth-code-point), https://github.com/sindresorhus/is-obj.git (is-obj), https://github.com/sindresorhus/is-plain-obj.git (is-plain-obj), https://github.com/sindresorhus/is-stream.git (is-stream), https://github.com/sindresorhus/is-text-path.git (is-text-path), https://github.com/sindresorhus/load-json-file.git (load-json-file), https://github.com/sindresorhus/locate-path.git (locate-path), https://github.com/sindresorhus/log-symbols.git (log-symbols), https://github.com/sindresorhus/map-obj.git (map-obj), https://github.com/sindresorhus/modify-values.git (modify-values), https://github.com/sindresorhus/npm-run-path.git (npm-run-path), https://github.com/sindresorhus/number-is-nan.git (number-is-nan), https://github.com/sindresorhus/object-assign.git (object-assign), https://github.com/sindresorhus/onetime.git (onetime), https://github.com/sindresorhus/os-tmpdir.git (os-tmpdir), https://github.com/sindresorhus/p-finally.git (p-finally), https://github.com/sindresorhus/p-locate.git (p-locate), https://github.com/sindresorhus/p-try.git (p-try), https://github.com/sindresorhus/path-exists.git (path-exists), https://github.com/sindresorhus/path-is-absolute.git (path-is-absolute), https://github.com/sindresorhus/path-key.git (path-key), https://github.com/sindresorhus/pify.git (pify), https://github.com/sindresorhus/resolve-from.git (resolve-from), https://github.com/sindresorhus/restore-cursor.git (restore-cursor), https://github.com/sindresorhus/shebang-regex.git (shebang-regex), https://github.com/sindresorhus/string-width.git (string-width), https://github.com/chalk/strip-ansi.git (strip-ansi), https://github.com/sindresorhus/strip-bom.git (strip-bom), https://github.com/sindresorhus/strip-eof.git (strip-eof), https://github.com/sindresorhus/strip-json-comments.git (strip-json-comments), https://github.com/chalk/supports-color.git (supports-color), https://github.com/sindresorhus/temp-dir.git (temp-dir). This software contains the following license and notice below: The MIT License (MIT) @@ -8275,32 +8054,6 @@ SOFTWARE. ----- -The following software may be included in this product: array-flatten, camel-case, capital-case, change-case, constant-case, dot-case, header-case, is-lower-case, is-upper-case, lower-case, lower-case-first, no-case, param-case, pascal-case, path-case, path-to-regexp, sentence-case, snake-case, swap-case, title-case, ts-node, upper-case-first. A copy of the source code may be downloaded from git://github.com/blakeembrey/array-flatten.git (array-flatten), git://github.com/blakeembrey/change-case.git (camel-case), git://github.com/blakeembrey/change-case.git (capital-case), git://github.com/blakeembrey/change-case.git (change-case), git://github.com/blakeembrey/change-case.git (constant-case), git://github.com/blakeembrey/change-case.git (dot-case), git://github.com/blakeembrey/change-case.git (header-case), git://github.com/blakeembrey/change-case.git (is-lower-case), git://github.com/blakeembrey/change-case.git (is-upper-case), git://github.com/blakeembrey/change-case.git (lower-case), git://github.com/blakeembrey/change-case.git (lower-case-first), git://github.com/blakeembrey/change-case.git (no-case), git://github.com/blakeembrey/change-case.git (param-case), git://github.com/blakeembrey/change-case.git (pascal-case), git://github.com/blakeembrey/change-case.git (path-case), https://github.com/pillarjs/path-to-regexp.git (path-to-regexp), git://github.com/blakeembrey/change-case.git (sentence-case), git://github.com/blakeembrey/change-case.git (snake-case), git://github.com/blakeembrey/change-case.git (swap-case), git://github.com/blakeembrey/change-case.git (title-case), git://github.com/TypeStrong/ts-node.git (ts-node), git://github.com/blakeembrey/change-case.git (upper-case-first). This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - The following software may be included in this product: array-includes, define-properties. A copy of the source code may be downloaded from git://github.com/es-shims/array-includes.git (array-includes), git://github.com/ljharb/define-properties.git (define-properties). This software contains the following license and notice below: The MIT License (MIT) @@ -8429,7 +8182,7 @@ IN THE SOFTWARE. ----- -The following software may be included in this product: assign-symbols, define-property, is-accessor-descriptor, is-data-descriptor, is-extendable, pascalcase, unc-path-regex. A copy of the source code may be downloaded from https://github.com/jonschlinkert/assign-symbols.git (assign-symbols), https://github.com/jonschlinkert/define-property.git (define-property), https://github.com/jonschlinkert/is-accessor-descriptor.git (is-accessor-descriptor), https://github.com/jonschlinkert/is-data-descriptor.git (is-data-descriptor), https://github.com/jonschlinkert/is-extendable.git (is-extendable), https://github.com/jonschlinkert/pascalcase.git (pascalcase), https://github.com/regexhq/unc-path-regex.git (unc-path-regex). This software contains the following license and notice below: +The following software may be included in this product: assign-symbols, define-property, is-accessor-descriptor, is-data-descriptor, is-extendable, pascalcase. A copy of the source code may be downloaded from https://github.com/jonschlinkert/assign-symbols.git (assign-symbols), https://github.com/jonschlinkert/define-property.git (define-property), https://github.com/jonschlinkert/is-accessor-descriptor.git (is-accessor-descriptor), https://github.com/jonschlinkert/is-data-descriptor.git (is-data-descriptor), https://github.com/jonschlinkert/is-extendable.git (is-extendable), https://github.com/jonschlinkert/pascalcase.git (pascalcase). This software contains the following license and notice below: The MIT License (MIT) @@ -10391,212 +10144,6 @@ Amazon Web Services, Inc. (http://aws.amazon.com/). ----- -The following software may be included in this product: aws-sdk-mock. A copy of the source code may be downloaded from git+https://github.com/dwyl/aws-sdk-mock.git. This software contains the following license and notice below: - -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2012-2018 dwyl.com - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ------ - The following software may be included in this product: axe-core. A copy of the source code may be downloaded from https://github.com/dequelabs/axe-core.git. This software contains the following license and notice below: Mozilla Public License, version 2.0 @@ -11115,32 +10662,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: babel-preset-fbjs, fbjs, fbjs-css-vars, invariant, prop-types. A copy of the source code may be downloaded from https://github.com/facebook/fbjs.git (babel-preset-fbjs), https://github.com/facebook/fbjs.git (fbjs), https://github.com/facebook/fbjs.git (fbjs-css-vars), https://github.com/zertosh/invariant (invariant), https://github.com/facebook/prop-types.git (prop-types). This software contains the following license and notice below: - -MIT License - -Copyright (c) 2013-present, Facebook, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: balanced-match. A copy of the source code may be downloaded from git://github.com/juliangruber/balanced-match.git. This software contains the following license and notice below: (MIT) @@ -11536,59 +11057,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI ----- -The following software may be included in this product: body-parser, type-is. A copy of the source code may be downloaded from https://github.com/expressjs/body-parser.git (body-parser), https://github.com/jshttp/type-is.git (type-is). This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2014 Jonathan Ong -Copyright (c) 2014-2015 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - -The following software may be included in this product: bottleneck. A copy of the source code may be downloaded from https://github.com/SGrondin/bottleneck. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2014 Simon Grondin - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: bowser. A copy of the source code may be downloaded from git+https://github.com/lancedikson/bowser.git. This software contains the following license and notice below: Copyright 2015, Dustin Diaz (the "Original Author") @@ -11823,23 +11291,6 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEAL ----- -The following software may be included in this product: buffer-equal-constant-time. A copy of the source code may be downloaded from git@github.com:goinstant/buffer-equal-constant-time.git. This software contains the following license and notice below: - -Copyright (c) 2013, GoInstant Inc., a salesforce.com company -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -* Neither the name of salesforce.com, nor GoInstant, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------ - The following software may be included in this product: buffer-from. A copy of the source code may be downloaded from https://github.com/LinusU/buffer-from.git. This software contains the following license and notice below: MIT License @@ -11915,30 +11366,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: busboy, streamsearch. A copy of the source code may be downloaded from http://github.com/mscdex/busboy.git (busboy), http://github.com/mscdex/streamsearch.git (streamsearch). This software contains the following license and notice below: - -Copyright Brian White. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. - ------ - The following software may be included in this product: byte-size. A copy of the source code may be downloaded from https://github.com/75lb/byte-size. This software contains the following license and notice below: The MIT License (MIT) @@ -11965,34 +11392,6 @@ SOFTWARE. ----- -The following software may be included in this product: bytes. A copy of the source code may be downloaded from https://github.com/visionmedia/bytes.js.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2012-2014 TJ Holowaychuk -Copyright (c) 2015 Jed Watson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: bytes-iec. A copy of the source code may be downloaded from https://github.com/Saevon/bytes.js.git. This software contains the following license and notice below: (The MIT License) @@ -12574,15 +11973,35 @@ OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: change-case-all. A copy of the source code may be downloaded from https://github.com/btxtiger/change-case-all. This software contains the following license and notice below: +The following software may be included in this product: char-regex. A copy of the source code may be downloaded from https://github.com/Richienb/char-regex.git. This software contains the following license and notice below: MIT License -Modified work: Copyright (c) 2020 Jonas Gnioui +Copyright (c) 2019 Richie Bendall -Original work: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com) +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + +The following software may be included in this product: chardet. A copy of the source code may be downloaded from git@github.com:runk/node-chardet.git. This software contains the following license and notice below: + +Copyright (C) 2018 Dmitry Shirokov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -12604,18 +12023,46 @@ THE SOFTWARE. ----- -The following software may be included in this product: change-case-all. A copy of the source code may be downloaded from https://github.com/btxtiger/change-case-all. This software contains the following license and notice below: +The following software may be included in this product: charenc, crypt. A copy of the source code may be downloaded from git://github.com/pvorb/node-charenc.git (charenc), git://github.com/pvorb/node-crypt.git (crypt). This software contains the following license and notice below: -MIT License +Copyright © 2011, Paul Vorbach. All rights reserved. +Copyright © 2009, Jeff Mott. All rights reserved. -Modified work: Copyright (c) 2020 Jonas Gnioui +All rights reserved. -Original work: +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: -Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com) +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. +* Neither the name Crypto-JS nor the names of its contributors may be used to + endorse or promote products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----- + +The following software may be included in this product: chokidar. A copy of the source code may be downloaded from git+https://github.com/paulmillr/chokidar.git. This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2012-2019 Paul Miller (https://paulmillr.com), Elan Shanker Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal +of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is @@ -12624,7 +12071,7 @@ furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER @@ -12634,198 +12081,90 @@ THE SOFTWARE. ----- -The following software may be included in this product: char-regex. A copy of the source code may be downloaded from https://github.com/Richienb/char-regex.git. This software contains the following license and notice below: +The following software may be included in this product: chrome-trace-event. A copy of the source code may be downloaded from https://github.com/samccone/chrome-trace-event.git. This software contains the following license and notice below: + +# This is the MIT license + +Copyright (c) 2015 Joyent Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + +The following software may be included in this product: ci-info, is-ci. A copy of the source code may be downloaded from https://github.com/watson/ci-info.git (ci-info), https://github.com/watson/is-ci.git (is-ci). This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2016-2018 Thomas Watson Steen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + +The following software may be included in this product: ci-info. A copy of the source code may be downloaded from https://github.com/watson/ci-info.git. This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2016 Thomas Watson Steen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + +The following software may be included in this product: circleci-api. A copy of the source code may be downloaded from https://github.com/worldturtlemedia/circleci-api. This software contains the following license and notice below: MIT License -Copyright (c) 2019 Richie Bendall - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: chardet. A copy of the source code may be downloaded from git@github.com:runk/node-chardet.git. This software contains the following license and notice below: - -Copyright (C) 2018 Dmitry Shirokov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - -The following software may be included in this product: charenc, crypt. A copy of the source code may be downloaded from git://github.com/pvorb/node-charenc.git (charenc), git://github.com/pvorb/node-crypt.git (crypt). This software contains the following license and notice below: - -Copyright © 2011, Paul Vorbach. All rights reserved. -Copyright © 2009, Jeff Mott. All rights reserved. - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, this - list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. -* Neither the name Crypto-JS nor the names of its contributors may be used to - endorse or promote products derived from this software without specific prior - written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------ - -The following software may be included in this product: chokidar. A copy of the source code may be downloaded from git+https://github.com/paulmillr/chokidar.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2012-2019 Paul Miller (https://paulmillr.com), Elan Shanker - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the “Software”), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - -The following software may be included in this product: chrome-trace-event. A copy of the source code may be downloaded from https://github.com/samccone/chrome-trace-event.git. This software contains the following license and notice below: - -# This is the MIT license - -Copyright (c) 2015 Joyent Inc. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - -The following software may be included in this product: ci-info, is-ci. A copy of the source code may be downloaded from https://github.com/watson/ci-info.git (ci-info), https://github.com/watson/is-ci.git (is-ci). This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2016-2018 Thomas Watson Steen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: ci-info, is-deflate. A copy of the source code may be downloaded from https://github.com/watson/ci-info.git (ci-info), git+https://github.com/watson/is-deflate.git (is-deflate). This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2016 Thomas Watson Steen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: circleci-api. A copy of the source code may be downloaded from https://github.com/worldturtlemedia/circleci-api. This software contains the following license and notice below: - -MIT License - -Copyright (c) 2019 WorldTurtleMedia +Copyright (c) 2019 WorldTurtleMedia Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -13418,21 +12757,6 @@ SOFTWARE. ----- -The following software may be included in this product: common-tags. A copy of the source code may be downloaded from https://github.com/declandewet/common-tags. This software contains the following license and notice below: - -License (MIT) -------------- - -Copyright © Declan de Wet - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: commondir. A copy of the source code may be downloaded from http://github.com/substack/node-commondir.git. This software contains the following license and notice below: The MIT License @@ -13926,60 +13250,6 @@ Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. ----- -The following software may be included in this product: content-disposition, forwarded, vary. A copy of the source code may be downloaded from https://github.com/jshttp/content-disposition.git (content-disposition), https://github.com/jshttp/forwarded.git (forwarded), https://github.com/jshttp/vary.git (vary). This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2014-2017 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - -The following software may be included in this product: content-type. A copy of the source code may be downloaded from https://github.com/jshttp/content-type.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2015 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: conventional-changelog-angular, conventional-changelog-conventionalcommits. A copy of the source code may be downloaded from https://github.com/conventional-changelog/conventional-changelog.git (conventional-changelog-angular), https://github.com/conventional-changelog/conventional-changelog.git (conventional-changelog-conventionalcommits). This software contains the following license and notice below: ### ISC License @@ -14158,54 +13428,6 @@ THE SOFTWARE.** ----- -The following software may be included in this product: core-js. A copy of the source code may be downloaded from https://github.com/zloirock/core-js.git. This software contains the following license and notice below: - -Copyright (c) 2014-2023 Denis Pushkarev - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - -The following software may be included in this product: core-js. A copy of the source code may be downloaded from https://github.com/zloirock/core-js.git. This software contains the following license and notice below: - -Copyright (c) 2014-2020 Denis Pushkarev - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - The following software may be included in this product: core-util-is. A copy of the source code may be downloaded from git://github.com/isaacs/core-util-is. This software contains the following license and notice below: Copyright Node.js contributors. All rights reserved. @@ -14230,33 +13452,6 @@ IN THE SOFTWARE. ----- -The following software may be included in this product: cors. A copy of the source code may be downloaded from https://github.com/expressjs/cors.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2013 Troy Goode - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: cosmiconfig. A copy of the source code may be downloaded from git+https://github.com/davidtheclark/cosmiconfig.git. This software contains the following license and notice below: The MIT License (MIT) @@ -14907,32 +14102,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI ----- -The following software may be included in this product: dataloader, graphql. A copy of the source code may be downloaded from http://github.com/graphql/dataloader.git (dataloader), https://github.com/graphql/graphql-js.git (graphql). This software contains the following license and notice below: - -MIT License - -Copyright (c) GraphQL Contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: date-fns. A copy of the source code may be downloaded from https://github.com/date-fns/date-fns. This software contains the following license and notice below: # License @@ -15529,57 +14698,6 @@ Apache License ----- -The following software may be included in this product: depd. A copy of the source code may be downloaded from https://github.com/dougwilson/nodejs-depd.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2014-2018 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - -The following software may be included in this product: dependency-graph. A copy of the source code may be downloaded from git://github.com/jriecken/dependency-graph.git. This software contains the following license and notice below: - -Copyright (C) 2013-2020 by Jim Riecken - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - The following software may be included in this product: deprecation. A copy of the source code may be downloaded from https://github.com/gr2m/deprecation.git. This software contains the following license and notice below: The ISC License @@ -15600,7 +14718,7 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ----- -The following software may be included in this product: dequal, dset, kleur. A copy of the source code may be downloaded from https://github.com/lukeed/dequal.git (dequal), https://github.com/lukeed/dset.git (dset), https://github.com/lukeed/kleur.git (kleur). This software contains the following license and notice below: +The following software may be included in this product: dequal, kleur. A copy of the source code may be downloaded from https://github.com/lukeed/dequal.git (dequal), https://github.com/lukeed/kleur.git (kleur). This software contains the following license and notice below: The MIT License (MIT) @@ -15626,58 +14744,6 @@ THE SOFTWARE. ----- -The following software may be included in this product: destroy. A copy of the source code may be downloaded from https://github.com/stream-utils/destroy.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2014 Jonathan Ong me@jongleberry.com -Copyright (c) 2015-2022 Douglas Christopher Wilson doug@somethingdoug.com - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - -The following software may be included in this product: detect-port. A copy of the source code may be downloaded from git://github.com/node-modules/detect-port.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2014 - present node-modules and other contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: diff. A copy of the source code may be downloaded from git://github.com/kpdecker/jsdiff.git. This software contains the following license and notice below: Software License Agreement (BSD License) @@ -16025,243 +15091,33 @@ SOFTWARE. ----- -The following software may be included in this product: duplexify, end-of-stream, generate-function, peek-stream, pump, pumpify, tar-fs, tar-stream. A copy of the source code may be downloaded from git://github.com/mafintosh/duplexify (duplexify), git://github.com/mafintosh/end-of-stream.git (end-of-stream), https://github.com/mafintosh/generate-function (generate-function), git://github.com/mafintosh/peek-stream (peek-stream), git://github.com/mafintosh/pump.git (pump), git://github.com/mafintosh/pumpify (pumpify), https://github.com/mafintosh/tar-fs.git (tar-fs), git+https://github.com/mafintosh/tar-stream.git (tar-stream). This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2014 Mathias Buus +The following software may be included in this product: electron-to-chromium. A copy of the source code may be downloaded from https://github.com/kilian/electron-to-chromium/. This software contains the following license and notice below: -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright 2018 Kilian Valkhof -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ----- -The following software may be included in this product: ecdsa-sig-formatter. A copy of the source code may be downloaded from git+ssh://git@github.com/Brightspace/node-ecdsa-sig-formatter.git. This software contains the following license and notice below: - -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. +The following software may be included in this product: emojis-list. A copy of the source code may be downloaded from git+https://github.com/kikobeats/emojis-list.git. This software contains the following license and notice below: - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. +The MIT License (MIT) - Copyright 2015 D2L Corporation +Copyright © 2015 Kiko Beats - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - http://www.apache.org/licenses/LICENSE-2.0 +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: ee-first, fs-readdir-recursive. A copy of the source code may be downloaded from https://github.com/jonathanong/ee-first.git (ee-first), https://github.com/fs-utils/fs-readdir-recursive.git (fs-readdir-recursive). This software contains the following license and notice below: - -The MIT License (MIT) +The following software may be included in this product: encoding. A copy of the source code may be downloaded from https://github.com/andris9/encoding.git. This software contains the following license and notice below: -Copyright (c) 2014 Jonathan Ong me@jongleberry.com +Copyright (c) 2012-2014 Andris Reinman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -16270,73 +15126,21 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - -The following software may be included in this product: electron-to-chromium. A copy of the source code may be downloaded from https://github.com/kilian/electron-to-chromium/. This software contains the following license and notice below: - -Copyright 2018 Kilian Valkhof - -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. ----- -The following software may be included in this product: emojis-list. A copy of the source code may be downloaded from git+https://github.com/kikobeats/emojis-list.git. This software contains the following license and notice below: +The following software may be included in this product: end-of-stream, generate-function, pump, tar-fs, tar-stream. A copy of the source code may be downloaded from git://github.com/mafintosh/end-of-stream.git (end-of-stream), https://github.com/mafintosh/generate-function (generate-function), git://github.com/mafintosh/pump.git (pump), https://github.com/mafintosh/tar-fs.git (tar-fs), git+https://github.com/mafintosh/tar-stream.git (tar-stream). This software contains the following license and notice below: The MIT License (MIT) -Copyright © 2015 Kiko Beats - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - -The following software may be included in this product: encodeurl. A copy of the source code may be downloaded from https://github.com/pillarjs/encodeurl.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2016 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - -The following software may be included in this product: encoding. A copy of the source code may be downloaded from https://github.com/andris9/encoding.git. This software contains the following license and notice below: - -Copyright (c) 2012-2014 Andris Reinman +Copyright (c) 2014 Mathias Buus Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -16345,13 +15149,16 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. ----- @@ -16540,35 +15347,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI ----- -The following software may be included in this product: escape-html. A copy of the source code may be downloaded from https://github.com/component/escape-html.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2012-2013 TJ Holowaychuk -Copyright (c) 2015 Andreas Lubbe -Copyright (c) 2015 Tiancheng "Timothy" Gu - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: escodegen. A copy of the source code may be downloaded from http://github.com/estools/escodegen.git. This software contains the following license and notice below: Copyright (C) 2012 Yusuke Suzuki (twitter: @Constellation) and other contributors. @@ -17173,33 +15951,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----- -The following software may be included in this product: etag, proxy-addr. A copy of the source code may be downloaded from https://github.com/jshttp/etag.git (etag), https://github.com/jshttp/proxy-addr.git (proxy-addr). This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2014-2016 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: eventemitter3. A copy of the source code may be downloaded from git://github.com/primus/eventemitter3.git. This software contains the following license and notice below: The MIT License (MIT) @@ -17511,35 +16262,6 @@ Apache License ----- -The following software may be included in this product: express. A copy of the source code may be downloaded from https://github.com/expressjs/express.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2009-2014 TJ Holowaychuk -Copyright (c) 2013-2014 Roman Shtylman -Copyright (c) 2014-2015 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: extend-shallow, mixin-deep. A copy of the source code may be downloaded from https://github.com/jonschlinkert/extend-shallow.git (extend-shallow), https://github.com/jonschlinkert/mixin-deep.git (mixin-deep). This software contains the following license and notice below: The MIT License (MIT) @@ -17566,7 +16288,7 @@ THE SOFTWARE. ----- -The following software may be included in this product: extend-shallow, parse-filepath. A copy of the source code may be downloaded from https://github.com/jonschlinkert/extend-shallow.git (extend-shallow), https://github.com/jonschlinkert/parse-filepath.git (parse-filepath). This software contains the following license and notice below: +The following software may be included in this product: extend-shallow. A copy of the source code may be downloaded from https://github.com/jonschlinkert/extend-shallow.git. This software contains the following license and notice below: The MIT License (MIT) @@ -17618,34 +16340,6 @@ SOFTWARE. ----- -The following software may be included in this product: fast-decode-uri-component. A copy of the source code may be downloaded from git+https://github.com/delvedor/fast-decode-uri-component.git. This software contains the following license and notice below: - -MIT License - -Copyright (c) 2018 Tomas Della Vedova -Copyright (c) 2017 Justin Ridgewell -Copyright (c) 2008-2009 Bjoern Hoehrmann - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: fast-deep-equal, json-schema-traverse. A copy of the source code may be downloaded from git+https://github.com/epoberezkin/fast-deep-equal.git (fast-deep-equal), git+https://github.com/epoberezkin/json-schema-traverse.git (json-schema-traverse). This software contains the following license and notice below: MIT License @@ -17753,36 +16447,6 @@ SOFTWARE. ----- -The following software may be included in this product: fast-querystring. A copy of the source code may be downloaded from git+https://github.com/anonrig/fast-querystring.git. This software contains the following license and notice below: - -Copyright (c) 2022 Yagiz Nizipli - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: fast-url-parser. A copy of the source code may be downloaded from git://github.com/petkaantonov/urlparser.git. This software contains the following license and notice below: Copyright (c) 2014 Petka Antonov @@ -17951,33 +16615,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: finalhandler. A copy of the source code may be downloaded from https://github.com/pillarjs/finalhandler.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2014-2022 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: flat. A copy of the source code may be downloaded from git://github.com/hughsk/flat.git. This software contains the following license and notice below: Copyright (c) 2014, Hugh Kennedy @@ -18067,19 +16704,6 @@ SOFTWARE. ----- -The following software may be included in this product: folder-hash. A copy of the source code may be downloaded from https://github.com/marc136/node-folder-hash.git. This software contains the following license and notice below: - -MIT License -Copyright (c) 2015 Marc Walter - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: follow-redirects. A copy of the source code may be downloaded from git@github.com:follow-redirects/follow-redirects.git. This software contains the following license and notice below: Copyright 2014–present Olivier Lalonde , James Talmage , Ruben Verborgh @@ -18225,34 +16849,6 @@ THE SOFTWARE. ----- -The following software may be included in this product: fresh. A copy of the source code may be downloaded from https://github.com/jshttp/fresh.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2012 TJ Holowaychuk -Copyright (c) 2016-2017 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: from2. A copy of the source code may be downloaded from git://github.com/hughsk/from2. This software contains the following license and notice below: ## The MIT License (MIT) ## @@ -18325,6 +16921,32 @@ OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHE ----- +The following software may be included in this product: fs-readdir-recursive. A copy of the source code may be downloaded from https://github.com/fs-utils/fs-readdir-recursive.git. This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2014 Jonathan Ong me@jongleberry.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +----- + The following software may be included in this product: fs.realpath. A copy of the source code may be downloaded from git+https://github.com/isaacs/fs.realpath.git. This software contains the following license and notice below: The ISC License @@ -18802,89 +17424,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: graphql-config. A copy of the source code may be downloaded from https://github.com/kamilkisiela/graphql-config.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2016 Kamil - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: graphql-import, graphql-request. A copy of the source code may be downloaded from git@github.com:graphcool/graphql-import.git (graphql-import), git+https://github.com/graphcool/graphql-request.git (graphql-request). This software contains the following license and notice below: +The following software may be included in this product: graphql. A copy of the source code may be downloaded from https://github.com/graphql/graphql-js.git. This software contains the following license and notice below: MIT License -Copyright (c) 2017 Graphcool - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: graphql-iso-date. A copy of the source code may be downloaded from https://github.com/excitement-engineer/graphql-iso-date.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2017 Dirk-Jan Rutten - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: graphql-subscriptions. A copy of the source code may be downloaded from https://github.com/apollostack/graphql-subscriptions.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2015 - 2016 Meteor Development Group, Inc. +Copyright (c) GraphQL Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18906,11 +17450,11 @@ SOFTWARE. ----- -The following software may be included in this product: graphql-tag, zen-observable-ts. A copy of the source code may be downloaded from git+https://github.com/apollographql/graphql-tag.git (graphql-tag), git+https://github.com/apollographql/zen-observable-ts.git (zen-observable-ts). This software contains the following license and notice below: +The following software may be included in this product: graphql-config. A copy of the source code may be downloaded from https://github.com/kamilkisiela/graphql-config.git. This software contains the following license and notice below: The MIT License (MIT) -Copyright (c) 2021 Apollo Graph, Inc. (Formerly Meteor Development Group, Inc.) +Copyright (c) 2016 Kamil Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18932,11 +17476,37 @@ SOFTWARE. ----- -The following software may be included in this product: gunzip-maybe, stream-shift. A copy of the source code may be downloaded from https://github.com/mafintosh/gunzip-maybe (gunzip-maybe), https://github.com/mafintosh/stream-shift.git (stream-shift). This software contains the following license and notice below: +The following software may be included in this product: graphql-import, graphql-request. A copy of the source code may be downloaded from git@github.com:graphcool/graphql-import.git (graphql-import), git+https://github.com/graphcool/graphql-request.git (graphql-request). This software contains the following license and notice below: + +MIT License + +Copyright (c) 2017 Graphcool + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + +The following software may be included in this product: graphql-tag, zen-observable-ts. A copy of the source code may be downloaded from git+https://github.com/apollographql/graphql-tag.git (graphql-tag), git+https://github.com/apollographql/zen-observable-ts.git (zen-observable-ts). This software contains the following license and notice below: The MIT License (MIT) -Copyright (c) 2016 Mathias Buus +Copyright (c) 2021 Apollo Graph, Inc. (Formerly Meteor Development Group, Inc.) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18945,20 +17515,20 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. ----- -The following software may be included in this product: handlebars. A copy of the source code may be downloaded from https://github.com/wycats/handlebars.js.git. This software contains the following license and notice below: +The following software may be included in this product: handlebars. A copy of the source code may be downloaded from https://github.com/handlebars-lang/handlebars.js.git. This software contains the following license and notice below: Copyright (C) 2011-2019 by Yehuda Katz @@ -19146,33 +17716,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ----- -The following software may be included in this product: http-errors. A copy of the source code may be downloaded from https://github.com/jshttp/http-errors.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2014 Jonathan Ong me@jongleberry.com -Copyright (c) 2016 Douglas Christopher Wilson doug@somethingdoug.com - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - The following software may be included in this product: http-proxy-agent. A copy of the source code may be downloaded from https://github.com/TooTallNate/proxy-agents.git. This software contains the following license and notice below: License @@ -19752,41 +18295,6 @@ SOFTWARE. ----- -The following software may be included in this product: immutable. A copy of the source code may be downloaded from git://github.com/facebook/immutable-js.git. This software contains the following license and notice below: - -BSD License - -For Immutable JS software - -Copyright (c) 2014-2015, Facebook, Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name Facebook nor the names of its contributors may be used to - endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------ - The following software may be included in this product: immutable-tuple. A copy of the source code may be downloaded from git+https://github.com/benjamn/immutable-tuple.git. This software contains the following license and notice below: MIT License @@ -19813,34 +18321,6 @@ SOFTWARE. ----- -The following software may be included in this product: inflected. A copy of the source code may be downloaded from https://github.com/martinandert/inflected.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2014-2017 Martin Andert -Copyright (c) 2005-2017 David Heinemeier Hansson -Copyright (c) 2008 The Ruby I18n team - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: inherits. A copy of the source code may be downloaded from git://github.com/isaacs/inherits. This software contains the following license and notice below: The ISC License @@ -19915,32 +18395,6 @@ OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: inquirer-datepicker. A copy of the source code may be downloaded from git+https://github.com/nuintun/inquirer-datepicker.git. This software contains the following license and notice below: - -MIT License - -Copyright (c) 2017 nuintun - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: interpret. A copy of the source code may be downloaded from https://github.com/gulpjs/interpret.git. This software contains the following license and notice below: Copyright (c) 2014-2018 Tyler Kellen , Blaine Bublitz , and Eric Schoffstall @@ -19968,57 +18422,6 @@ OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: ipaddr.js. A copy of the source code may be downloaded from git://github.com/whitequark/ipaddr.js. This software contains the following license and notice below: - -Copyright (C) 2011-2017 whitequark - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - -The following software may be included in this product: is-absolute. A copy of the source code may be downloaded from https://github.com/jonschlinkert/is-absolute.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2014-2017, Jon Schlinkert. -Copyright (c) 2009-2014, TJ Holowaychuk - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - The following software may be included in this product: is-arguments, is-generator-function, is-negative-zero, is-regex. A copy of the source code may be downloaded from git://github.com/inspect-js/is-arguments.git (is-arguments), git://github.com/inspect-js/is-generator-function.git (is-generator-function), git://github.com/inspect-js/is-negative-zero.git (is-negative-zero), git://github.com/inspect-js/is-regex.git (is-regex). This software contains the following license and notice below: The MIT License (MIT) @@ -20198,7 +18601,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: is-descriptor, is-extendable, is-unc-path. A copy of the source code may be downloaded from https://github.com/jonschlinkert/is-descriptor.git (is-descriptor), https://github.com/jonschlinkert/is-extendable.git (is-extendable), https://github.com/jonschlinkert/is-unc-path.git (is-unc-path). This software contains the following license and notice below: +The following software may be included in this product: is-descriptor, is-extendable. A copy of the source code may be downloaded from https://github.com/jonschlinkert/is-descriptor.git (is-descriptor), https://github.com/jonschlinkert/is-extendable.git (is-extendable). This software contains the following license and notice below: The MIT License (MIT) @@ -20224,7 +18627,7 @@ THE SOFTWARE. ----- -The following software may be included in this product: is-glob, is-plain-object, is-relative, kind-of. A copy of the source code may be downloaded from https://github.com/micromatch/is-glob.git (is-glob), https://github.com/jonschlinkert/is-plain-object.git (is-plain-object), https://github.com/jonschlinkert/is-relative.git (is-relative), https://github.com/jonschlinkert/kind-of.git (kind-of). This software contains the following license and notice below: +The following software may be included in this product: is-glob, is-plain-object, kind-of. A copy of the source code may be downloaded from https://github.com/micromatch/is-glob.git (is-glob), https://github.com/jonschlinkert/is-plain-object.git (is-plain-object), https://github.com/jonschlinkert/kind-of.git (kind-of). This software contains the following license and notice below: The MIT License (MIT) @@ -20464,29 +18867,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----- -The following software may be included in this product: iterall. A copy of the source code may be downloaded from https://github.com/leebyron/iterall.git. This software contains the following license and notice below: - -Copyright (c) 2016 Lee Byron - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: jackspeak, path-scurry. A copy of the source code may be downloaded from git+https://github.com/isaacs/jackspeak.git (jackspeak), git+https://github.com/isaacs/path-scurry (path-scurry). This software contains the following license and notice below: # Blue Oak Model License @@ -20823,32 +19203,6 @@ SOFTWARE. ----- -The following software may be included in this product: jose. A copy of the source code may be downloaded from https://github.com/panva/jose.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2018 Filip Skokan - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: js-cookie. A copy of the source code may be downloaded from git://github.com/js-cookie/js-cookie.git. This software contains the following license and notice below: MIT License @@ -20875,32 +19229,6 @@ SOFTWARE. ----- -The following software may be included in this product: js-string-escape. A copy of the source code may be downloaded from https://github.com/joliss/js-string-escape. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2013 Jo Liss - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - The following software may be included in this product: js-tokens. A copy of the source code may be downloaded from https://github.com/lydell/js-tokens.git. This software contains the following license and notice below: The MIT License (MIT) @@ -21430,51 +19758,7 @@ limitations under the License. ----- -The following software may be included in this product: jsonwebtoken, jwt-decode. A copy of the source code may be downloaded from https://github.com/auth0/node-jsonwebtoken (jsonwebtoken), git://github.com/auth0/jwt-decode (jwt-decode). This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2015 Auth0, Inc. (http://auth0.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: jstreemap. A copy of the source code may be downloaded from git+https://github.com/kirusi/jstreemap.git. This software contains the following license and notice below: - -Copyright (c) 2017-2018 Kirusi Msafiri - -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ------ - -The following software may be included in this product: just-diff, just-diff-apply, just-extend. A copy of the source code may be downloaded from https://github.com/angus-c/just (just-diff), https://github.com/angus-c/just (just-diff-apply), https://github.com/angus-c/just (just-extend). This software contains the following license and notice below: +The following software may be included in this product: just-diff, just-diff-apply. A copy of the source code may be downloaded from https://github.com/angus-c/just (just-diff), https://github.com/angus-c/just (just-diff-apply). This software contains the following license and notice below: The MIT License (MIT) @@ -21500,28 +19784,6 @@ SOFTWARE. ----- -The following software may be included in this product: jwa, jws. A copy of the source code may be downloaded from git://github.com/brianloveswords/node-jwa.git (jwa), git://github.com/brianloveswords/node-jws.git (jws). This software contains the following license and notice below: - -Copyright (c) 2013 Brian J. Brennan - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the -Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: knex. A copy of the source code may be downloaded from git://github.com/knex/knex.git. This software contains the following license and notice below: Copyright (c) 2013-present Tim Griesser @@ -21894,7 +20156,7 @@ terms above. ----- -The following software may be included in this product: lodash.defaults, lodash.difference, lodash.flatten, lodash.get, lodash.includes, lodash.isinteger, lodash.ismatch, lodash.isplainobject, lodash.memoize, lodash.once, lodash.throttle, lodash.truncate, lodash.union, lodash.uniq. A copy of the source code may be downloaded from https://github.com/lodash/lodash.git (lodash.defaults), https://github.com/lodash/lodash.git (lodash.difference), https://github.com/lodash/lodash.git (lodash.flatten), https://github.com/lodash/lodash.git (lodash.get), https://github.com/lodash/lodash.git (lodash.includes), https://github.com/lodash/lodash.git (lodash.isinteger), https://github.com/lodash/lodash.git (lodash.ismatch), https://github.com/lodash/lodash.git (lodash.isplainobject), https://github.com/lodash/lodash.git (lodash.memoize), https://github.com/lodash/lodash.git (lodash.once), https://github.com/lodash/lodash.git (lodash.throttle), https://github.com/lodash/lodash.git (lodash.truncate), https://github.com/lodash/lodash.git (lodash.union), https://github.com/lodash/lodash.git (lodash.uniq). This software contains the following license and notice below: +The following software may be included in this product: lodash.defaults, lodash.difference, lodash.flatten, lodash.get, lodash.ismatch, lodash.isplainobject, lodash.memoize, lodash.truncate, lodash.union, lodash.uniq. A copy of the source code may be downloaded from https://github.com/lodash/lodash.git (lodash.defaults), https://github.com/lodash/lodash.git (lodash.difference), https://github.com/lodash/lodash.git (lodash.flatten), https://github.com/lodash/lodash.git (lodash.get), https://github.com/lodash/lodash.git (lodash.ismatch), https://github.com/lodash/lodash.git (lodash.isplainobject), https://github.com/lodash/lodash.git (lodash.memoize), https://github.com/lodash/lodash.git (lodash.truncate), https://github.com/lodash/lodash.git (lodash.union), https://github.com/lodash/lodash.git (lodash.uniq). This software contains the following license and notice below: Copyright jQuery Foundation and other contributors @@ -21946,33 +20208,6 @@ terms above. ----- -The following software may be included in this product: lodash.isboolean, lodash.isnumber, lodash.isstring. A copy of the source code may be downloaded from https://github.com/lodash/lodash.git (lodash.isboolean), https://github.com/lodash/lodash.git (lodash.isnumber), https://github.com/lodash/lodash.git (lodash.isstring). This software contains the following license and notice below: - -Copyright 2012-2016 The Dojo Foundation -Based on Underscore.js, copyright 2009-2016 Jeremy Ashkenas, -DocumentCloud and Investigative Reporters & Editors - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: lodash.isequal. A copy of the source code may be downloaded from https://github.com/lodash/lodash.git. This software contains the following license and notice below: Copyright JS Foundation and other contributors @@ -22043,30 +20278,6 @@ Copyright 2015 Gareth Jones (with contributions from many other people) ----- -The following software may be included in this product: logdown. A copy of the source code may be downloaded from https://github.com/caiogondim/logdown. This software contains the following license and notice below: - -Copyright (c) 2017 [Caio Gondim](https://caiogondim.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: logform. A copy of the source code may be downloaded from git+https://github.com/winstonjs/logform.git. This software contains the following license and notice below: MIT License @@ -22458,61 +20669,6 @@ IN THE SOFTWARE. ----- -The following software may be included in this product: media-typer. A copy of the source code may be downloaded from https://github.com/jshttp/media-typer.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2014 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - -The following software may be included in this product: merge-descriptors. A copy of the source code may be downloaded from https://github.com/component/merge-descriptors.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2013 Jonathan Ong -Copyright (c) 2015 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: merge-stream. A copy of the source code may be downloaded from https://github.com/grncdr/merge-stream.git. This software contains the following license and notice below: The MIT License (MIT) @@ -22565,12 +20721,12 @@ SOFTWARE. ----- -The following software may be included in this product: methods. A copy of the source code may be downloaded from https://github.com/jshttp/methods.git. This software contains the following license and notice below: +The following software may be included in this product: mime-db. A copy of the source code may be downloaded from https://github.com/jshttp/mime-db.git. This software contains the following license and notice below: (The MIT License) -Copyright (c) 2013-2014 TJ Holowaychuk -Copyright (c) 2015-2016 Douglas Christopher Wilson +Copyright (c) 2014 Jonathan Ong +Copyright (c) 2015-2022 Douglas Christopher Wilson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -22593,38 +20749,12 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: mime. A copy of the source code may be downloaded from https://github.com/broofa/node-mime. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2010 Benjamin Thomas, Robert Kieffer - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - -The following software may be included in this product: mime-db. A copy of the source code may be downloaded from https://github.com/jshttp/mime-db.git. This software contains the following license and notice below: +The following software may be included in this product: mime-types. A copy of the source code may be downloaded from https://github.com/jshttp/mime-types.git. This software contains the following license and notice below: (The MIT License) Copyright (c) 2014 Jonathan Ong -Copyright (c) 2015-2022 Douglas Christopher Wilson +Copyright (c) 2015 Douglas Christopher Wilson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -22673,24 +20803,6 @@ THE SOFTWARE. ----- -The following software may be included in this product: minimalistic-assert. A copy of the source code may be downloaded from https://github.com/calvinmetcalf/minimalistic-assert.git. This software contains the following license and notice below: - -Copyright 2015 Calvin Metcalf - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. - ------ - The following software may be included in this product: minimatch, rimraf. A copy of the source code may be downloaded from git://github.com/isaacs/minimatch.git (minimatch), git://github.com/isaacs/rimraf.git (rimraf). This software contains the following license and notice below: The ISC License @@ -23058,31 +21170,6 @@ OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: moment-jdateformatparser. A copy of the source code may be downloaded from https://github.com/MadMG/moment-jdateformatparser. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2013 MadMG - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: moment-timezone. A copy of the source code may be downloaded from https://github.com/moment/moment-timezone.git. This software contains the following license and notice below: The MIT License (MIT) @@ -23403,38 +21490,6 @@ THE SOFTWARE. ----- -The following software may be included in this product: nise, sinon. A copy of the source code may be downloaded from http://github.com/sinonjs/nise.git (nise), http://github.com/sinonjs/sinon.git (sinon). This software contains the following license and notice below: - -(The BSD License) - -Copyright (c) 2010-2017, Christian Johansen, christian@cjohansen.no -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of Christian Johansen nor the names of his contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------ - The following software may be included in this product: node-abi. A copy of the source code may be downloaded from https://github.com/electron/node-abi.git. This software contains the following license and notice below: MIT License @@ -23841,19 +21896,6 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----- -The following software may be included in this product: nullthrows. A copy of the source code may be downloaded from https://github.com/zertosh/nullthrows. This software contains the following license and notice below: - -The MIT License (MIT) -Copyright (c) 2016 Andres Suarez - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: nwsapi. A copy of the source code may be downloaded from git://github.com/dperini/nwsapi.git. This software contains the following license and notice below: Copyright (c) 2007-2019 Diego Perini (http://www.iport.it/) @@ -23881,7 +21923,7 @@ OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: object-copy, path-root, path-root-regex, static-extend. A copy of the source code may be downloaded from https://github.com/jonschlinkert/object-copy.git (object-copy), https://github.com/jonschlinkert/path-root.git (path-root), https://github.com/regexhq/path-root-regex.git (path-root-regex), https://github.com/jonschlinkert/static-extend.git (static-extend). This software contains the following license and notice below: +The following software may be included in this product: object-copy, static-extend. A copy of the source code may be downloaded from https://github.com/jonschlinkert/object-copy.git (object-copy), https://github.com/jonschlinkert/static-extend.git (static-extend). This software contains the following license and notice below: The MIT License (MIT) @@ -23985,31 +22027,6 @@ THE SOFTWARE. ----- -The following software may be included in this product: object-to-xml. A copy of the source code may be downloaded from git://github.com/wankdanker/node-object-to-xml.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2013 Dan VerWeire - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: object.assign. A copy of the source code may be downloaded from git://github.com/ljharb/object.assign.git. This software contains the following license and notice below: The MIT License (MIT) @@ -24088,34 +22105,6 @@ THE SOFTWARE. ----- -The following software may be included in this product: on-finished. A copy of the source code may be downloaded from https://github.com/jshttp/on-finished.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2013 Jonathan Ong -Copyright (c) 2014 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: one-time, querystringify, requires-port, url-parse. A copy of the source code may be downloaded from https://github.com/3rd-Eden/one-time.git (one-time), https://github.com/unshiftio/querystringify (querystringify), https://github.com/unshiftio/requires-port (requires-port), https://github.com/unshiftio/url-parse.git (url-parse). This software contains the following license and notice below: The MIT License (MIT) @@ -24218,32 +22207,6 @@ The following software may be included in this product: pako. A copy of the sour (The MIT License) -Copyright (C) 2014-2016 by Vitaly Puzrin - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - -The following software may be included in this product: pako. A copy of the source code may be downloaded from https://github.com/nodeca/pako.git. This software contains the following license and notice below: - -(The MIT License) - Copyright (C) 2014-2017 by Vitaly Puzrin and Andrei Tuputcyn Permission is hereby granted, free of charge, to any person obtaining a copy @@ -24290,34 +22253,6 @@ THE SOFTWARE. ----- -The following software may be included in this product: parseurl. A copy of the source code may be downloaded from https://github.com/pillarjs/parseurl.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2014 Jonathan Ong -Copyright (c) 2014-2017 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: path-parse. A copy of the source code may be downloaded from https://github.com/jbgutierrez/path-parse.git. This software contains the following license and notice below: The MIT License (MIT) @@ -30886,18 +28821,6 @@ By: Ika ----- -The following software may be included in this product: prettier. A copy of the source code may be downloaded from https://github.com/prettier/prettier.git. This software contains the following license and notice below: - -Copyright © James Long and contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: proc-log. A copy of the source code may be downloaded from https://github.com/npm/proc-log.git. This software contains the following license and notice below: The ISC License @@ -30969,30 +28892,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: promise. A copy of the source code may be downloaded from https://github.com/then/promise.git. This software contains the following license and notice below: - -Copyright (c) 2014 Forbes Lindesay - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - The following software may be included in this product: promise-inflight. A copy of the source code may be downloaded from git+https://github.com/iarna/promise-inflight.git. This software contains the following license and notice below: Copyright (c) 2017, Rebecca Turner @@ -31035,11 +28934,11 @@ THE SOFTWARE. ----- -The following software may be included in this product: promise-sequential. A copy of the source code may be downloaded from git+https://github.com/russiann/promise-sequential.git. This software contains the following license and notice below: +The following software may be included in this product: prompts, prompts-ncu, sisteransi. A copy of the source code may be downloaded from https://github.com/terkelg/prompts.git (prompts), https://github.com/raineorshine/prompts/tree/ncu (prompts-ncu), https://github.com/terkelg/sisteransi (sisteransi). This software contains the following license and notice below: MIT License -Copyright (c) 2016 Russian Rebouças +Copyright (c) 2018 Terkel Gjervig Nielsen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -31061,11 +28960,11 @@ SOFTWARE. ----- -The following software may be included in this product: prompts, prompts-ncu, sisteransi. A copy of the source code may be downloaded from https://github.com/terkelg/prompts.git (prompts), https://github.com/raineorshine/prompts/tree/ncu (prompts-ncu), https://github.com/terkelg/sisteransi (sisteransi). This software contains the following license and notice below: +The following software may be included in this product: prop-types. A copy of the source code may be downloaded from https://github.com/facebook/prop-types.git. This software contains the following license and notice below: MIT License -Copyright (c) 2018 Terkel Gjervig Nielsen +Copyright (c) 2013-present, Facebook, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -31232,61 +29131,6 @@ SOFTWARE. ----- -The following software may be included in this product: range-parser. A copy of the source code may be downloaded from https://github.com/jshttp/range-parser.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2012-2014 TJ Holowaychuk -Copyright (c) 2015-2016 Douglas Christopher Wilson -Copyright (c) 2014-2022 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - The following software may be included in this product: rc-config-loader. A copy of the source code may be downloaded from https://github.com/azu/rc-config-loader.git. This software contains the following license and notice below: Copyright (c) 2017 azu @@ -32602,34 +30446,6 @@ Apache-2.0 License Summary ----- -The following software may be included in this product: send. A copy of the source code may be downloaded from https://github.com/pillarjs/send.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2012 TJ Holowaychuk -Copyright (c) 2014-2022 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: seq-queue. A copy of the source code may be downloaded from git@github.com:changchang/seq-queue.git. This software contains the following license and notice below: (The MIT License) @@ -32689,36 +30505,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----- -The following software may be included in this product: serve-static. A copy of the source code may be downloaded from https://github.com/expressjs/serve-static.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2010 Sencha Inc. -Copyright (c) 2011 LearnBoost -Copyright (c) 2011 TJ Holowaychuk -Copyright (c) 2014-2016 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: set-function-name. A copy of the source code may be downloaded from git+https://github.com/ljharb/set-function-name.git. This software contains the following license and notice below: MIT License @@ -32770,24 +30556,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: setprototypeof. A copy of the source code may be downloaded from https://github.com/wesleytodd/setprototypeof.git. This software contains the following license and notice below: - -Copyright (c) 2015, Wes Todd - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY -SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION -OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ------ - The following software may be included in this product: shallow-clone, to-regex-range, use. A copy of the source code may be downloaded from https://github.com/jonschlinkert/shallow-clone.git (shallow-clone), https://github.com/micromatch/to-regex-range.git (to-regex-range), https://github.com/jonschlinkert/use.git (use). This software contains the following license and notice below: The MIT License (MIT) @@ -32937,42 +30705,6 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ----- -The following software may be included in this product: signedsource. This software contains the following license and notice below: - -BSD License - -For signedsource software - -Copyright (c) 2013-present, Facebook, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name Facebook nor the names of its contributors may be used to - endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------ - The following software may be included in this product: simple-plist. A copy of the source code may be downloaded from https://github.com/wollardj/simple-plist.git. This software contains the following license and notice below: The MIT License (MIT) @@ -33436,33 +31168,6 @@ THE SOFTWARE. ----- -The following software may be included in this product: statuses. A copy of the source code may be downloaded from https://github.com/jshttp/statuses.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2014 Jonathan Ong -Copyright (c) 2016 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - The following software may be included in this product: stream-browserify. A copy of the source code may be downloaded from git://github.com/browserify/stream-browserify.git. This software contains the following license and notice below: MIT License @@ -34098,59 +31803,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI ----- -The following software may be included in this product: to-fast-properties. A copy of the source code may be downloaded from https://github.com/sindresorhus/to-fast-properties.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2014 Petka Antonov - 2015 Sindre Sorhus - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - -The following software may be included in this product: toidentifier. A copy of the source code may be downloaded from https://github.com/component/toidentifier.git. This software contains the following license and notice below: - -MIT License - -Copyright (c) 2016 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: tough-cookie. A copy of the source code may be downloaded from git://github.com/salesforce/tough-cookie.git. This software contains the following license and notice below: Copyright (c) 2015, Salesforce.com, Inc. @@ -34194,14 +31846,11 @@ SOFTWARE. ----- -The following software may be included in this product: traverse. A copy of the source code may be downloaded from git://github.com/ljharb/js-traverse.git. This software contains the following license and notice below: - -Copyright 2010 James Halliday (mail@substack.net) +The following software may be included in this product: triple-beam. A copy of the source code may be downloaded from git+https://github.com/winstonjs/triple-beam.git. This software contains the following license and notice below: -This project is free software released under the MIT/X11 license: -http://www.opensource.org/licenses/mit-license.php +MIT License -Copyright 2010 James Halliday (mail@substack.net) +Copyright (c) 2017 winstonjs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -34210,24 +31859,24 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. ----- -The following software may be included in this product: triple-beam. A copy of the source code may be downloaded from git+https://github.com/winstonjs/triple-beam.git. This software contains the following license and notice below: +The following software may be included in this product: ts-dedent. A copy of the source code may be downloaded from https://github.com/tamino-martinius/node-ts-dedent.git. This software contains the following license and notice below: MIT License -Copyright (c) 2017 winstonjs +Copyright (c) 2018 Tamino Martinius Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -34249,11 +31898,11 @@ SOFTWARE. ----- -The following software may be included in this product: ts-dedent. A copy of the source code may be downloaded from https://github.com/tamino-martinius/node-ts-dedent.git. This software contains the following license and notice below: +The following software may be included in this product: ts-invariant. A copy of the source code may be downloaded from git+https://github.com/apollographql/invariant-packages.git. This software contains the following license and notice below: MIT License -Copyright (c) 2018 Tamino Martinius +Copyright (c) 2019 Apollo GraphQL Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -34275,11 +31924,11 @@ SOFTWARE. ----- -The following software may be included in this product: ts-invariant. A copy of the source code may be downloaded from git+https://github.com/apollographql/invariant-packages.git. This software contains the following license and notice below: +The following software may be included in this product: ts-jest. A copy of the source code may be downloaded from git+https://github.com/kulshekhar/ts-jest.git. This software contains the following license and notice below: MIT License -Copyright (c) 2019 Apollo GraphQL +Copyright (c) 2016-2018 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -34301,11 +31950,11 @@ SOFTWARE. ----- -The following software may be included in this product: ts-jest. A copy of the source code may be downloaded from git+https://github.com/kulshekhar/ts-jest.git. This software contains the following license and notice below: +The following software may be included in this product: ts-node. A copy of the source code may be downloaded from git://github.com/TypeStrong/ts-node.git. This software contains the following license and notice below: -MIT License +The MIT License (MIT) -Copyright (c) 2016-2018 +Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -34314,16 +31963,16 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. ----- @@ -34551,32 +32200,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ----- -The following software may be included in this product: ua-parser-js. A copy of the source code may be downloaded from https://github.com/faisalman/ua-parser-js.git. This software contains the following license and notice below: - -MIT License - -Copyright (c) 2012-2023 Faisal Salman <> - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: uglify-js. A copy of the source code may be downloaded from https://github.com/mishoo/UglifyJS.git. This software contains the following license and notice below: UglifyJS is released under the BSD license: @@ -34756,33 +32379,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: unpipe. A copy of the source code may be downloaded from https://github.com/stream-utils/unpipe.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2015 Douglas Christopher Wilson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: upath. A copy of the source code may be downloaded from git://github.com/anodynos/upath. This software contains the following license and notice below: Copyright(c) 2014-2020 Angelos Pikoulas (agelos.pikoulas@gmail.com) @@ -34917,30 +32513,6 @@ SOFTWARE. ----- -The following software may be included in this product: urlpattern-polyfill. A copy of the source code may be downloaded from https://github.com/kenchris/urlpattern-polyfill. This software contains the following license and notice below: - -Copyright 2020 Intel Corporation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - The following software may be included in this product: util-deprecate. A copy of the source code may be downloaded from git://github.com/TooTallNate/util-deprecate.git. This software contains the following license and notice below: (The MIT License) @@ -34970,31 +32542,6 @@ OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: utils-merge. A copy of the source code may be downloaded from git://github.com/jaredhanson/utils-merge.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2013-2017 Jared Hanson - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: uuid. A copy of the source code may be downloaded from https://github.com/uuidjs/uuid.git. This software contains the following license and notice below: The MIT License (MIT) @@ -35142,32 +32689,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: value-or-promise. A copy of the source code may be downloaded from https://github.com/yaacovCR/value-or-promise. This software contains the following license and notice below: - -MIT License - -Copyright (c) 2019 Yaacov Rydzinski - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: w3c-hr-time. A copy of the source code may be downloaded from https://github.com/jsdom/w3c-hr-time. This software contains the following license and notice below: # The MIT License (MIT) @@ -35224,32 +32745,6 @@ OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: wait-port. A copy of the source code may be downloaded from git+https://github.com/dwmkerr/wait-port.git. This software contains the following license and notice below: - -MIT License - -Copyright (c) 2017 Dave Kerr - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: walker. A copy of the source code may be downloaded from https://github.com/daaku/nodejs-walker. This software contains the following license and notice below: Copyright 2013 Naitik Shah @@ -35753,211 +33248,6 @@ Apache License ----- - -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright 2017 - 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - ------ - The following software may be included in this product: write-file-atomic. A copy of the source code may be downloaded from git@github.com:iarna/write-file-atomic.git. This software contains the following license and notice below: Copyright (c) 2015, Rebecca Turner @@ -35994,31 +33284,6 @@ SOFTWARE. ----- -The following software may be included in this product: ws. A copy of the source code may be downloaded from git+https://github.com/websockets/ws.git. This software contains the following license and notice below: - -Copyright (c) 2011 Einar Otto Stangvik -Copyright (c) 2013 Arnout Kazemier and contributors -Copyright (c) 2016 Luigi Pinca and contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: xml. A copy of the source code may be downloaded from http://github.com/dylang/node-xml. This software contains the following license and notice below: (The MIT License) @@ -36046,32 +33311,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: xml-js. A copy of the source code may be downloaded from git+https://github.com/nashwaan/xml-js.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2016-2017 Yousuf Almarzooqi - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: xml-name-validator. A copy of the source code may be downloaded from https://github.com/jsdom/xml-name-validator.git. This software contains the following license and notice below: Apache License @@ -36326,32 +33565,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: xstate. A copy of the source code may be downloaded from git+https://github.com/statelyai/xstate.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2015 David Khourshid - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: xtend. A copy of the source code may be downloaded from git://github.com/Raynos/xtend.git. This software contains the following license and notice below: The MIT License (MIT) diff --git a/packages/amplify-e2e-tests/src/__tests__/migration/api.connection.migration.test.ts b/packages/amplify-e2e-tests/src/__tests__/migration/api.connection.migration.test.ts deleted file mode 100644 index fcac81b373..0000000000 --- a/packages/amplify-e2e-tests/src/__tests__/migration/api.connection.migration.test.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { - initJSProjectWithProfile, - deleteProject, - amplifyPush, - amplifyPushUpdate, - addFeatureFlag, - addApiWithoutSchema, - updateApiSchema, - createNewProjectDir, - deleteProjectDir, -} from 'amplify-category-api-e2e-core'; - -describe('amplify add api', () => { - let projRoot: string; - beforeEach(async () => { - projRoot = await createNewProjectDir('api-conn-migration'); - }); - - afterEach(async () => { - await deleteProject(projRoot); - deleteProjectDir(projRoot); - }); - - it('init project, run invalid migration trying to add a sort key to @connection, and check for error', async () => { - const projectName = 'addconnection'; - const initialSchema = 'migrations_connection/initial_schema.graphql'; - const nextSchema1 = 'migrations_connection/cant_add_a_sort_key.graphql'; - - await initJSProjectWithProfile(projRoot, { name: projectName }); - await addFeatureFlag(projRoot, 'graphqltransformer', 'enableiterativegsiupdates', false); - - await addApiWithoutSchema(projRoot, { transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, initialSchema); - await amplifyPush(projRoot); - updateApiSchema(projRoot, projectName, nextSchema1); - await expect( - amplifyPushUpdate( - projRoot, - /Attempting to edit the global secondary index gsi-PostComments on the CommentTable table in the Comment stack.*/, - ), - ).rejects.toThrowError('Process exited with non zero exit code 1'); - }); - - it('init project, run invalid migration trying to change add and remove connection at same time, and check for error', async () => { - const projectName = 'iremoveaddconnection'; - const initialSchema = 'migrations_connection/initial_schema.graphql'; - const nextSchema1 = 'migrations_connection/cant_add_and_remove_at_same_time.graphql'; - - await initJSProjectWithProfile(projRoot, { name: projectName }); - addFeatureFlag(projRoot, 'graphqltransformer', 'enableiterativegsiupdates', false); - - await addApiWithoutSchema(projRoot, { transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, initialSchema); - await amplifyPush(projRoot); - updateApiSchema(projRoot, projectName, nextSchema1); - await expect( - amplifyPushUpdate( - projRoot, - /Attempting to add and remove a global secondary index at the same time on the CommentTable table in the Comment stack.*/, - ), - ).rejects.toThrowError('Process exited with non zero exit code 1'); - }); -}); diff --git a/packages/amplify-e2e-tests/src/__tests__/migration/api.connection.migration2.test.ts b/packages/amplify-e2e-tests/src/__tests__/migration/api.connection.migration2.test.ts deleted file mode 100644 index a2c73ce447..0000000000 --- a/packages/amplify-e2e-tests/src/__tests__/migration/api.connection.migration2.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { - initJSProjectWithProfile, - deleteProject, - amplifyPush, - amplifyPushUpdate, - addFeatureFlag, - addApiWithoutSchema, - updateApiSchema, - createNewProjectDir, - deleteProjectDir, -} from 'amplify-category-api-e2e-core'; - -describe('amplify add api', () => { - let projRoot: string; - beforeEach(async () => { - projRoot = await createNewProjectDir('api-conn-migration'); - }); - - afterEach(async () => { - await deleteProject(projRoot); - deleteProjectDir(projRoot); - }); - - it('init project, run invalid migration trying to change a @connection field name, and check for error', async () => { - const projectName = 'changeconnection'; - const initialSchema = 'migrations_connection/initial_schema.graphql'; - const nextSchema1 = 'migrations_connection/cant_change_connection_field_name.graphql'; - - await initJSProjectWithProfile(projRoot, { name: projectName }); - await addFeatureFlag(projRoot, 'graphqltransformer', 'enableiterativegsiupdates', false); - - await addApiWithoutSchema(projRoot, { transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, initialSchema); - await amplifyPush(projRoot); - updateApiSchema(projRoot, projectName, nextSchema1); - await expect( - amplifyPushUpdate( - projRoot, - /Attempting to edit the global secondary index gsi-PostComments on the CommentTable table in the Comment stack.*/, - ), - ).rejects.toThrowError('Process exited with non zero exit code 1'); - }); - - it('init project, run valid migration to remove a connection, then run another migration that adds a slightly different GSI.', async () => { - const projectName = 'removeaddconnection'; - const initialSchema = 'migrations_connection/initial_schema.graphql'; - const nextSchema1 = 'migrations_connection/remove_connection.graphql'; - const nextSchema2 = 'migrations_connection/add_a_sort_key.graphql'; - - await initJSProjectWithProfile(projRoot, { name: projectName }); - await addFeatureFlag(projRoot, 'graphqltransformer', 'enableiterativegsiupdates', false); - - await addApiWithoutSchema(projRoot, { transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, initialSchema); - await amplifyPush(projRoot); - updateApiSchema(projRoot, projectName, nextSchema1); - await amplifyPushUpdate(projRoot, /GraphQL endpoint:.*/); - updateApiSchema(projRoot, projectName, nextSchema2); - await amplifyPushUpdate(projRoot, /GraphQL endpoint:.*/); - }); -}); diff --git a/packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration1.test.ts b/packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration1.test.ts deleted file mode 100644 index 99e09ba369..0000000000 --- a/packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration1.test.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { - initJSProjectWithProfile, - deleteProject, - amplifyPush, - amplifyPushUpdate, - addFeatureFlag, - addApiWithoutSchema, - updateApiSchema, - createNewProjectDir, - deleteProjectDir, -} from 'amplify-category-api-e2e-core'; - -describe('amplify add api', () => { - let projRoot: string; - beforeEach(async () => { - projRoot = await createNewProjectDir('api-key-migration'); - }); - - afterEach(async () => { - await deleteProject(projRoot); - deleteProjectDir(projRoot); - }); - - it('init project, run invalid migration trying to add an LSI, and wait for error', async () => { - const projectName = 'migratingkey'; - const initialSchema = 'migrations_key/initial_schema.graphql'; - const nextSchema1 = 'migrations_key/cant_add_lsi.graphql'; - - await initJSProjectWithProfile(projRoot, { name: projectName }); - addFeatureFlag(projRoot, 'graphqltransformer', 'enableiterativegsiupdates', false); - // testing this with old behavior with named lsi key - addFeatureFlag(projRoot, 'graphqltransformer', 'secondarykeyasgsi', false); - - await addApiWithoutSchema(projRoot, { apiKeyExpirationDays: 2, transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, initialSchema); - await amplifyPush(projRoot); - - updateApiSchema(projRoot, projectName, nextSchema1); - await expect( - amplifyPushUpdate( - projRoot, - /Attempting to add a local secondary index to the TodoTable table in the Todo stack. Local secondary indexes must be created when the table is created.*/, - ), - ).rejects.toThrowError('Process exited with non zero exit code 1'); - }); - - it('init project, run invalid migration trying to change a gsi, and check for error', async () => { - const projectName = 'migratingkey'; - const initialSchema = 'migrations_key/initial_schema.graphql'; - const nextSchema1 = 'migrations_key/cant_change_gsi.graphql'; - - await initJSProjectWithProfile(projRoot, { name: projectName }); - addFeatureFlag(projRoot, 'graphqltransformer', 'enableiterativegsiupdates', false); - - await addApiWithoutSchema(projRoot, { transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, initialSchema); - await amplifyPush(projRoot); - - updateApiSchema(projRoot, projectName, nextSchema1); - await expect( - amplifyPushUpdate(projRoot, /Attempting to edit the global secondary index SomeGSI on the TodoTable table in the Todo stack.*/), - ).rejects.toThrowError('Process exited with non zero exit code 1'); - }); - - it('init project, run invalid migration trying to change the key schema, and check for error', async () => { - const projectName = 'migratingkey'; - const initialSchema = 'migrations_key/initial_schema.graphql'; - const nextSchema1 = 'migrations_key/cant_change_key_schema.graphql'; - - await initJSProjectWithProfile(projRoot, { name: projectName }); - addFeatureFlag(projRoot, 'graphqltransformer', 'enableiterativegsiupdates', false); - - await addApiWithoutSchema(projRoot, { transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, initialSchema); - await amplifyPush(projRoot); - - updateApiSchema(projRoot, projectName, nextSchema1); - await expect( - amplifyPushUpdate(projRoot, /Attempting to edit the key schema of the TodoTable table in the Todo stack.*/), - ).rejects.toThrowError('Process exited with non zero exit code 1'); - }); - - it('init project, run invalid migration trying to change an lsi, and check for error', async () => { - const projectName = 'migrationchangelsi'; - const initialSchema = 'migrations_key/initial_schema.graphql'; - const nextSchema1 = 'migrations_key/cant_change_lsi.graphql'; - - await initJSProjectWithProfile(projRoot, { name: projectName }); - addFeatureFlag(projRoot, 'graphqltransformer', 'enableiterativegsiupdates', false); - - await addApiWithoutSchema(projRoot, { transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, initialSchema); - await amplifyPush(projRoot); - - updateApiSchema(projRoot, projectName, nextSchema1); - await expect( - amplifyPushUpdate(projRoot, /Attempting to edit the local secondary index SomeLSI on the TodoTable table in the Todo stack.*/), - ).rejects.toThrowError('Process exited with non zero exit code 1'); - }); -}); diff --git a/packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration2.test.ts b/packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration2.test.ts deleted file mode 100644 index 465f5c0974..0000000000 --- a/packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration2.test.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { - initJSProjectWithProfile, - deleteProject, - amplifyPush, - amplifyPushUpdate, - addFeatureFlag, - addApiWithoutSchema, - updateApiSchema, - getProjectMeta, - createNewProjectDir, - deleteProjectDir, -} from 'amplify-category-api-e2e-core'; -import { addEnvironment } from '../../environment/env'; - -describe('amplify add api', () => { - let projRoot: string; - beforeEach(async () => { - projRoot = await createNewProjectDir('api-key-migration-2'); - }); - - afterEach(async () => { - await deleteProject(projRoot); - deleteProjectDir(projRoot); - }); - - it('init project, allow adding key when keyschema of one key is used in another key', async () => { - const projectName = 'validksgsiupdate'; - const initial_schema = 'migrations_key/three_gsi_model_schema.graphql'; - const nextSchema = 'migrations_key/four_gsi_model_schema.graphql'; - await initJSProjectWithProfile(projRoot, { name: projectName }); - await addApiWithoutSchema(projRoot, { transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, initial_schema); - await amplifyPush(projRoot); - - updateApiSchema(projRoot, projectName, nextSchema); - await amplifyPushUpdate(projRoot, /GraphQL endpoint:.*/); - }); - - it('init project, allow editing keyschema when adding environment', async () => { - const projectName = 'migratingkey'; - const initialSchema = 'migrations_key/initial_schema.graphql'; - const nextSchema1 = 'migrations_key/cant_change_key_schema.graphql'; - - await initJSProjectWithProfile(projRoot, { name: projectName }); - await addApiWithoutSchema(projRoot, { transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, initialSchema); - await amplifyPush(projRoot); - await addEnvironment(projRoot, { envName: 'test' }); - updateApiSchema(projRoot, projectName, nextSchema1); - await amplifyPush(projRoot); - const { output } = getProjectMeta(projRoot).api[projectName]; - const { GraphQLAPIIdOutput, GraphQLAPIEndpointOutput, GraphQLAPIKeyOutput } = output; - - expect(GraphQLAPIIdOutput).toBeDefined(); - expect(GraphQLAPIEndpointOutput).toBeDefined(); - expect(GraphQLAPIKeyOutput).toBeDefined(); - }); -}); diff --git a/packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration3.test.ts b/packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration3.test.ts deleted file mode 100644 index c5d3f1eea7..0000000000 --- a/packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration3.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { - initJSProjectWithProfile, - deleteProject, - amplifyPush, - amplifyPushUpdate, - addFeatureFlag, - addApiWithoutSchema, - updateApiSchema, - getProjectMeta, - createNewProjectDir, - deleteProjectDir, -} from 'amplify-category-api-e2e-core'; -import { addEnvironment } from '../../environment/env'; - -describe('amplify add api', () => { - let projRoot: string; - beforeEach(async () => { - projRoot = await createNewProjectDir('api-key-migration-3'); - }); - - afterEach(async () => { - await deleteProject(projRoot); - deleteProjectDir(projRoot); - }); - - it('init project, run invalid migration trying to delete more than one gsi, and check for error', async () => { - const projectName = 'migratingkey1'; - const initialSchema = 'migrations_key/initial_schema1.graphql'; - const nextSchema1 = 'migrations_key/cant_remove_more_gsi.graphql'; - - await initJSProjectWithProfile(projRoot, { name: projectName }); - addFeatureFlag(projRoot, 'graphqltransformer', 'enableiterativegsiupdates', false); - - await addApiWithoutSchema(projRoot, { transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, initialSchema); - await amplifyPush(projRoot); - - updateApiSchema(projRoot, projectName, nextSchema1); - await expect( - amplifyPushUpdate( - projRoot, - /Attempting to delete more than 1 global secondary index SomeGSI1 and someGSI2 on the TodoTable table in the Todo stack.*/, - ), - ).rejects.toThrowError('Process exited with non zero exit code 1'); - }); - - it('init project, run invalid migration trying to add and delete gsi, and check for error', async () => { - const projectName = 'migratingkey2'; - const initialSchema = 'migrations_key/initial_schema.graphql'; - const nextSchema1 = 'migrations_key/cant_update_delete_gsi.graphql'; - - await initJSProjectWithProfile(projRoot, { name: projectName }); - addFeatureFlag(projRoot, 'graphqltransformer', 'enableiterativegsiupdates', false); - - await addApiWithoutSchema(projRoot, { transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, initialSchema); - await amplifyPush(projRoot); - updateApiSchema(projRoot, projectName, nextSchema1); - await expect( - amplifyPushUpdate( - projRoot, - /Attempting to add and delete a global secondary index SomeGSI1 and someGSI2 on the TodoTable table in the Todo stack.*/, - ), - ).rejects.toThrowError('Process exited with non zero exit code 1'); - }); -}); diff --git a/packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration4.test.ts b/packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration4.test.ts deleted file mode 100644 index 7a09df6c04..0000000000 --- a/packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration4.test.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { - initJSProjectWithProfile, - deleteProject, - amplifyPush, - amplifyPushUpdate, - addFeatureFlag, - addApiWithoutSchema, - updateApiSchema, - getProjectMeta, - createNewProjectDir, - deleteProjectDir, -} from 'amplify-category-api-e2e-core'; -import { addEnvironment } from '../../environment/env'; - -describe('amplify add api', () => { - let projRoot: string; - beforeEach(async () => { - projRoot = await createNewProjectDir('api-key-migration-4'); - }); - - afterEach(async () => { - await deleteProject(projRoot); - deleteProjectDir(projRoot); - }); - - it('init project, allow updated two types with new GSIs', async () => { - const projectName = 'twotableupdategsi'; - const initialSchema = 'migrations_key/two_key_model_schema.graphql'; - const nextSchema = 'migrations_key/four_key_model_schema.graphql'; - - await initJSProjectWithProfile(projRoot, { name: projectName }); - addFeatureFlag(projRoot, 'graphqltransformer', 'enableiterativegsiupdates', false); - - await addApiWithoutSchema(projRoot, { transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, initialSchema); - await amplifyPush(projRoot); - - updateApiSchema(projRoot, projectName, nextSchema); - await amplifyPushUpdate(projRoot, /GraphQL endpoint:.*/); - }); - - it('init project, run valid migration adding a GSI', async () => { - const projectName = 'validaddinggsi'; - const initialSchema = 'migrations_key/initial_schema.graphql'; - const nextSchema1 = 'migrations_key/add_gsi.graphql'; - - await initJSProjectWithProfile(projRoot, { name: projectName }); - addFeatureFlag(projRoot, 'graphqltransformer', 'enableiterativegsiupdates', false); - - await addApiWithoutSchema(projRoot, { transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, initialSchema); - await amplifyPush(projRoot); - - updateApiSchema(projRoot, projectName, nextSchema1); - await amplifyPushUpdate(projRoot, /GraphQL endpoint:.*/); - }); -}); diff --git a/packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration5.test.ts b/packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration5.test.ts deleted file mode 100644 index 0cbf9dcc3c..0000000000 --- a/packages/amplify-e2e-tests/src/__tests__/migration/api.key.migration5.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { - initJSProjectWithProfile, - deleteProject, - amplifyPush, - amplifyPushUpdate, - addFeatureFlag, - addApiWithoutSchema, - updateApiSchema, - getProjectMeta, - createNewProjectDir, - deleteProjectDir, -} from 'amplify-category-api-e2e-core'; -import { addEnvironment } from '../../environment/env'; - -describe('amplify add api', () => { - let projRoot: string; - beforeEach(async () => { - projRoot = await createNewProjectDir('api-key-migration-5'); - }); - - afterEach(async () => { - await deleteProject(projRoot); - deleteProjectDir(projRoot); - }); - - it('init project, run invalid migration trying to add more than one gsi, and check for error', async () => { - const projectName = 'migratingkey3'; - const initialSchema = 'migrations_key/initial_schema.graphql'; - const nextSchema1 = 'migrations_key/cant_add_more_gsi.graphql'; - - await initJSProjectWithProfile(projRoot, { name: projectName }); - addFeatureFlag(projRoot, 'graphqltransformer', 'enableiterativegsiupdates', false); - - await addApiWithoutSchema(projRoot, { transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, initialSchema); - await amplifyPush(projRoot); - - updateApiSchema(projRoot, projectName, nextSchema1); - await expect( - amplifyPushUpdate( - projRoot, - /Attempting to add more than 1 global secondary index SomeGSI1 and someGSI2 on the TodoTable table in the Todo stack.*/, - ), - ).rejects.toThrowError('Process exited with non zero exit code 1'); - }); - - it('init project, run invalid migration when adding more than one gsi on the same table', async () => { - const projectName = 'invalidgsiupdate'; - - const initialSchema = 'migrations_key/simple_key.graphql'; - const nextSchema = 'migrations_key/cant_add_multiple_gsi.graphql'; - - await initJSProjectWithProfile(projRoot, { name: projectName }); - addFeatureFlag(projRoot, 'graphqltransformer', 'enableiterativegsiupdates', false); - - await addApiWithoutSchema(projRoot, { transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, initialSchema); - await amplifyPush(projRoot); - - updateApiSchema(projRoot, projectName, nextSchema); - await expect( - amplifyPushUpdate( - projRoot, - /Attempting to mutate more than 1 global secondary index at the same time on the TodoTable table in the Todo stack.*/, - ), - ).rejects.toThrowError('Process exited with non zero exit code 1'); - }); -}); diff --git a/packages/amplify-e2e-tests/src/__tests__/schema-connection.test.ts b/packages/amplify-e2e-tests/src/__tests__/schema-connection.test.ts deleted file mode 100644 index 0448f7a57d..0000000000 --- a/packages/amplify-e2e-tests/src/__tests__/schema-connection.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { initJSProjectWithProfile, deleteProject, createNewProjectDir, deleteProjectDir } from 'amplify-category-api-e2e-core'; -import { testSchema } from '../schema-api-directives'; - -describe('api directives @connection', () => { - let projectDir: string; - - beforeEach(async () => { - projectDir = await createNewProjectDir('connection'); - await initJSProjectWithProfile(projectDir, {}); - }); - - afterEach(async () => { - await deleteProject(projectDir); - deleteProjectDir(projectDir); - }); - - it('connection belongsTo', async () => { - const testresult = await testSchema(projectDir, 'connection', 'belongsTo'); - expect(testresult).toBeTruthy(); - }); - - it('connection hasMany', async () => { - const testresult = await testSchema(projectDir, 'connection', 'hasMany'); - expect(testresult).toBeTruthy(); - }); - - it('connection hasOne1', async () => { - const testresult = await testSchema(projectDir, 'connection', 'hasOne1'); - expect(testresult).toBeTruthy(); - }); - - it('connection hasOne2', async () => { - const testresult = await testSchema(projectDir, 'connection', 'hasOne2'); - expect(testresult).toBeTruthy(); - }); - - it('connection manyToMany', async () => { - const testresult = await testSchema(projectDir, 'connection', 'manyToMany'); - expect(testresult).toBeTruthy(); - }); - - it('connection limit', async () => { - const testresult = await testSchema(projectDir, 'connection', 'limit'); - expect(testresult).toBeTruthy(); - }); -}); diff --git a/packages/amplify-e2e-tests/src/__tests__/schema-key.test.ts b/packages/amplify-e2e-tests/src/__tests__/schema-key.test.ts deleted file mode 100644 index 5c3e20b608..0000000000 --- a/packages/amplify-e2e-tests/src/__tests__/schema-key.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { - initJSProjectWithProfile, - deleteProject, - createNewProjectDir, - deleteProjectDir, - createRandomName, -} from 'amplify-category-api-e2e-core'; -import { testSchema } from '../schema-api-directives'; - -describe('api directives @key', () => { - let projectDir: string; - let appName: string; - - beforeEach(async () => { - appName = createRandomName(); - projectDir = await createNewProjectDir('key'); - await initJSProjectWithProfile(projectDir, { name: appName }); - }); - - afterEach(async () => { - await deleteProject(projectDir); - deleteProjectDir(projectDir); - }); - - it('key howTo1', async () => { - const testresult = await testSchema(projectDir, 'key', 'howTo1'); - expect(testresult).toBeTruthy(); - }); - - it('key howTo2', async () => { - const testresult = await testSchema(projectDir, 'key', 'howTo2'); - expect(testresult).toBeTruthy(); - }); - - it('key howTo3', async () => { - const testresult = await testSchema(projectDir, 'key', 'howTo3'); - expect(testresult).toBeTruthy(); - }); - - it('key SelectiveSync with key directive', async () => { - const testresult = await testSchema(projectDir, 'key', 'howTo4', appName); - expect(testresult).toBeTruthy(); - }); -}); diff --git a/packages/amplify-e2e-tests/src/__tests__/schema-versioned.test.ts b/packages/amplify-e2e-tests/src/__tests__/schema-versioned.test.ts deleted file mode 100644 index ea06267c38..0000000000 --- a/packages/amplify-e2e-tests/src/__tests__/schema-versioned.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { initJSProjectWithProfile, deleteProject, createNewProjectDir, deleteProjectDir } from 'amplify-category-api-e2e-core'; -import { testSchema } from '../schema-api-directives'; - -describe('api directives @versioned', () => { - let projectDir: string; - - beforeEach(async () => { - projectDir = await createNewProjectDir('versioned'); - await initJSProjectWithProfile(projectDir, {}); - }); - - afterEach(async () => { - await deleteProject(projectDir); - deleteProjectDir(projectDir); - }); - - it('versioned usage', async () => { - const testresult = await testSchema(projectDir, 'versioned', 'usage'); - expect(testresult).toBeTruthy(); - }); -}); diff --git a/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/auth-migration.test.ts b/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/auth-migration.test.ts deleted file mode 100644 index ac83a95658..0000000000 --- a/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/auth-migration.test.ts +++ /dev/null @@ -1,275 +0,0 @@ -import { - initJSProjectWithProfile, - deleteProject, - amplifyPush, - amplifyPushUpdate, - addFeatureFlag, - createRandomName, - updateApiSchema, - createNewProjectDir, - deleteProjectDir, - updateApiWithMultiAuth, - addApiWithoutSchema, - updateAuthAddUserGroups, -} from 'amplify-category-api-e2e-core'; -import gql from 'graphql-tag'; - -(global as any).fetch = require('node-fetch'); - -import { default as CognitoClient } from 'aws-sdk/clients/cognitoidentityserviceprovider'; -import { Auth } from 'aws-amplify'; -import moment from 'moment'; -import { IAM } from 'aws-sdk'; -import { - configureAmplify, - getUserPoolId, - getConfiguredAppsyncClientCognitoAuth, - getConfiguredAppsyncClientAPIKeyAuth, - getApiKey, - getConfiguredAppsyncClientIAMAuth, - setupUser, - signInUser, -} from '../../schema-api-directives'; - -describe('transformer @auth migration test', () => { - let projRoot: string; - let projectName: string; - - const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); - const GROUPNAME = 'Admin'; - const PASSWORD = 'user1Password'; - const NEW_PASSWORD = 'user1Password!!!**@@@'; - const EMAIL = 'username@amazon.com'; - const UNAUTH_ROLE_NAME = `unauthRole${BUILD_TIMESTAMP}`; - - const modelSchemaV1 = 'transformer_migration/auth-model-v1.graphql'; - const modelSchemaV2 = 'transformer_migration/auth-model-v2.graphql'; - - beforeEach(async () => { - projectName = createRandomName(); - projRoot = await createNewProjectDir(projectName); - await initJSProjectWithProfile(projRoot, { name: projectName }); - - await addApiWithoutSchema(projRoot, { apiName: projectName, transformerVersion: 1 }); - await updateApiWithMultiAuth(projRoot, {}); - updateApiSchema(projRoot, projectName, modelSchemaV1); - await updateAuthAddUserGroups(projRoot, [GROUPNAME]); - await amplifyPush(projRoot); - }); - - afterEach(async () => { - await deleteProject(projRoot); - deleteProjectDir(projRoot); - }); - - it('migration of queries with different auth methods should succeed', async () => { - const iamHelper = new IAM({ region: 'us-east-2' }); - const awsconfig = configureAmplify(projRoot); - const userPoolId = getUserPoolId(projRoot); - - await setupUser(userPoolId, EMAIL, PASSWORD); - const user = await signInUser(EMAIL, PASSWORD); - - let apiKey = getApiKey(projRoot); - - let appSyncClientViaUser = getConfiguredAppsyncClientCognitoAuth( - awsconfig.aws_appsync_graphqlEndpoint, - awsconfig.aws_appsync_region, - user, - ); - let appSyncClientViaApiKey = getConfiguredAppsyncClientAPIKeyAuth( - awsconfig.aws_appsync_graphqlEndpoint, - awsconfig.aws_appsync_region, - apiKey, - ); - let appSyncClientViaIAM = getConfiguredAppsyncClientIAMAuth(awsconfig.aws_appsync_graphqlEndpoint, awsconfig.aws_appsync_region); - - let createPostMutation = /* GraphQL */ ` - mutation CreatePost { - createPost(input: { title: "Created in V1" }) { - id - } - } - `; - - let createPostResult = await appSyncClientViaUser.mutate({ - mutation: gql(createPostMutation), - fetchPolicy: 'no-cache', - }); - - expect(createPostResult.errors).toBeUndefined(); - expect(createPostResult.data).toBeDefined(); - - let createPostPublicMutation = /* GraphQL */ ` - mutation CreatePostPublic { - createPostPublic(input: { title: "Created in V1" }) { - id - } - } - `; - - let createPostPublicResult = await appSyncClientViaApiKey.mutate({ - mutation: gql(createPostPublicMutation), - fetchPolicy: 'no-cache', - }); - - expect(createPostPublicResult.errors).toBeUndefined(); - expect(createPostPublicResult.data).toBeDefined(); - - let createPostPublicIAMMutation = /* GraphQL */ ` - mutation CreatePostPublicIAM { - createPostPublicIAM(input: { title: "Created in V1" }) { - id - } - } - `; - - let createPostPublicIAMResult = await appSyncClientViaIAM.mutate({ - mutation: gql(createPostPublicIAMMutation), - fetchPolicy: 'no-cache', - }); - - expect(createPostPublicIAMResult.errors).toBeUndefined(); - expect(createPostPublicIAMResult.data).toBeDefined(); - - let createSalaryMutation = /* GraphQL */ ` - mutation CreateSalary { - createSalary(input: { wage: 1000000000 }) { - id - owner - } - } - `; - - let createSalaryResult = await appSyncClientViaUser.mutate({ - mutation: gql(createSalaryMutation), - fetchPolicy: 'no-cache', - }); - - expect(createSalaryResult.errors).toBeUndefined(); - expect(createSalaryResult.data).toBeDefined(); - - addFeatureFlag(projRoot, 'graphqltransformer', 'transformerVersion', 2); - addFeatureFlag(projRoot, 'graphqltransformer', 'useExperimentalPipelinedTransformer', true); - - await updateApiSchema(projRoot, projectName, modelSchemaV2); - await amplifyPushUpdate(projRoot); - - appSyncClientViaUser = getConfiguredAppsyncClientCognitoAuth(awsconfig.aws_appsync_graphqlEndpoint, awsconfig.aws_appsync_region, user); - - createPostMutation = /* GraphQL */ ` - mutation CreatePost { - createPost(input: { title: "Created in V2" }) { - id - } - } - `; - - createPostResult = await appSyncClientViaUser.mutate({ - mutation: gql(createPostMutation), - fetchPolicy: 'no-cache', - }); - - expect(createPostResult.errors).toBeUndefined(); - expect(createPostResult.data).toBeDefined(); - - apiKey = getApiKey(projRoot); - appSyncClientViaApiKey = getConfiguredAppsyncClientAPIKeyAuth( - awsconfig.aws_appsync_graphqlEndpoint, - awsconfig.aws_appsync_region, - apiKey, - ); - - createPostPublicMutation = /* GraphQL */ ` - mutation CreatePostPublic { - createPostPublic(input: { title: "Created in V1" }) { - id - } - } - `; - - createPostPublicResult = await appSyncClientViaApiKey.mutate({ - mutation: gql(createPostPublicMutation), - fetchPolicy: 'no-cache', - }); - - expect(createPostPublicResult.errors).toBeUndefined(); - expect(createPostPublicResult.data).toBeDefined(); - - createSalaryMutation = /* GraphQL */ ` - mutation CreateSalary { - createSalary(input: { wage: 1000000000 }) { - id - owner - } - } - `; - - createSalaryResult = await appSyncClientViaUser.mutate({ - mutation: gql(createSalaryMutation), - fetchPolicy: 'no-cache', - }); - - expect(createSalaryResult.errors).toBeUndefined(); - expect(createSalaryResult.data).toBeDefined(); - - const postsQuery = /* GraphQL */ ` - query ListPosts { - listPosts { - items { - id - title - } - } - } - `; - - let queryResult = await appSyncClientViaUser.query({ - query: gql(postsQuery), - fetchPolicy: 'no-cache', - }); - - expect(queryResult.errors).toBeUndefined(); - expect(queryResult.data).toBeDefined(); - expect((queryResult.data as any).listPosts.items.length).toEqual(2); - - const postPublicsQuery = /* GraphQL */ ` - query ListPostPublics { - listPostPublics { - items { - id - title - } - } - } - `; - - queryResult = await appSyncClientViaApiKey.query({ - query: gql(postPublicsQuery), - fetchPolicy: 'no-cache', - }); - - expect(queryResult.errors).toBeUndefined(); - expect(queryResult.data).toBeDefined(); - expect((queryResult.data as any).listPostPublics.items.length).toEqual(2); - - const salaryQuery = /* GraphQL */ ` - query ListSalary { - listSalaries { - items { - wage - } - } - } - `; - - queryResult = await appSyncClientViaUser.query({ - query: gql(salaryQuery), - fetchPolicy: 'no-cache', - }); - - expect(queryResult.errors).toBeUndefined(); - expect(queryResult.data).toBeDefined(); - expect((queryResult.data as any).listSalaries.items.length).toEqual(2); - }); -}); diff --git a/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/function-migration.test.ts b/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/function-migration.test.ts deleted file mode 100644 index f0063bcf1c..0000000000 --- a/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/function-migration.test.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { - initJSProjectWithProfile, - deleteProject, - createNewProjectDir, - deleteProjectDir, - addFeatureFlag, - amplifyPush, - addApi, - amplifyPushUpdate, -} from 'amplify-category-api-e2e-core'; -import { addSimpleFunction, updateFunctionNameInSchema } from '../../schema-api-directives/functionTester'; -import { updateSchemaInTestProject, testQueries } from '../../schema-api-directives/common'; -import { getApiKey, configureAmplify, getConfiguredAppsyncClientAPIKeyAuth } from '../../schema-api-directives/authHelper'; - -describe('api directives @function v1 to v2 migration', () => { - let projectDir: string; - - beforeEach(async () => { - projectDir = await createNewProjectDir('function'); - await initJSProjectWithProfile(projectDir, {}); - }); - - afterEach(async () => { - await deleteProject(projectDir); - deleteProjectDir(projectDir); - }); - - it('function directive migration testing', async () => { - const testModule = { - func1, - func2, - schema, - query, - expected_result_query, - }; - const v1TransformerVersion = 'v1'; - const v2TransformerVersion = 'v2'; - const function1Name = await addSimpleFunction(projectDir, testModule, 'func1'); - const function2Name = await addSimpleFunction(projectDir, testModule, 'func2'); - await addApi(projectDir, { transformerVersion: 1 }); - updateSchemaInTestProject(projectDir, testModule.schema); - updateFunctionNameInSchema(projectDir, '', function1Name); - updateFunctionNameInSchema(projectDir, '', function2Name); - updateFunctionNameInSchema(projectDir, '', v1TransformerVersion); - await amplifyPush(projectDir); - - let awsconfig = configureAmplify(projectDir); - let apiKey = getApiKey(projectDir); - let appSyncClient = getConfiguredAppsyncClientAPIKeyAuth(awsconfig.aws_appsync_graphqlEndpoint, awsconfig.aws_appsync_region, apiKey); - - await testQueries(testModule, appSyncClient); - - await addFeatureFlag(projectDir, 'graphqltransformer', 'transformerVersion', 2); - await addFeatureFlag(projectDir, 'graphqltransformer', 'useExperimentalPipelinedTransformer', true); - updateSchemaInTestProject(projectDir, testModule.schema); - updateFunctionNameInSchema(projectDir, '', function1Name); - updateFunctionNameInSchema(projectDir, '', function2Name); - updateFunctionNameInSchema(projectDir, '', v2TransformerVersion); - await amplifyPushUpdate(projectDir); - - awsconfig = configureAmplify(projectDir); - apiKey = getApiKey(projectDir); - appSyncClient = getConfiguredAppsyncClientAPIKeyAuth(awsconfig.aws_appsync_graphqlEndpoint, awsconfig.aws_appsync_region, apiKey); - - await testQueries(testModule, appSyncClient); - }); - - // schema - const env = '${env}'; - const schema = ` - #Transformer Version: - type Query { - doSomeWork(msg: String): String @function(name: "-${env}") @function(name: "-${env}") - } - `; - - // functions - const func1 = ` - exports.handler = async event => { - return event.arguments.msg + '|processed by worker-function'; - }; - `; - const func2 = ` - exports.handler = async event => { - return event.prev.result + '|processed by audit function'; - }; - `; - - // queries - const query = ` - query DoSomeWork { - doSomeWork(msg: "initial mutation message") - } - `; - const expected_result_query = { - data: { - doSomeWork: 'initial mutation message|processed by worker-function|processed by audit function', - }, - }; -}); diff --git a/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/http-migration.test.ts b/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/http-migration.test.ts deleted file mode 100644 index 7624bf734c..0000000000 --- a/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/http-migration.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { - initJSProjectWithProfile, - deleteProject, - amplifyPush, - amplifyPushForce, - addFeatureFlag, - createRandomName, - addAuthWithDefault, - addApiWithoutSchema, - updateApiSchema, - createNewProjectDir, - deleteProjectDir, -} from 'amplify-category-api-e2e-core'; - -describe('transformer @http migration test', () => { - let projRoot: string; - let projectName: string; - - beforeEach(async () => { - projectName = createRandomName(); - projRoot = await createNewProjectDir(createRandomName()); - await initJSProjectWithProfile(projRoot, { name: projectName }); - await addAuthWithDefault(projRoot, {}); - }); - - afterEach(async () => { - await deleteProject(projRoot); - deleteProjectDir(projRoot); - }); - - it('migration of @http schema', async () => { - const httpSchema = 'transformer_migration/http.graphql'; - - await addApiWithoutSchema(projRoot, { apiName: projectName, transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, httpSchema); - await amplifyPush(projRoot); - - await addFeatureFlag(projRoot, 'graphqltransformer', 'transformerVersion', 2); - await addFeatureFlag(projRoot, 'graphqltransformer', 'useExperimentalPipelinedTransformer', true); - - await updateApiSchema(projRoot, projectName, httpSchema); - await amplifyPushForce(projRoot); - }); -}); diff --git a/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/model-migration.test.ts b/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/model-migration.test.ts deleted file mode 100644 index 7265902f91..0000000000 --- a/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/model-migration.test.ts +++ /dev/null @@ -1,276 +0,0 @@ -import { - initJSProjectWithProfile, - deleteProject, - amplifyPush, - amplifyPushUpdate, - addFeatureFlag, - createRandomName, - addAuthWithDefault, - addApiWithoutSchema, - updateApiSchema, - getProjectMeta, - createNewProjectDir, - deleteProjectDir, -} from 'amplify-category-api-e2e-core'; -import AWSAppSyncClient, { AUTH_TYPE } from 'aws-appsync'; -import gql from 'graphql-tag'; - -(global as any).fetch = require('node-fetch'); - -describe('transformer model migration test', () => { - let projRoot: string; - let projectName: string; - - beforeEach(async () => { - projectName = createRandomName(); - projRoot = await createNewProjectDir(createRandomName()); - await initJSProjectWithProfile(projRoot, { name: projectName }); - await addAuthWithDefault(projRoot, {}); - }); - - afterEach(async () => { - await deleteProject(projRoot); - deleteProjectDir(projRoot); - }); - - it('migration of model key queries timestamps should succeed', async () => { - const modelSchemaV1 = 'transformer_migration/basic-model-v1.graphql'; - const modelSchemaV2 = 'transformer_migration/basic-model-v2.graphql'; - - await addApiWithoutSchema(projRoot, { apiName: projectName, transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, modelSchemaV1); - await amplifyPush(projRoot); - - let appSyncClient = getAppSyncClientFromProj(projRoot); - - let createPostMutation = /* GraphQL */ ` - mutation CreatePost { - createPost(input: { title: "Created in V1" }) { - id - } - } - `; - - let createPostResult = await appSyncClient.mutate({ - mutation: gql(createPostMutation), - fetchPolicy: 'no-cache', - }); - - expect(createPostResult.errors).toBeUndefined(); - expect(createPostResult.data).toBeDefined(); - - let createCustomerMutation = /* GraphQL */ ` - mutation CreateCustomer { - createCustomer(input: { email: "v1@test.com" }) { - email - } - } - `; - - let createCustomerResult = await appSyncClient.mutate({ - mutation: gql(createCustomerMutation), - fetchPolicy: 'no-cache', - }); - - expect(createCustomerResult.errors).toBeUndefined(); - expect(createCustomerResult.data).toBeDefined(); - - let createTestMutation = /* GraphQL */ ` - mutation CreateTest { - createTest(input: { title: "Created in V1" }) { - id - } - } - `; - - let createTestResult = await appSyncClient.mutate({ - mutation: gql(createTestMutation), - fetchPolicy: 'no-cache', - }); - - expect(createTestResult.errors).toBeUndefined(); - expect(createTestResult.data).toBeDefined(); - - let createRenameMutation = /* GraphQL */ ` - mutation CreateRename { - makeRename(input: { title: "Created in V1" }) { - id - } - } - `; - - let createRenameResult = await appSyncClient.mutate({ - mutation: gql(createRenameMutation), - fetchPolicy: 'no-cache', - }); - - expect(createRenameResult.errors).toBeUndefined(); - expect(createRenameResult.data).toBeDefined(); - - await addFeatureFlag(projRoot, 'graphqltransformer', 'transformerVersion', 2); - await addFeatureFlag(projRoot, 'graphqltransformer', 'useExperimentalPipelinedTransformer', true); - - await updateApiSchema(projRoot, projectName, modelSchemaV2); - await amplifyPushUpdate(projRoot); - - appSyncClient = getAppSyncClientFromProj(projRoot); - - createPostMutation = /* GraphQL */ ` - mutation CreatePost { - createPost(input: { title: "Created in V2" }) { - id - } - } - `; - - createPostResult = await appSyncClient.mutate({ - mutation: gql(createPostMutation), - fetchPolicy: 'no-cache', - }); - - expect(createPostResult.errors).toBeUndefined(); - expect(createPostResult.data).toBeDefined(); - - createCustomerMutation = /* GraphQL */ ` - mutation CreateCustomer { - createCustomer(input: { email: "v2@test.com" }) { - email - } - } - `; - - createCustomerResult = await appSyncClient.mutate({ - mutation: gql(createCustomerMutation), - fetchPolicy: 'no-cache', - }); - - expect(createCustomerResult.errors).toBeUndefined(); - expect(createCustomerResult.data).toBeDefined(); - - createTestMutation = /* GraphQL */ ` - mutation CreateTest { - createTest(input: { title: "Created in V2" }) { - id - } - } - `; - - createTestResult = await appSyncClient.mutate({ - mutation: gql(createTestMutation), - fetchPolicy: 'no-cache', - }); - - expect(createTestResult.errors).toBeUndefined(); - expect(createTestResult.data).toBeDefined(); - - createRenameMutation = /* GraphQL */ ` - mutation CreateRename { - makeRename(input: { title: "Created in V2" }) { - id - } - } - `; - - createRenameResult = await appSyncClient.mutate({ - mutation: gql(createRenameMutation), - fetchPolicy: 'no-cache', - }); - - expect(createRenameResult.errors).toBeUndefined(); - expect(createRenameResult.data).toBeDefined(); - - const postsQuery = /* GraphQL */ ` - query ListPosts { - listPosts { - items { - id - title - } - } - } - `; - - let queryResult = await appSyncClient.query({ - query: gql(postsQuery), - fetchPolicy: 'no-cache', - }); - - expect(queryResult.errors).toBeUndefined(); - expect(queryResult.data).toBeDefined(); - expect((queryResult.data as any).listPosts.items.length).toEqual(2); - - const customersQuery = /* GraphQL */ ` - query ListCustomers { - listCustomers { - items { - email - } - } - } - `; - - queryResult = await appSyncClient.query({ - query: gql(customersQuery), - fetchPolicy: 'no-cache', - }); - - expect(queryResult.errors).toBeUndefined(); - expect(queryResult.data).toBeDefined(); - expect((queryResult.data as any).listCustomers.items.length).toEqual(2); - - const testsQuery = /* GraphQL */ ` - query ListTests { - listTests { - items { - id - title - } - } - } - `; - - queryResult = await appSyncClient.query({ - query: gql(testsQuery), - fetchPolicy: 'no-cache', - }); - - expect(queryResult.errors).toBeUndefined(); - expect(queryResult.data).toBeDefined(); - expect((queryResult.data as any).listTests.items.length).toEqual(2); - - const renamesQuery = /* GraphQL */ ` - query GetRename { - rename (id: "${(createRenameResult.data as any).makeRename.id}") { - id - title - } - } - `; - - queryResult = await appSyncClient.query({ - query: gql(renamesQuery), - fetchPolicy: 'no-cache', - }); - - expect(queryResult.errors).toBeUndefined(); - expect(queryResult.data).toBeDefined(); - }); - - const getAppSyncClientFromProj = (projRoot: string) => { - const meta = getProjectMeta(projRoot); - const region = meta['providers']['awscloudformation']['Region'] as string; - const { output } = meta.api[projectName]; - const url = output.GraphQLAPIEndpointOutput as string; - const apiKey = output.GraphQLAPIKeyOutput as string; - - return new AWSAppSyncClient({ - url, - region, - disableOffline: true, - auth: { - type: AUTH_TYPE.API_KEY, - apiKey, - }, - }); - }; -}); diff --git a/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/predictions-migration.test.ts b/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/predictions-migration.test.ts deleted file mode 100644 index d64df64963..0000000000 --- a/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/predictions-migration.test.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { - initJSProjectWithProfile, - deleteProject, - amplifyPush, - amplifyPushUpdate, - addFeatureFlag, - createRandomName, - addS3AndAuthWithAuthOnlyAccess, - amplifyPushForce, - addApiWithoutSchema, - updateApiSchema, - getProjectMeta, - createNewProjectDir, - deleteProjectDir, -} from 'amplify-category-api-e2e-core'; -import AWSAppSyncClient, { AUTH_TYPE } from 'aws-appsync'; -import gql from 'graphql-tag'; - -(global as any).fetch = require('node-fetch'); - -describe('transformer predictions migration test', () => { - let projRoot: string; - let projectName: string; - - beforeEach(async () => { - projectName = createRandomName(); - projRoot = await createNewProjectDir(createRandomName()); - await initJSProjectWithProfile(projRoot, { name: projectName }); - await addS3AndAuthWithAuthOnlyAccess(projRoot, {}); - }); - - afterEach(async () => { - await deleteProject(projRoot); - deleteProjectDir(projRoot); - }); - - it('migration of predictions directives', async () => { - const predictionsSchema = 'transformer_migration/predictions.graphql'; - - await addApiWithoutSchema(projRoot, { apiName: projectName, transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, predictionsSchema); - await amplifyPush(projRoot); - - let appSyncClient = getAppSyncClientFromProj(projRoot); - - let translateQuery = /* GraphQL */ ` - query TranslateThis { - translateThis(input: { translateText: { sourceLanguage: "en", targetLanguage: "de", text: "This is a voice test" } }) - } - `; - - let translateResult = await appSyncClient.query({ - query: gql(translateQuery), - fetchPolicy: 'no-cache', - }); - - expect(translateResult.errors).toBeUndefined(); - expect(translateResult.data).toBeDefined(); - expect((translateResult.data as any).translateThis).toMatch( - /((\bDies\b)|(\bdas\b)|(\bder\b)) ist ein ((\bStimmtest\b)|(\Sprachtest\b)|(\bStimmetest\b)|(\bStimmentest\b))/i, - ); - - let speakQuery = /* GraphQL */ ` - query SpeakTranslatedText { - speakTranslatedText( - input: { - translateText: { sourceLanguage: "en", targetLanguage: "es", text: "this is a voice test" } - convertTextToSpeech: { voiceID: "Conchita" } - } - ) - } - `; - - let speakResult = await appSyncClient.query({ - query: gql(speakQuery), - fetchPolicy: 'no-cache', - }); - - expect(speakResult.errors).toBeUndefined(); - expect(speakResult.data).toBeDefined(); - expect((speakResult.data as any).speakTranslatedText).toMatch( - /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/, - ); - - await updateApiSchema(projRoot, projectName, predictionsSchema); - await amplifyPushForce(projRoot); - - appSyncClient = getAppSyncClientFromProj(projRoot); - - translateResult = await appSyncClient.query({ - query: gql(translateQuery), - fetchPolicy: 'no-cache', - }); - - expect(translateResult.errors).toBeUndefined(); - expect(translateResult.data).toBeDefined(); - expect((translateResult.data as any).translateThis).toMatch( - /((\bDies\b)|(\bdas\b)|(\bder\b)) ist ein ((\bStimmtest\b)|(\Sprachtest\b)|(\bStimmetest\b)|(\bStimmentest\b))/i, - ); - - speakResult = await appSyncClient.query({ - query: gql(speakQuery), - fetchPolicy: 'no-cache', - }); - - expect(speakResult.errors).toBeUndefined(); - expect(speakResult.data).toBeDefined(); - expect((speakResult.data as any).speakTranslatedText).toMatch( - /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/, - ); - }); - - const getAppSyncClientFromProj = (projRoot: string) => { - const meta = getProjectMeta(projRoot); - const region = meta['providers']['awscloudformation']['Region'] as string; - const { output } = meta.api[projectName]; - const url = output.GraphQLAPIEndpointOutput as string; - const apiKey = output.GraphQLAPIKeyOutput as string; - - return new AWSAppSyncClient({ - url, - region, - disableOffline: true, - auth: { - type: AUTH_TYPE.API_KEY, - apiKey, - }, - }); - }; -}); diff --git a/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/searchable-migration.test.ts b/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/searchable-migration.test.ts deleted file mode 100644 index a575be3af9..0000000000 --- a/packages/amplify-e2e-tests/src/__tests__/transformer-migrations/searchable-migration.test.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { - initJSProjectWithProfile, - deleteProject, - amplifyPush, - amplifyPushUpdate, - addFeatureFlag, - createRandomName, - addAuthWithDefault, - addApiWithoutSchema, - updateApiSchema, - getProjectMeta, - createNewProjectDir, - deleteProjectDir, - tryScheduleCredentialRefresh, -} from 'amplify-category-api-e2e-core'; -import gql from 'graphql-tag'; -import AWSAppSyncClient, { AUTH_TYPE } from 'aws-appsync'; - -(global as any).fetch = require('node-fetch'); - -jest.setTimeout(120 * 60 * 1000); // Set timeout to 2 hour because of creating/deleting searchable instance - -describe('transformer model searchable migration test', () => { - let projRoot: string; - let projectName: string; - let appSyncClient = undefined; - - beforeAll(() => { - tryScheduleCredentialRefresh(); - }); - - beforeEach(async () => { - projectName = createRandomName(); - projRoot = await createNewProjectDir(createRandomName()); - await initJSProjectWithProfile(projRoot, { - name: projectName, - }); - await addAuthWithDefault(projRoot, {}); - }); - - afterEach(async () => { - await deleteProject(projRoot); - deleteProjectDir(projRoot); - }); - - it('migration of searchable directive - search should return expected results', async () => { - const v1Schema = 'transformer_migration/searchable-v1.graphql'; - const v2Schema = 'transformer_migration/searchable-v2.graphql'; - - await addApiWithoutSchema(projRoot, { apiName: projectName, transformerVersion: 1 }); - await updateApiSchema(projRoot, projectName, v1Schema); - await amplifyPush(projRoot); - - appSyncClient = getAppSyncClientFromProj(projRoot); - await runAndValidateQuery('test1', 'test1', 10); - - await addFeatureFlag(projRoot, 'graphqltransformer', 'transformerVersion', 2); - await addFeatureFlag(projRoot, 'graphqltransformer', 'useExperimentalPipelinedTransformer', true); - - await updateApiSchema(projRoot, projectName, v2Schema); - await amplifyPushUpdate(projRoot); - - appSyncClient = getAppSyncClientFromProj(projRoot); - await runAndValidateQuery('test2', 'test2', 10); - }); - - const getAppSyncClientFromProj = (projRoot: string) => { - const meta = getProjectMeta(projRoot); - const region = meta['providers']['awscloudformation']['Region'] as string; - const { output } = meta.api[projectName]; - const url = output.GraphQLAPIEndpointOutput as string; - const apiKey = output.GraphQLAPIKeyOutput as string; - - return new AWSAppSyncClient({ - url, - region, - disableOffline: true, - auth: { - type: AUTH_TYPE.API_KEY, - apiKey, - }, - }); - }; - - const fragments = [`fragment FullTodo on Todo { id name description count }`]; - - const runMutation = async (query: string) => { - try { - const q = [query, ...fragments].join('\n'); - const response = await appSyncClient.mutate({ - mutation: gql(q), - fetchPolicy: 'no-cache', - }); - return response; - } catch (e) { - console.error(e); - return null; - } - }; - - const createEntry = async (name: string, description: string, count: number) => { - return await runMutation(getCreateTodosMutation(name, description, count)); - }; - - function getCreateTodosMutation(name: string, description: string, count: number): string { - return `mutation { - createTodo(input: { - name: "${name}" - description: "${description}" - count: ${count} - }) { ...FullTodo } - }`; - } - - const runAndValidateQuery = async (name: string, description: string, count: number) => { - const response = await createEntry(name, description, count); - expect(response).toBeDefined(); - expect(response.errors).toBeUndefined(); - expect(response.data).toBeDefined(); - expect(response.data.createTodo).toBeDefined(); - }; -}); diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/ConnectionsWithAuthTests.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/ConnectionsWithAuthTests.e2e.test.ts deleted file mode 100644 index 8ca98ae6f4..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/ConnectionsWithAuthTests.e2e.test.ts +++ /dev/null @@ -1,514 +0,0 @@ -import * as fs from 'fs'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as S3, CreateBucketRequest } from 'aws-sdk/clients/s3'; -import { default as CognitoClient } from 'aws-sdk/clients/cognitoidentityserviceprovider'; -import { default as moment } from 'moment'; -import { GraphQLClient } from '../GraphQLClient'; -import { S3Client } from '../S3Client'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { - createUserPool, - createUserPoolClient, - createGroup, - addUserToGroup, - configureAmplify, - signupUser, - authenticateUser, -} from '../cognitoUtils'; -import 'isomorphic-fetch'; - -// to deal with bug in cognito-identity-js -(global as any).fetch = require('node-fetch'); - -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `ConnectionsWithAuthTests-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `connections-with-auth-test-bucket-${BUILD_TIMESTAMP}`; -const LOCAL_BUILD_ROOT = '/tmp/connections_with_auth_test/'; -const DEPLOYMENT_ROOT_KEY = 'deployments'; - -let GRAPHQL_ENDPOINT = undefined; - -/** - * Client 1 is logged in and is a member of the Admin group. - */ -let GRAPHQL_CLIENT_1 = undefined; - -/** - * Client 2 is logged in and is a member of the Devs group. - */ -let GRAPHQL_CLIENT_2 = undefined; - -/** - * Client 3 is logged in and has no group memberships. - */ -let GRAPHQL_CLIENT_3 = undefined; - -let USER_POOL_ID = undefined; - -const USERNAME1 = 'user1@test.com'; -const USERNAME2 = 'user2@test.com'; -const USERNAME3 = 'user3@test.com'; -const TMP_PASSWORD = 'Password123!'; -const REAL_PASSWORD = 'Password1234!'; - -const ADMIN_GROUP_NAME = 'Admin'; -const DEVS_GROUP_NAME = 'Devs'; -const PARTICIPANT_GROUP_NAME = 'Participant'; -const WATCHER_GROUP_NAME = 'Watcher'; - -const cognitoClient = new CognitoClient({ apiVersion: '2016-04-19', region: region }); -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -async function createBucket(name: string) { - return new Promise((res, rej) => { - const params: CreateBucketRequest = { - Bucket: name, - }; - awsS3Client.createBucket(params, (err, data) => (err ? rej(err) : res(data))); - }); -} - -async function deleteBucket(name: string) { - return new Promise((res, rej) => { - const params: CreateBucketRequest = { - Bucket: name, - }; - awsS3Client.deleteBucket(params, (err, data) => (err ? rej(err) : res(data))); - }); -} - -beforeAll(async () => { - // Create a stack for the post model with auth enabled. - if (!fs.existsSync(LOCAL_BUILD_ROOT)) { - fs.mkdirSync(LOCAL_BUILD_ROOT); - } - await createBucket(BUCKET_NAME); - const validSchema = ` - type Post @model( - subscriptions: { - level: public - })@auth(rules: [{ allow: owner }]) { - id: ID! - title: String! - author: User @connection(name: "UserPosts", keyField: "owner") - owner: String - } - type User @model( - subscriptions: { - level: public - }) @auth(rules: [{ allow: owner }]) { - id: ID! - posts: [Post!]! @connection(name: "UserPosts", keyField: "owner") - } - type FieldProtected @model( - subscriptions: { - level: public - }){ - id: ID! - owner: String - ownerOnly: String @auth(rules: [{ allow: owner }]) - } - type OpenTopLevel @model( - subscriptions: { - level: public - }) { - id: ID! - name: String - owner: String - protected: [ConnectionProtected] @connection(name: "ProtectedConnection") - } - type ConnectionProtected @model( - subscriptions: { - level: public - } - queries: null - )@auth(rules: [{ allow: owner }]) { - id: ID! - name: String - owner: String - topLevel: OpenTopLevel @connection(name: "ProtectedConnection") - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelConnectionTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const userPoolResponse = await createUserPool(cognitoClient, `UserPool${STACK_NAME}`); - USER_POOL_ID = userPoolResponse.UserPool.Id; - const userPoolClientResponse = await createUserPoolClient(cognitoClient, USER_POOL_ID, `UserPool${STACK_NAME}`); - const userPoolClientId = userPoolClientResponse.UserPoolClient.ClientId; - try { - // Clean the bucket - const out = transformer.transform(validSchema); - - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { AuthCognitoUserPoolId: USER_POOL_ID }, - LOCAL_BUILD_ROOT, - BUCKET_NAME, - DEPLOYMENT_ROOT_KEY, - BUILD_TIMESTAMP, - ); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - GRAPHQL_ENDPOINT = getApiEndpoint(finishedStack.Outputs); - - // Verify we have all the details - expect(GRAPHQL_ENDPOINT).toBeTruthy(); - expect(USER_POOL_ID).toBeTruthy(); - expect(userPoolClientId).toBeTruthy(); - - // Configure Amplify, create users, and sign in. - configureAmplify(USER_POOL_ID, userPoolClientId); - - await signupUser(USER_POOL_ID, USERNAME1, TMP_PASSWORD); - await signupUser(USER_POOL_ID, USERNAME2, TMP_PASSWORD); - await signupUser(USER_POOL_ID, USERNAME3, TMP_PASSWORD); - await createGroup(USER_POOL_ID, ADMIN_GROUP_NAME); - await createGroup(USER_POOL_ID, PARTICIPANT_GROUP_NAME); - await createGroup(USER_POOL_ID, WATCHER_GROUP_NAME); - await createGroup(USER_POOL_ID, DEVS_GROUP_NAME); - await addUserToGroup(ADMIN_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(PARTICIPANT_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(WATCHER_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(DEVS_GROUP_NAME, USERNAME2, USER_POOL_ID); - const authResAfterGroup: any = await authenticateUser(USERNAME1, TMP_PASSWORD, REAL_PASSWORD); - - const idToken = authResAfterGroup.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_1 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken }); - - const authRes2AfterGroup: any = await authenticateUser(USERNAME2, TMP_PASSWORD, REAL_PASSWORD); - const idToken2 = authRes2AfterGroup.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_2 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken2 }); - - const authRes3: any = await authenticateUser(USERNAME3, TMP_PASSWORD, REAL_PASSWORD); - const idToken3 = authRes3.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_3 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken3 }); - - // Wait for any propagation to avoid random - // "The security token included in the request is invalid" errors - await new Promise((res) => setTimeout(() => res(), 5000)); - } catch (e) { - console.error(e); - throw e; - } -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf, { cognitoClient, userPoolId: USER_POOL_ID }); -}); - -/** - * Tests - */ -test('creating a post and immediately view it via the User.posts connection.', async () => { - const createUser1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createUser(input: { id: "user1@test.com" }) { - id - } - }`, - {}, - ); - expect(createUser1.data.createUser.id).toEqual('user1@test.com'); - - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - owner - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.owner).toBeDefined(); - - const getResponse = await GRAPHQL_CLIENT_1.query( - `query { - getUser(id: "user1@test.com") { - posts { - items { - id - title - owner - author { - id - } - } - } - } - }`, - {}, - ); - expect(getResponse.data.getUser.posts.items[0].id).toBeDefined(); - expect(getResponse.data.getUser.posts.items[0].title).toEqual('Hello, World!'); - expect(getResponse.data.getUser.posts.items[0].owner).toEqual('user1@test.com'); - expect(getResponse.data.getUser.posts.items[0].author.id).toEqual('user1@test.com'); -}); - -test('Testing reading an owner protected field as a non owner', async () => { - const response1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createFieldProtected(input: { id: "1", owner: "${USERNAME1}", ownerOnly: "owner-protected" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response1.data.createFieldProtected.id).toEqual('1'); - expect(response1.data.createFieldProtected.owner).toEqual(USERNAME1); - expect(response1.data.createFieldProtected.ownerOnly).toEqual('owner-protected'); - - const response2 = await GRAPHQL_CLIENT_2.query( - `query { - getFieldProtected(id: "1") { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response2.data.getFieldProtected.ownerOnly).toBeNull(); - expect(response2.errors).toHaveLength(1); - - const response3 = await GRAPHQL_CLIENT_1.query( - `query { - getFieldProtected(id: "1") { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response3.data.getFieldProtected.id).toEqual('1'); - expect(response3.data.getFieldProtected.owner).toEqual(USERNAME1); - expect(response3.data.getFieldProtected.ownerOnly).toEqual('owner-protected'); -}); - -test('that @connection resolvers respect @model read operations.', async () => { - const response1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createOpenTopLevel(input: { id: "1", owner: "${USERNAME1}", name: "open" }) { - id - owner - name - } - }`, - {}, - ); - expect(response1.data.createOpenTopLevel.id).toEqual('1'); - expect(response1.data.createOpenTopLevel.owner).toEqual(USERNAME1); - expect(response1.data.createOpenTopLevel.name).toEqual('open'); - - const response2 = await GRAPHQL_CLIENT_2.query( - `mutation { - createConnectionProtected(input: { id: "1", owner: "${USERNAME2}", name: "closed", connectionProtectedTopLevelId: "1" }) { - id - owner - name - } - }`, - {}, - ); - expect(response2.data.createConnectionProtected.id).toEqual('1'); - expect(response2.data.createConnectionProtected.owner).toEqual(USERNAME2); - expect(response2.data.createConnectionProtected.name).toEqual('closed'); - - const response3 = await GRAPHQL_CLIENT_1.query( - `query { - getOpenTopLevel(id: "1") { - id - protected { - items { - id - name - owner - } - } - } - }`, - {}, - ); - expect(response3.data.getOpenTopLevel.id).toEqual('1'); - expect(response3.data.getOpenTopLevel.protected.items).toHaveLength(0); - - const response4 = await GRAPHQL_CLIENT_2.query( - `query { - getOpenTopLevel(id: "1") { - id - protected { - items { - id - name - owner - } - } - } - }`, - {}, - ); - expect(response4.data.getOpenTopLevel.id).toEqual('1'); - expect(response4.data.getOpenTopLevel.protected.items).toHaveLength(1); -}); - -// Per field auth in mutations -test('that owners cannot set the field of a FieldProtected object unless authorized.', async () => { - const response1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createFieldProtected(input: { id: "2", owner: "${USERNAME1}", ownerOnly: "owner-protected" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response1.data.createFieldProtected.id).toEqual('2'); - expect(response1.data.createFieldProtected.owner).toEqual(USERNAME1); - expect(response1.data.createFieldProtected.ownerOnly).toEqual('owner-protected'); - - const response2 = await GRAPHQL_CLIENT_1.query( - `mutation { - createFieldProtected(input: { id: "3", owner: "${USERNAME2}", ownerOnly: "owner-protected" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response2.data.createFieldProtected).toBeNull(); - expect(response2.errors).toHaveLength(1); - - // The auth rule is on ownerOnly. Omitting the "ownerOnly" field will - // not trigger the @auth check - const response3 = await GRAPHQL_CLIENT_1.query( - `mutation { - createFieldProtected(input: { id: "4", owner: "${USERNAME2}" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response3.data.createFieldProtected.id).toEqual('4'); - expect(response3.data.createFieldProtected.owner).toEqual(USERNAME2); - // The length is one because the 'ownerOnly' field is protected on reads. - // Since the caller is not the owner this will throw after the mutation succeeds - // and return partial results. - expect(response3.errors).toHaveLength(1); -}); - -test('that owners cannot update the field of a FieldProtected object unless authorized.', async () => { - const response1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createFieldProtected(input: { owner: "${USERNAME1}", ownerOnly: "owner-protected" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response1.data.createFieldProtected.id).not.toBeNull(); - expect(response1.data.createFieldProtected.owner).toEqual(USERNAME1); - expect(response1.data.createFieldProtected.ownerOnly).toEqual('owner-protected'); - - const response2 = await GRAPHQL_CLIENT_2.query( - `mutation { - updateFieldProtected(input: { id: "${response1.data.createFieldProtected.id}", ownerOnly: "owner2-protected" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response2.data.updateFieldProtected).toBeNull(); - expect(response2.errors).toHaveLength(1); - - // The auth rule is on ownerOnly. Omitting the "ownerOnly" field will - // not trigger the @auth check - const response3 = await GRAPHQL_CLIENT_1.query( - `mutation { - updateFieldProtected(input: { id: "${response1.data.createFieldProtected.id}", ownerOnly: "updated" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response3.data.updateFieldProtected.id).toEqual(response1.data.createFieldProtected.id); - expect(response3.data.updateFieldProtected.owner).toEqual(USERNAME1); - expect(response3.data.updateFieldProtected.ownerOnly).toEqual('updated'); - - // This request should succeed since we are not updating the protected field. - const response4 = await GRAPHQL_CLIENT_3.query( - `mutation { - updateFieldProtected(input: { id: "${response1.data.createFieldProtected.id}", owner: "${USERNAME3}" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response4.data.updateFieldProtected.id).toEqual(response1.data.createFieldProtected.id); - expect(response4.data.updateFieldProtected.owner).toEqual(USERNAME3); - expect(response4.data.updateFieldProtected.ownerOnly).toEqual('updated'); -}); diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/DynamoDBModelTransformer.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/DynamoDBModelTransformer.e2e.test.ts deleted file mode 100644 index c862760277..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/DynamoDBModelTransformer.e2e.test.ts +++ /dev/null @@ -1,845 +0,0 @@ -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as S3 } from 'aws-sdk/clients/s3'; -import { default as moment } from 'moment'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { GraphQLClient } from '../GraphQLClient'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { S3Client } from '../S3Client'; -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `DynamoDBModelTransformerTest-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `appsync-model-transformer-test-bucket-${BUILD_TIMESTAMP}`; - -let GRAPHQL_CLIENT = undefined; - -const TMP_ROOT = '/tmp/model_transform_tests/'; - -const ROOT_KEY = 'deployments'; - -let GRAPHQL_ENDPOINT = undefined; - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -beforeAll(async () => { - const validSchema = /* GraphQL */ ` - type Post @model { - id: ID! - title: String! - createdAt: AWSDateTime - updatedAt: AWSDateTime - metadata: PostMetadata - entityMetadata: EntityMetadata - appearsIn: [Episode!] - episode: Episode - } - type Author @model { - id: ID! - name: String! - postMetadata: PostMetadata - entityMetadata: EntityMetadata - } - type EntityMetadata { - isActive: Boolean - } - type PostMetadata { - tags: Tag - } - type Tag { - published: Boolean - metadata: PostMetadata - } - enum Episode { - NEWHOPE - EMPIRE - JEDI - } - type Require @model { - id: ID! - requiredField: String! - notRequiredField: String - } - type Comment @model(timestamps: { createdAt: "createdOn", updatedAt: "updatedOn" }) { - id: ID! - title: String! - content: String - updatedOn: Int # No automatic generation of timestamp if its not AWSDateTime - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - // fs.writeFileSync('./out.json', JSON.stringify(out, null, 4)); - try { - await awsS3Client - .createBucket({ - Bucket: BUCKET_NAME, - }) - .promise(); - } catch (e) { - console.error(`Failed to create S3 bucket: ${e}`); - } - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { CreateAPIKey: '1', DynamoDBEnablePointInTimeRecovery: 'true' }, - TMP_ROOT, - BUCKET_NAME, - ROOT_KEY, - BUILD_TIMESTAMP, - ); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - GRAPHQL_ENDPOINT = getApiEndpoint(finishedStack.Outputs); - - const apiKey = getApiKey(finishedStack.Outputs); - expect(apiKey).toBeTruthy(); - expect(GRAPHQL_ENDPOINT).toBeTruthy(); - GRAPHQL_CLIENT = new GraphQLClient(GRAPHQL_ENDPOINT, { 'x-api-key': apiKey }); -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf); -}); - -afterEach(async () => { - // delete all the records - const response = await GRAPHQL_CLIENT.query( - ` - query { - listPosts { - items { - id - } - } - }`, - {}, - ); - const rows = response.data.listPosts.items || []; - const deletePromises = []; - rows.forEach((row) => { - deletePromises.push( - GRAPHQL_CLIENT.query(`mutation delete{ - deletePost(input: {id: "${row.id}"}) { id } - }`), - ); - }); - await Promise.all(deletePromises); -}); - -/** - * Test queries below - */ -test('createAuthor mutation', async () => { - const response = await GRAPHQL_CLIENT.query( - `mutation($input: CreateAuthorInput!) { - createAuthor(input: $input) { - id - name - entityMetadata { - isActive - } - createdAt - updatedAt - } - }`, - { - input: { - name: 'Jeff B', - entityMetadata: { - isActive: true, - }, - }, - }, - ); - expect(response.data.createAuthor.id).toBeDefined(); - expect(response.data.createAuthor.name).toEqual('Jeff B'); - expect(response.data.createAuthor.createdAt).toBeDefined(); - expect(response.data.createAuthor.updatedAt).toBeDefined(); - expect(response.data.createAuthor.entityMetadata).toBeDefined(); - expect(response.data.createAuthor.entityMetadata.isActive).toEqual(true); -}); - -test('createPost mutation', async () => { - const response = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); -}); -test('updateComment mutation with null and empty', async () => { - const requiredFieldValue = 'thisisrequired'; - const notRequiredFieldValue = 'thisisnotrequired'; - const response = await GRAPHQL_CLIENT.query( - /* GraphQL */ ` - mutation ($input: CreateRequireInput!) { - createRequire(input: $input) { - id - requiredField - notRequiredField - } - } - `, - { - input: { - requiredField: requiredFieldValue, - notRequiredField: notRequiredFieldValue, - }, - }, - ); - expect(response.data.createRequire.id).toBeDefined(); - const id = response.data.createRequire.id; - const updateResponse = await GRAPHQL_CLIENT.query( - /* GraphQL */ ` - mutation ($input: UpdateRequireInput!) { - updateRequire(input: $input) { - id - requiredField - notRequiredField - } - } - `, - { - input: { - id: id, - }, - }, - ); - expect(updateResponse.data.updateRequire.requiredField).toEqual(requiredFieldValue); - expect(updateResponse.data.updateRequire.notRequiredField).toEqual(notRequiredFieldValue); - const update2Response = await GRAPHQL_CLIENT.query( - /* GraphQL */ ` - mutation ($input: UpdateRequireInput!) { - updateRequire(input: $input) { - id - requiredField - notRequiredField - } - } - `, - { - input: { - id: id, - requiredField: null, - }, - }, - ); - expect(update2Response.errors[0].message).toEqual( - 'An argument you marked as Non-Null is set to Null in the query or the body of your request.', - ); -}); -test('updatePost mutation', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Update" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Update'); - const updateResponse = await GRAPHQL_CLIENT.query( - `mutation { - updatePost(input: { id: "${createResponse.data.createPost.id}", title: "Bye, World!" }) { - id - title - } - }`, - {}, - ); - expect(updateResponse.data.updatePost.title).toEqual('Bye, World!'); -}); - -test('createPost and updatePost mutation with a client generated id.', async () => { - const clientId = 'a-client-side-generated-id'; - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { id: "${clientId}" title: "Test Update" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toEqual(clientId); - expect(createResponse.data.createPost.title).toEqual('Test Update'); - const updateResponse = await GRAPHQL_CLIENT.query( - `mutation { - updatePost(input: { id: "${clientId}", title: "Bye, World!" }) { - id - title - } - }`, - {}, - ); - expect(updateResponse.data.updatePost.id).toEqual(clientId); - expect(updateResponse.data.updatePost.title).toEqual('Bye, World!'); - const getResponse = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${clientId}") { - id - title - } - }`, - {}, - ); - expect(getResponse.data.getPost.id).toEqual(clientId); - expect(getResponse.data.getPost.title).toEqual('Bye, World!'); - - const deleteResponse = await GRAPHQL_CLIENT.query( - `mutation { - deletePost(input: { id: "${clientId}" }) { - id - title - } - }`, - {}, - ); - expect(deleteResponse.data.deletePost.id).toEqual(clientId); - expect(deleteResponse.data.deletePost.title).toEqual('Bye, World!'); - - const getResponse2 = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${clientId}") { - id - title - } - }`, - {}, - ); - expect(getResponse2.data.getPost).toBeNull(); -}); - -test('deletePost mutation', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Delete" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Delete'); - const deleteResponse = await GRAPHQL_CLIENT.query( - `mutation { - deletePost(input: { id: "${createResponse.data.createPost.id}" }) { - id - title - } - }`, - {}, - ); - expect(deleteResponse.data.deletePost.title).toEqual('Test Delete'); - const getResponse = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - } - }`, - {}, - ); - expect(getResponse.data.getPost).toBeNull(); -}); - -test('getPost query', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Get" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeTruthy(); - expect(createResponse.data.createPost.title).toEqual('Test Get'); - const getResponse = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - } - }`, - {}, - ); - expect(getResponse.data.getPost.title).toEqual('Test Get'); -}); - -test('listPosts query', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test List" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test List'); - const listResponse = await GRAPHQL_CLIENT.query( - `query { - listPosts { - items { - id - title - } - } - }`, - {}, - ); - expect(listResponse.data.listPosts.items).toBeDefined(); - const items = listResponse.data.listPosts.items; - expect(items.length).toBeGreaterThan(0); -}); - -test('listPosts query with filter', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test List with filter" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test List with filter'); - const listWithFilterResponse = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { - title: { - contains: "List with filter" - } - }) { - items { - id - title - } - } - }`, - {}, - ); - expect(listWithFilterResponse.data.listPosts.items).toBeDefined(); - const items = listWithFilterResponse.data.listPosts.items; - expect(items.length).toEqual(1); - expect(items[0].title).toEqual('Test List with filter'); -}); - -test('enum filters List', async () => { - await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Appears in New Hope", appearsIn: [NEWHOPE], episode: NEWHOPE }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Appears in Jedi", appearsIn: [JEDI], episode: JEDI }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Appears in Empire", appearsIn: [EMPIRE], episode: EMPIRE }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - - await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Appears in Empire & JEDI", appearsIn: [EMPIRE, JEDI] }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - - // filter list of enums - const appearsInWithFilterResponseJedi = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { appearsIn: {eq: [JEDI]}}) { - items { - title - id - } - } - } - `, - {}, - ); - expect(appearsInWithFilterResponseJedi.data.listPosts.items).toBeDefined(); - const items = appearsInWithFilterResponseJedi.data.listPosts.items; - expect(items.length).toEqual(1); - expect(items[0].title).toEqual('Appears in Jedi'); - - const appearsInWithFilterResponseNonJedi = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { appearsIn: {ne: [JEDI]}}) { - items { - title - id - } - } - } - `, - {}, - ); - expect(appearsInWithFilterResponseNonJedi.data.listPosts.items).toBeDefined(); - const appearsInNonJediItems = appearsInWithFilterResponseNonJedi.data.listPosts.items; - expect(appearsInNonJediItems.length).toEqual(3); - appearsInNonJediItems.forEach((item) => { - expect(['Appears in Empire & JEDI', 'Appears in New Hope', 'Appears in Empire'].includes(item.title)).toBeTruthy(); - }); - - const appearsInContainingJedi = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { appearsIn: {contains: JEDI }}) { - items { - title - id - } - } - } - `, - {}, - ); - expect(appearsInContainingJedi.data.listPosts.items).toBeDefined(); - const appearsInWithJediItems = appearsInContainingJedi.data.listPosts.items; - expect(appearsInWithJediItems.length).toEqual(2); - appearsInWithJediItems.forEach((item) => { - expect(['Appears in Empire & JEDI', 'Appears in Jedi'].includes(item.title)).toBeTruthy(); - }); - - const appearsInNotContainingJedi = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { appearsIn: {notContains: JEDI }}) { - items { - title - id - } - } - } - `, - {}, - ); - expect(appearsInNotContainingJedi.data.listPosts.items).toBeDefined(); - const appearsInWithNonJediItems = appearsInNotContainingJedi.data.listPosts.items; - expect(appearsInWithNonJediItems.length).toEqual(2); - appearsInWithNonJediItems.forEach((item) => { - expect(['Appears in New Hope', 'Appears in Empire'].includes(item.title)).toBeTruthy(); - }); - - // enum filter - const jediEpisode = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { episode: {eq: JEDI }}) { - items { - title - id - } - } - } - `, - {}, - ); - expect(jediEpisode.data.listPosts.items).toBeDefined(); - const jediEpisodeItems = jediEpisode.data.listPosts.items; - expect(jediEpisodeItems.length).toEqual(1); - expect(jediEpisodeItems[0].title).toEqual('Appears in Jedi'); - - const nonJediEpisode = await GRAPHQL_CLIENT.query( - `query { - listPosts(filter: { episode: {ne: JEDI }}) { - items { - title - id - } - } - } - `, - {}, - ); - expect(nonJediEpisode.data.listPosts.items).toBeDefined(); - const nonJediEpisodeItems = nonJediEpisode.data.listPosts.items; - expect(nonJediEpisodeItems.length).toEqual(3); - nonJediEpisodeItems.forEach((item) => { - expect(['Appears in New Hope', 'Appears in Empire', 'Appears in Empire & JEDI'].includes(item.title)).toBeTruthy(); - }); -}); - -test('next token', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - first: createPost(input: { title: "Test create for next token one" }) { - id - title - createdAt - updatedAt - } - second: createPost(input: { title: "Test create for next token two" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.first.id).toBeDefined(); - expect(createResponse.data.first.title).toEqual('Test create for next token one'); - - expect(createResponse.data.second.id).toBeDefined(); - expect(createResponse.data.second.title).toEqual('Test create for next token two'); - - const listResponse = await GRAPHQL_CLIENT.query( - /* GraphQL */ ` - query { - listPosts(limit: 1) { - items { - id - title - } - nextToken - } - } - `, - {}, - ); - expect(listResponse.data.listPosts.items).toBeDefined(); - const items = listResponse.data.listPosts.items; - expect(items.length).toEqual(1); - expect(listResponse.data.listPosts.nextToken).toBeDefined(); - expect(listResponse.data.listPosts.nextToken).not.toBeNull(); - - const listResponsePage2 = await GRAPHQL_CLIENT.query( - /* GraphQL */ `query { - listPosts(limit: 1, nextToken:"${listResponse.data.listPosts.nextToken}") { - items { - id - title - } - nextToken - } - }`, - {}, - ); - expect(listResponsePage2.data.listPosts.items).toBeDefined(); - const items2 = listResponsePage2.data.listPosts.items; - expect(items2.length).toBeGreaterThan(0); -}); - -test('createPost mutation with non-model types', async () => { - const response = await GRAPHQL_CLIENT.query( - `mutation CreatePost($input: CreatePostInput!) { - createPost(input: $input) { - id - title - createdAt - updatedAt - metadata { - tags { - published - metadata { - tags { - published - } - } - } - } - appearsIn - } - }`, - { - input: { - title: 'Check that metadata exists', - metadata: { - tags: { - published: true, - metadata: { - tags: { - published: false, - }, - }, - }, - }, - appearsIn: ['NEWHOPE'], - }, - }, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Check that metadata exists'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.metadata).toBeDefined(); - expect(response.data.createPost.metadata.tags.published).toEqual(true); - expect(response.data.createPost.metadata.tags.metadata.tags.published).toEqual(false); - expect(response.data.createPost.appearsIn).toEqual(['NEWHOPE']); -}); - -test('updatePost mutation with non-model types', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Update" }) { - id - title - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Update'); - const updateResponse = await GRAPHQL_CLIENT.query( - `mutation UpdatePost($input: UpdatePostInput!) { - updatePost(input: $input) { - id - title - createdAt - updatedAt - metadata { - tags { - published - metadata { - tags { - published - } - } - } - } - appearsIn - } - }`, - { - input: { - id: createResponse.data.createPost.id, - title: 'Add some metadata', - metadata: { - tags: { - published: true, - metadata: { - tags: { - published: false, - }, - }, - }, - }, - appearsIn: ['NEWHOPE', 'EMPIRE'], - }, - }, - ); - expect(updateResponse.data.updatePost.title).toEqual('Add some metadata'); - expect(updateResponse.data.updatePost.metadata).toBeDefined(); - expect(updateResponse.data.updatePost.metadata.tags.published).toEqual(true); - expect(updateResponse.data.updatePost.metadata.tags.metadata.tags.published).toEqual(false); - expect(updateResponse.data.updatePost.appearsIn).toEqual(['NEWHOPE', 'EMPIRE']); -}); - -describe('Timestamp configuration', () => { - test('createdAt is present in the schema', async () => { - const response = await GRAPHQL_CLIENT.query( - /* GraphQL */ ` - mutation CreateComment { - createComment(input: { title: "GraphQL transformer rocks" }) { - id - title - createdOn - updatedOn - } - } - `, - {}, - ); - expect(response.data.createComment.id).toBeDefined(); - expect(response.data.createComment.title).toEqual('GraphQL transformer rocks'); - expect(response.data.createComment.updatedOn).toBeNull(); - expect(response.data.createComment.createdOn).toBeDefined(); - }); -}); diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/FunctionTransformerTests.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/FunctionTransformerTests.e2e.test.ts deleted file mode 100644 index 09f9a6b481..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/FunctionTransformerTests.e2e.test.ts +++ /dev/null @@ -1,258 +0,0 @@ -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { FunctionTransformer } from 'graphql-function-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as moment } from 'moment'; -import { default as S3 } from 'aws-sdk/clients/s3'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { GraphQLClient } from '../GraphQLClient'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { S3Client } from '../S3Client'; -import { LambdaHelper } from '../LambdaHelper'; -import { IAMHelper } from '../IAMHelper'; -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `FunctionTransformerTests-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `appsync-function-transformer-test-bucket-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/function_transformer_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; -const ECHO_FUNCTION_NAME = `long-prefix-e2e-test-functions-echo-dev-${BUILD_TIMESTAMP}`; -const HELLO_FUNCTION_NAME = `long-prefix-e2e-test-functions-hello-${BUILD_TIMESTAMP}`; -const LAMBDA_EXECUTION_ROLE_NAME = `amplify_e2e_tests_lambda_basic_${BUILD_TIMESTAMP}`; -const LAMBDA_EXECUTION_POLICY_NAME = `amplify_e2e_tests_lambda_basic_access_${BUILD_TIMESTAMP}`; -let LAMBDA_EXECUTION_POLICY_ARN = ''; - -let GRAPHQL_CLIENT = undefined; - -const LAMBDA_HELPER = new LambdaHelper(); -const IAM_HELPER = new IAMHelper(); - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -beforeAll(async () => { - const validSchema = ` - type Query { - echo(msg: String!): Context @function(name: "${ECHO_FUNCTION_NAME}") - e_cho(msg: String!): Context @function(name: "${ECHO_FUNCTION_NAME}") - echoEnv(msg: String!): Context @function(name: "long-prefix-e2e-test-functions-echo-\${env}-${BUILD_TIMESTAMP}") - duplicate(msg: String!): Context @function(name: "long-prefix-e2e-test-functions-echo-dev-${BUILD_TIMESTAMP}") - pipeline(msg: String!): String - @function(name: "${ECHO_FUNCTION_NAME}") - @function(name: "${HELLO_FUNCTION_NAME}") - pipelineReverse(msg: String!): Context - @function(name: "${HELLO_FUNCTION_NAME}") - @function(name: "${ECHO_FUNCTION_NAME}") - } - type Context { - arguments: Arguments - typeName: String - fieldName: String - } - type Arguments { - msg: String! - } - `; - try { - await awsS3Client.createBucket({ Bucket: BUCKET_NAME }).promise(); - } catch (e) { - console.warn(`Could not create bucket: ${e}`); - expect(true).toEqual(false); - } - try { - const role = await IAM_HELPER.createLambdaExecutionRole(LAMBDA_EXECUTION_ROLE_NAME); - await wait(5000); - const policy = await IAM_HELPER.createLambdaExecutionPolicy(LAMBDA_EXECUTION_POLICY_NAME); - await wait(5000); - LAMBDA_EXECUTION_POLICY_ARN = policy.Policy.Arn; - await IAM_HELPER.attachPolicy(policy.Policy.Arn, role.Role.RoleName); - await wait(10000); - await LAMBDA_HELPER.createFunction(ECHO_FUNCTION_NAME, role.Role.Arn, 'echoFunction'); - await LAMBDA_HELPER.createFunction(HELLO_FUNCTION_NAME, role.Role.Arn, 'hello'); - } catch (e) { - console.warn(`Could not setup function: ${e}`); - expect(true).toEqual(false); - } - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new FunctionTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { CreateAPIKey: '1', env: 'dev' }, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - // Arbitrary wait to make sure everything is ready. - await cf.wait(5, () => Promise.resolve()); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - const endpoint = getApiEndpoint(finishedStack.Outputs); - const apiKey = getApiKey(finishedStack.Outputs); - expect(apiKey).toBeDefined(); - expect(endpoint).toBeDefined(); - GRAPHQL_CLIENT = new GraphQLClient(endpoint, { 'x-api-key': apiKey }); -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf); - - try { - await LAMBDA_HELPER.deleteFunction(ECHO_FUNCTION_NAME); - } catch (e) { - console.warn(`Error during function cleanup: ${e}`); - } - try { - await LAMBDA_HELPER.deleteFunction(HELLO_FUNCTION_NAME); - } catch (e) { - console.warn(`Error during function cleanup: ${e}`); - } - try { - await IAM_HELPER.detachPolicy(LAMBDA_EXECUTION_POLICY_ARN, LAMBDA_EXECUTION_ROLE_NAME); - } catch (e) { - console.warn(`Error during policy dissociation: ${e}`); - } - try { - await IAM_HELPER.deleteRole(LAMBDA_EXECUTION_ROLE_NAME); - } catch (e) { - console.warn(`Error during role cleanup: ${e}`); - } - try { - await IAM_HELPER.deletePolicy(LAMBDA_EXECUTION_POLICY_ARN); - } catch (e) { - console.warn(`Error during policy cleanup: ${e}`); - } -}); - -/** - * Test queries below - */ -test('simple echo function', async () => { - const response = await GRAPHQL_CLIENT.query( - `query { - echo(msg: "Hello") { - arguments { - msg - } - typeName - fieldName - } - }`, - {}, - ); - expect(response.data.echo.arguments.msg).toEqual('Hello'); - expect(response.data.echo.typeName).toEqual('Query'); - expect(response.data.echo.fieldName).toEqual('echo'); -}); - -test('simple echoEnv function', async () => { - const response = await GRAPHQL_CLIENT.query( - `query { - echoEnv(msg: "Hello") { - arguments { - msg - } - typeName - fieldName - } - }`, - {}, - ); - expect(response.data.echoEnv.arguments.msg).toEqual('Hello'); - expect(response.data.echoEnv.typeName).toEqual('Query'); - expect(response.data.echoEnv.fieldName).toEqual('echoEnv'); -}); - -test('simple duplicate function', async () => { - const response = await GRAPHQL_CLIENT.query( - `query { - duplicate(msg: "Hello") { - arguments { - msg - } - typeName - fieldName - } - }`, - {}, - ); - expect(response.data.duplicate.arguments.msg).toEqual('Hello'); - expect(response.data.duplicate.typeName).toEqual('Query'); - expect(response.data.duplicate.fieldName).toEqual('duplicate'); -}); - -test('pipeline of @function(s)', async () => { - const response = await GRAPHQL_CLIENT.query( - `query { - pipeline(msg: "IGNORED") - }`, - {}, - ); - expect(response.data.pipeline).toEqual('Hello, world!'); -}); - -test('pipelineReverse of @function(s)', async () => { - const response = await GRAPHQL_CLIENT.query( - `query { - pipelineReverse(msg: "Hello") { - arguments { - msg - } - typeName - fieldName - } - }`, - {}, - ); - expect(response.data.pipelineReverse.arguments.msg).toEqual('Hello'); - expect(response.data.pipelineReverse.typeName).toEqual('Query'); - expect(response.data.pipelineReverse.fieldName).toEqual('pipelineReverse'); -}); - -function wait(ms: number) { - return new Promise((resolve, reject) => { - setTimeout(() => resolve(), ms); - }); -} diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/HttpTransformer.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/HttpTransformer.e2e.test.ts deleted file mode 100644 index b5e02d9685..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/HttpTransformer.e2e.test.ts +++ /dev/null @@ -1,468 +0,0 @@ -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as moment } from 'moment'; -import { default as S3 } from 'aws-sdk/clients/s3'; -import { HttpTransformer } from '../../../graphql-http-transformer'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { GraphQLClient } from '../GraphQLClient'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { S3Client } from '../S3Client'; -import { deployJsonServer, destroyJsonServer } from '../cdkUtils'; -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const customS3Client = new S3Client(region); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `HttpTransformerTest-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `appsync-http-transformer-test-bucket-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/http_transformer_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; - -let GRAPHQL_CLIENT = undefined; - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -beforeAll(async () => { - const { apiUrl } = deployJsonServer(); - - const validSchema = ` - type Comment @model { - id: ID! - title: String - simpleGet: CompObj @http(method: GET, url: "${apiUrl}posts/1") - simpleGet2: CompObj @http(url: "${apiUrl}posts/2") - complexPost( - id: Int, - title: String!, - body: String, - userId: Int - ): CompObj @http(method: POST, url: "${apiUrl}posts") - complexPut( - id: Int!, - title: String, - body: String, - userId: Int - ): CompObj @http(method: PUT, url: "${apiUrl}posts/:id") - deleter: String @http(method: DELETE, url: "${apiUrl}posts/4") - complexGet( - data: String!, - userId: Int!, - _limit: Int - ): [CompObj] @http(url: "${apiUrl}:data") - complexGet2( - dataType: String!, - postId: Int!, - secondType: String!, - id: Int - ): [PostComment] @http(url: "${apiUrl}:dataType/:postId/:secondType") - } - type CompObj { - userId: Int - id: Int - title: String - body: String - } - type PostComment { - postId: Int - id: Int - name: String - email: String - body: String - } - `; - - try { - await customS3Client.createBucket(BUCKET_NAME); - } catch (e) { - console.error(`Failed to create bucket: ${e}`); - expect(true).toEqual(false); - } - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }, - }), - new HttpTransformer(), - ], - }); - - const out = transformer.transform(validSchema); - - try { - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { CreateAPIKey: '1' }, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - - // Arbitrary wait to make sure everything is ready. - await cf.wait(5, () => Promise.resolve()); - - expect(finishedStack).toBeDefined(); - - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - const endpoint = getApiEndpoint(finishedStack.Outputs); - const apiKey = getApiKey(finishedStack.Outputs); - - expect(apiKey).toBeDefined(); - expect(endpoint).toBeDefined(); - - GRAPHQL_CLIENT = new GraphQLClient(endpoint, { 'x-api-key': apiKey }); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - destroyJsonServer(); - - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf); -}); - -/** - * Test queries below - */ -test('HTTP GET request', async () => { - try { - const response = await GRAPHQL_CLIENT.query( - `mutation { - createComment(input: { title: "Hello, World!" }) { - id - title - simpleGet { - id - title - body - } - } - }`, - {}, - ); - - const post1Title = 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit'; - - expect(response.errors).toBeUndefined(); - expect(response.data.createComment.id).toBeDefined(); - expect(response.data.createComment.title).toEqual('Hello, World!'); - expect(response.data.createComment.simpleGet).toBeDefined(); - expect(response.data.createComment.simpleGet.title).toEqual(post1Title); - } catch (e) { - console.error(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('HTTP GET request 2', async () => { - try { - const response = await GRAPHQL_CLIENT.query( - `mutation { - createComment(input: { title: "Hello, World!" }) { - id - title - simpleGet2 { - id - title - body - } - } - }`, - {}, - ); - - const post2Title = 'qui est esse'; - - expect(response.errors).toBeUndefined(); - expect(response.data.createComment.id).toBeDefined(); - expect(response.data.createComment.title).toEqual('Hello, World!'); - expect(response.data.createComment.simpleGet2).toBeDefined(); - expect(response.data.createComment.simpleGet2.title).toEqual(post2Title); - } catch (e) { - console.error(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('HTTP POST request', async () => { - try { - const response = await GRAPHQL_CLIENT.query( - `mutation { - createComment(input: { title: "Hello, World!" }) { - id - title - complexPost( - body: { - title: "foo", - body: "bar", - userId: 2 - } - ) { - id - title - body - userId - } - } - }`, - {}, - ); - - expect(response.errors).toBeUndefined(); - expect(response.data.createComment.id).toBeDefined(); - expect(response.data.createComment.title).toEqual('Hello, World!'); - expect(response.data.createComment.complexPost).toBeDefined(); - expect(response.data.createComment.complexPost.title).toEqual('foo'); - expect(response.data.createComment.complexPost.userId).toEqual(2); - } catch (e) { - console.error(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('HTTP PUT request', async () => { - try { - const response = await GRAPHQL_CLIENT.query( - `mutation { - createComment(input: { title: "Hello, World!" }) { - id - title - complexPut( - params: { - id: "3" - }, - body: { - title: "foo", - body: "bar", - userId: 2 - } - ) { - id - title - body - userId - } - } - }`, - {}, - ); - - expect(response.errors).toBeUndefined(); - expect(response.data.createComment.id).toBeDefined(); - expect(response.data.createComment.title).toEqual('Hello, World!'); - expect(response.data.createComment.complexPut).toBeDefined(); - expect(response.data.createComment.complexPut.title).toEqual('foo'); - expect(response.data.createComment.complexPut.userId).toEqual(2); - } catch (e) { - console.error(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('HTTP DELETE request', async () => { - try { - const response = await GRAPHQL_CLIENT.query( - `mutation { - createComment(input: { title: "Hello, World!" }) { - id - title - deleter - } - }`, - {}, - ); - - expect(response.errors).toBeUndefined(); - expect(response.data.createComment.id).toBeDefined(); - expect(response.data.createComment.title).toEqual('Hello, World!'); - expect(response.data.createComment.deleter).not.toBeNull(); - } catch (e) { - console.error(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('GET with URL param and query values', async () => { - try { - const response = await GRAPHQL_CLIENT.query( - `mutation { - createComment(input: { title: "Hello, World!" }) { - id - title - complexGet( - params: { - data: "posts" - }, - query: { - userId: 1, - _limit: 7 - } - ) { - id - title - body - } - } - }`, - {}, - ); - - expect(response.errors).toBeUndefined(); - expect(response.data.createComment.id).toBeDefined(); - expect(response.data.createComment.title).toEqual('Hello, World!'); - expect(response.data.createComment.complexGet).toBeDefined(); - expect(response.data.createComment.complexGet.length).toEqual(7); - } catch (e) { - console.error(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('GET with multiple URL params and query values', async () => { - try { - const response = await GRAPHQL_CLIENT.query( - `mutation { - createComment(input: { title: "Hello, World!" }) { - id - title - complexGet2( - params: { - dataType: "posts", - postId: "1", - secondType: "comments" - }, - query: { - id: 2 - } - ) { - id - name - email - } - } - }`, - {}, - ); - - expect(response.errors).toBeUndefined(); - expect(response.data.createComment.id).toBeDefined(); - expect(response.data.createComment.title).toEqual('Hello, World!'); - expect(response.data.createComment.complexGet2).toBeDefined(); - expect(response.data.createComment.complexGet2[0].email).toEqual('Jayne_Kuhic@sydney.com'); - } catch (e) { - console.error(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('that GET errors when missing a required Query input object', async () => { - try { - const response = await GRAPHQL_CLIENT.query( - `mutation { - createComment(input: { title: "Hello, World!" }) { - id - title - complexGet( - params: { - data: "posts", - } - ) { - id - title - body - } - } - }`, - {}, - ); - - expect(response.data).toBeNull(); - expect(response.errors).toBeDefined(); - expect(response.errors).toHaveLength(1); - expect(response.errors[0].message).toEqual( - "Validation error of type MissingFieldArgument: Missing field argument query @ 'createComment/complexGet'", - ); - } catch (e) { - console.error(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('that POST errors when missing a non-null arg in query/body', async () => { - try { - const response = await GRAPHQL_CLIENT.query( - `mutation { - createComment(input: { title: "Hello, World!" }) { - id - title - complexPost( - body: { - id: 1, - body: "bar" - } - ) { - id - title - body - } - } - }`, - {}, - ); - - expect(response.data.createComment.complexPost).toBeNull(); - expect(response.errors).toBeDefined(); - expect(response.errors).toHaveLength(1); - expect(response.errors[0].message).toEqual( - 'An argument you marked as Non-Null is not present in the query nor the body of your request.', - ); - } catch (e) { - console.error(e); - // fail - expect(e).toBeUndefined(); - } -}); diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/IndexTransformer.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/IndexTransformer.e2e.test.ts deleted file mode 100644 index 6db900afa1..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/IndexTransformer.e2e.test.ts +++ /dev/null @@ -1,1078 +0,0 @@ -import { IndexTransformer, PrimaryKeyTransformer } from '@aws-amplify/graphql-index-transformer'; -import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; -import { testTransform } from '@aws-amplify/graphql-transformer-test-utils'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { Output } from 'aws-sdk/clients/cloudformation'; -// eslint-disable-next-line import/no-named-default -import { default as moment } from 'moment'; -// eslint-disable-next-line import/no-named-default -import { default as S3 } from 'aws-sdk/clients/s3'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { GraphQLClient } from '../GraphQLClient'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { S3Client } from '../S3Client'; -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); -// eslint-disable-next-line spellcheck/spell-checker -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `IndexTransformerTests-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `appsync-index-transformer-test-bucket-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/index_transformer_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; - -let GRAPHQL_CLIENT; - -const outputValueSelector = (key: string) => (outputs: Output[]) => { - // eslint-disable-next-line react/destructuring-assignment - const output = outputs.find((o) => o.OutputKey === key); - return output ? output.OutputValue : null; -}; - -beforeAll(async () => { - const validSchema = /* GraphQL */ ` - type Order @model { - customerEmail: String! @primaryKey(sortKeyFields: ["createdAt"]) - createdAt: AWSDateTime! - orderId: ID! - } - type Customer @model { - email: String! @primaryKey - addressList: [String] - username: String - } - type Item @model { - orderId: ID! @primaryKey(sortKeyFields: ["status", "createdAt"]) - status: Status! @index(name: "ByStatus", sortKeyFields: ["createdAt"], queryField: "itemsByStatus") - createdAt: AWSDateTime! @index(name: "ByCreatedAt", sortKeyFields: ["status"], queryField: "itemsByCreatedAt") - name: String! - } - enum Status { - DELIVERED - IN_TRANSIT - PENDING - UNKNOWN - } - type ShippingUpdate @model { - id: ID! - orderId: ID @index(name: "ByOrderItemStatus", sortKeyFields: ["itemId", "status"], queryField: "shippingUpdates") - itemId: ID - status: Status - name: String - } - type ModelWithIdAndCreatedAtAsKey @model { - id: ID! @primaryKey(sortKeyFields: ["createdAt"]) - createdAt: AWSDateTime! - name: String! - } - type KeylessBlog @model { - id: ID! - name: String! - createdAt: AWSDateTime! - } - type KeyedBlog @model { - id: ID! @primaryKey - name: String! - createdAt: AWSDateTime - } - type KeyedSortedBlog @model { - id: ID! @primaryKey(sortKeyFields: ["createdAt"]) - name: String! - createdAt: AWSDateTime! - } - type TestModel @model { - id: ID! - parentId: ID @index(name: "parent-id-index") - } - type Todo @model { - id: ID! - name: String! - description: String - begin: AWSDateTime - end: AWSDateTime - createdAt: AWSDateTime! - isTeamTodo: Int! - isPublic: Int! - @index( - name: "byIsPublicByByCreatedAtByIsTeamTodoByBeginByEnd" - sortKeyFields: ["createdAt", "isTeamTodo", "begin", "end"] - queryField: "TodoByIsPublicByByCreatedAtByIsTeamTodoByBeginByEnd" - ) - } - `; - - try { - await awsS3Client.createBucket({ Bucket: BUCKET_NAME }).promise(); - } catch (e) { - console.warn(`Could not create bucket: ${e}`); - } - - const out = testTransform({ - schema: validSchema, - transformers: [new ModelTransformer(), new PrimaryKeyTransformer(), new IndexTransformer()], - transformParameters: { - sandboxModeEnabled: true, - }, - }); - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - {}, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - // Arbitrary wait to make sure everything is ready. - await cf.wait(5, () => Promise.resolve()); - // eslint-disable-next-line jest/no-standalone-expect - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - const endpoint = getApiEndpoint(finishedStack.Outputs); - const apiKey = getApiKey(finishedStack.Outputs); - - // eslint-disable-next-line jest/no-standalone-expect - expect(apiKey).toBeDefined(); - // eslint-disable-next-line jest/no-standalone-expect - expect(endpoint).toBeDefined(); - GRAPHQL_CLIENT = new GraphQLClient(endpoint, { 'x-api-key': apiKey }); -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf); -}); - -/** - * Test queries below - */ -test('next token with key', async () => { - const status = 'PENDING'; - const createdAt = '2019-06-06T00:01:01.000Z'; - // createItems - await createItem('order1', status, 'item1', '2019-01-06T00:01:01.000Z'); - await createItem('order2', status, 'item2', '2019-02-06T00:01:01.000Z'); - await createItem('order3', status, 'item3', '2019-03-06T00:01:01.000Z'); - await createItem('order4', status, 'item4', '2019-06-06T00:01:01.000Z'); - - // query itemsByCreatedAt with limit of 2 - const items = await itemsByStatus(status, { beginsWith: '2019' }, 2); - expect(items.data).toBeDefined(); - const itemsNextToken = items.data.itemsByStatus.nextToken; - expect(itemsNextToken).toBeDefined(); - // get first two values - expect(items.data.itemsByStatus.items).toHaveLength(2); - expect(items.data.itemsByStatus.items).toEqual( - expect.arrayContaining([ - expect.objectContaining({ orderId: 'order1', name: 'item1' }), - expect.objectContaining({ orderId: 'order2', name: 'item2' }), - ]), - ); - // use next token to get other values - const items2 = await itemsByStatus(status, { beginsWith: '2019' }, 2, itemsNextToken); - expect(items2.data).toBeDefined(); - // get last two values - expect(items2.data.itemsByStatus.items).toHaveLength(2); - expect(items2.data.itemsByStatus.items).toEqual( - expect.arrayContaining([ - expect.objectContaining({ orderId: 'order3', name: 'item3' }), - expect.objectContaining({ orderId: 'order4', name: 'item4' }), - ]), - ); - // deleteItems - await deleteItem('order1', status, createdAt); - await deleteItem('order2', status, createdAt); - await deleteItem('order3', status, createdAt); - await deleteItem('order4', status, createdAt); -}); - -test('index should handle begin and end keywords', async () => { - const todo = await createTodo('Test', 'Example', '2022-01-01T12:00:00.000Z', '2022-01-03T12:00:00.000Z', 0, 0); - expect(todo.data.createTodo.name).toEqual('Test'); - expect(todo.data.createTodo.description).toEqual('Example'); -}); - -test('getX with a two part primary key.', async () => { - const order1 = await createOrder('test@gmail.com', '1'); - expect(order1.data.createOrder.createdAt).toBeDefined(); - const getOrder1 = await getOrder('test@gmail.com', order1.data.createOrder.createdAt); - expect(getOrder1.data.getOrder.customerEmail).toEqual('test@gmail.com'); - expect(getOrder1.data.getOrder.orderId).toEqual('1'); - expect(getOrder1.data.getOrder.createdAt).toEqual(order1.data.createOrder.createdAt); -}); - -test('updateX with a two part primary key.', async () => { - const order2 = await createOrder('test3@gmail.com', '2'); - let getOrder2 = await getOrder('test3@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder.orderId).toEqual('2'); - const updateOrder2 = await updateOrder('test3@gmail.com', order2.data.createOrder.createdAt, '3'); - expect(updateOrder2.data.updateOrder.orderId).toEqual('3'); - getOrder2 = await getOrder('test3@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder.orderId).toEqual('3'); -}); - -test('deleteX with a two part primary key.', async () => { - const order2 = await createOrder('test2@gmail.com', '2'); - let getOrder2 = await getOrder('test2@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder.orderId).toEqual('2'); - const delOrder2 = await deleteOrder('test2@gmail.com', order2.data.createOrder.createdAt); - expect(delOrder2.data.deleteOrder.orderId).toEqual('2'); - getOrder2 = await getOrder('test2@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder).toBeNull(); -}); - -test('getX with a three part primary key', async () => { - const item1 = await createItem('1', 'PENDING', 'item1'); - const getItem1 = await getItem('1', 'PENDING', item1.data.createItem.createdAt); - expect(getItem1.data.getItem.orderId).toEqual('1'); - expect(getItem1.data.getItem.status).toEqual('PENDING'); -}); - -test('updateX with a three part primary key.', async () => { - const item2 = await createItem('2', 'PENDING', 'item2'); - let getItem2 = await getItem('2', 'PENDING', item2.data.createItem.createdAt); - expect(getItem2.data.getItem.orderId).toEqual('2'); - const updateItem2 = await updateItem('2', 'PENDING', item2.data.createItem.createdAt, 'item2.1'); - expect(updateItem2.data.updateItem.name).toEqual('item2.1'); - getItem2 = await getItem('2', 'PENDING', item2.data.createItem.createdAt); - expect(getItem2.data.getItem.name).toEqual('item2.1'); -}); - -test('deleteX with a three part primary key.', async () => { - const item3 = await createItem('3', 'IN_TRANSIT', 'item3'); - let getItem3 = await getItem('3', 'IN_TRANSIT', item3.data.createItem.createdAt); - expect(getItem3.data.getItem.name).toEqual('item3'); - const delItem3 = await deleteItem('3', 'IN_TRANSIT', item3.data.createItem.createdAt); - expect(delItem3.data.deleteItem.name).toEqual('item3'); - getItem3 = await getItem('3', 'IN_TRANSIT', item3.data.createItem.createdAt); - expect(getItem3.data.getItem).toBeNull(); -}); - -test('listX with three part primary key.', async () => { - const hashKey = 'TEST_LIST_ID'; - await createItem(hashKey, 'IN_TRANSIT', 'list1', '2018-01-01T00:01:01.000Z'); - await createItem(hashKey, 'PENDING', 'list2', '2018-06-01T00:01:01.000Z'); - await createItem(hashKey, 'PENDING', 'item3', '2018-09-01T00:01:01.000Z'); - let items = await listItem(undefined); - expect(items.data.listItems.items.length).toBeGreaterThan(0); - items = await listItem(hashKey); - expect(items.data.listItems.items).toHaveLength(3); - items = await listItem(hashKey, { beginsWith: { status: 'PENDING' } }); - expect(items.data.listItems.items).toHaveLength(2); - items = await listItem(hashKey, { beginsWith: { status: 'IN_TRANSIT' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { beginsWith: { status: 'PENDING', createdAt: '2018-09' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { eq: { status: 'PENDING', createdAt: '2018-09-01T00:01:01.000Z' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { - between: [ - { status: 'PENDING', createdAt: '2018-08-01' }, - { status: 'PENDING', createdAt: '2018-10-01' }, - ], - }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { gt: { status: 'PENDING', createdAt: '2018-08-1' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { ge: { status: 'PENDING', createdAt: '2018-09-01T00:01:01.000Z' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { lt: { status: 'IN_TRANSIT', createdAt: '2018-01-02' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { le: { status: 'IN_TRANSIT', createdAt: '2018-01-01T00:01:01.000Z' } }); - expect(items.data.listItems.items).toHaveLength(1); - await deleteItem(hashKey, 'IN_TRANSIT', '2018-01-01T00:01:01.000Z'); - await deleteItem(hashKey, 'PENDING', '2018-06-01T00:01:01.000Z'); - await deleteItem(hashKey, 'PENDING', '2018-09-01T00:01:01.000Z'); -}); - -test('query with three part secondary key.', async () => { - const hashKey = 'UNKNOWN'; - await createItem('order1', 'UNKNOWN', 'list1', '2018-01-01T00:01:01.000Z'); - await createItem('order2', 'UNKNOWN', 'list2', '2018-06-01T00:01:01.000Z'); - await createItem('order3', 'UNKNOWN', 'item3', '2018-09-01T00:01:01.000Z'); - let items = await itemsByStatus(undefined); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - items = await itemsByStatus(hashKey); - expect(items.data.itemsByStatus.items).toHaveLength(3); - items = await itemsByStatus(hashKey, { beginsWith: '2018-09' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { eq: '2018-09-01T00:01:01.000Z' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { between: ['2018-08-01', '2018-10-01'] }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { gt: '2018-08-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { ge: '2018-09-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { lt: '2018-07-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(2); - items = await itemsByStatus(hashKey, { le: '2018-06-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(undefined, { le: '2018-09-01' }); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - await deleteItem('order1', hashKey, '2018-01-01T00:01:01.000Z'); - await deleteItem('order2', hashKey, '2018-06-01T00:01:01.000Z'); - await deleteItem('order3', hashKey, '2018-09-01T00:01:01.000Z'); -}); - -test('query with three part secondary key, where sort key is an enum.', async () => { - const hashKey = '2018-06-01T00:01:01.000Z'; - const sortKey = 'UNKNOWN'; - await createItem('order1', sortKey, 'list1', '2018-01-01T00:01:01.000Z'); - await createItem('order2', sortKey, 'list2', hashKey); - await createItem('order3', sortKey, 'item3', '2018-09-01T00:01:01.000Z'); - let items = await itemsByCreatedAt(undefined); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - items = await itemsByCreatedAt(hashKey); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { beginsWith: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { eq: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { between: [sortKey, sortKey] }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { gt: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(0); - items = await itemsByCreatedAt(hashKey, { ge: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { lt: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(0); - items = await itemsByCreatedAt(hashKey, { le: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(undefined, { le: sortKey }); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - await deleteItem('order1', sortKey, '2018-01-01T00:01:01.000Z'); - await deleteItem('order2', sortKey, hashKey); - await deleteItem('order3', sortKey, '2018-09-01T00:01:01.000Z'); -}); - -test('create/update mutation validation with three part secondary key.', async () => { - const createResponseMissingLastSortKey = await createShippingUpdate({ orderId: 'order1', itemId: 'item1', name: '42' }); - expect(createResponseMissingLastSortKey.data.createShippingUpdate).toBeNull(); - expect(createResponseMissingLastSortKey.errors).toHaveLength(1); - - const createResponseMissingFirstSortKey = await createShippingUpdate({ orderId: 'secondEntry', status: 'PENDING', name: '43?' }); - expect(createResponseMissingFirstSortKey.data.createShippingUpdate).toBeNull(); - expect(createResponseMissingFirstSortKey.errors).toHaveLength(1); - - await createShippingUpdate({ - orderId: 'order1', - itemId: 'item1', - status: 'PENDING', - name: 'name1', - }); - const items = await getShippingUpdates('order1'); - expect(items.data.shippingUpdates.items).toHaveLength(1); - const item = items.data.shippingUpdates.items[0]; - expect(item.name).toEqual('name1'); - - const itemsWithFilter = await getShippingUpdatesWithNameFilter('order1', 'name1'); - expect(itemsWithFilter.data.shippingUpdates.items).toHaveLength(1); - const itemWithFilter = itemsWithFilter.data.shippingUpdates.items[0]; - expect(itemWithFilter.name).toEqual('name1'); - - const itemsWithUnknownFilter = await getShippingUpdatesWithNameFilter('order1', 'unknownName'); - expect(itemsWithUnknownFilter.data.shippingUpdates.items).toHaveLength(0); - - const updateResponseMissingLastSortKey = await updateShippingUpdate({ - id: item.id, - orderId: 'order1', - itemId: 'item1', - name: 'name2', - }); - expect(updateResponseMissingLastSortKey.data.updateShippingUpdate).toBeNull(); - expect(updateResponseMissingLastSortKey.errors).toHaveLength(1); - const updateResponseMissingFirstSortKey = await updateShippingUpdate({ - id: item.id, - orderId: 'order1', - status: 'PENDING', - name: 'name3', - }); - expect(updateResponseMissingFirstSortKey.data.updateShippingUpdate).toBeNull(); - expect(updateResponseMissingFirstSortKey.errors).toHaveLength(1); - const updateResponseMissingAllSortKeys = await updateShippingUpdate({ id: item.id, orderId: 'order1', name: 'testing' }); - expect(updateResponseMissingAllSortKeys.data.updateShippingUpdate.name).toEqual('testing'); - const updateResponseMissingNoKeys = await updateShippingUpdate({ - id: item.id, - orderId: 'order1', - itemId: 'item1', - status: 'PENDING', - name: 'testing2', - }); - expect(updateResponseMissingNoKeys.data.updateShippingUpdate.name).toEqual('testing2'); -}); - -test('Customer Create with list member and secondary key', async () => { - await createCustomer('customer1@email.com', ['thing1', 'thing2'], 'customerUser1'); - const getCustomer1 = await getCustomer('customer1@email.com'); - expect(getCustomer1.data.getCustomer.addressList).toEqual(['thing1', 'thing2']); -}); - -test('cannot overwrite customer record with custom primary key', async () => { - await createCustomer('customer42@email.com', ['thing1', 'thing2'], 'customerUser42'); - const response = await createCustomer('customer42@email.com', ['thing2'], 'customerUser43'); - expect(response.errors).toBeDefined(); - expect(response.errors[0]).toEqual( - expect.objectContaining({ - errorType: 'DynamoDB:ConditionalCheckFailedException', - message: expect.stringContaining('The conditional request failed'), - }), - ); -}); - -test('Customer Mutation with list member', async () => { - await createCustomer('customer2@email.com', ['thing1', 'thing2'], 'customerUser2'); - await updateCustomer('customer2@email.com', ['thing3', 'thing4'], 'new_customerUser2'); - const getCustomer1 = await getCustomer('customer2@email.com'); - expect(getCustomer1.data.getCustomer.addressList).toEqual(['thing3', 'thing4']); -}); - -test('@primaryKey directive with customer sortDirection', async () => { - await createOrder('testOrder@email.com', '1', '2016-03-10T00:45:08+00:00'); - await createOrder('testOrder@email.com', '2', '2018-05-22T21:45:08+00:00'); - await createOrder('testOrder@email.com', '3', '2019-06-27T12:00:08+00:00'); - const newOrders = await listOrders('testOrder@email.com', { beginsWith: '201' }, 'DESC'); - const oldOrders = await listOrders('testOrder@email.com', { beginsWith: '201' }, 'ASC'); - expect(newOrders.data.listOrders.items[0].createdAt).toEqual('2019-06-27T12:00:08+00:00'); - expect(newOrders.data.listOrders.items[0].orderId).toEqual('3'); - expect(oldOrders.data.listOrders.items[0].createdAt).toEqual('2016-03-10T00:45:08+00:00'); - expect(oldOrders.data.listOrders.items[0].orderId).toEqual('1'); -}); - -// orderId: string, itemId: string, status: string, name?: string -// DELIVERED IN_TRANSIT PENDING UNKNOWN -// (orderId: string, itemId: string, sortDirection: string) -test('@index directive with sortDirection on GSI', async () => { - await createShippingUpdate({ - orderId: 'order99', - itemId: 'product1', - status: 'PENDING', - name: 'order1Name1', - }); - await createShippingUpdate({ - orderId: 'order99', - itemId: 'product2', - status: 'IN_TRANSIT', - name: 'order1Name2', - }); - await createShippingUpdate({ - orderId: 'order99', - itemId: 'product3', - status: 'DELIVERED', - name: 'order1Name3', - }); - await createShippingUpdate({ - orderId: 'order99', - itemId: 'product4', - status: 'DELIVERED', - name: 'order1Name4', - }); - const newShippingUpdates = await listGSIShippingUpdate('order99', { beginsWith: { itemId: 'product' } }, 'DESC'); - const oldShippingUpdates = await listGSIShippingUpdate('order99', { beginsWith: { itemId: 'product' } }, 'ASC'); - expect(oldShippingUpdates.data.shippingUpdates.items[0].status).toEqual('PENDING'); - expect(oldShippingUpdates.data.shippingUpdates.items[0].name).toEqual('order1Name1'); - expect(newShippingUpdates.data.shippingUpdates.items[0].status).toEqual('DELIVERED'); - expect(newShippingUpdates.data.shippingUpdates.items[0].name).toEqual('order1Name4'); -}); - -test('@primaryKey directive supports auto Id and createdAt fields in create mutation', async () => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateModelWithIdAndCreatedAtAsKey{ - createModelWithIdAndCreatedAtAsKey(input:{ name: "John Doe" }) { - id - createdAt - name - } - }`, - ); - expect(result.data.createModelWithIdAndCreatedAtAsKey.id).not.toBeNull(); - expect(result.data.createModelWithIdAndCreatedAtAsKey.createdAt).not.toBeNull(); - expect(result.data.createModelWithIdAndCreatedAtAsKey.name).toEqual('John Doe'); -}); - -test('sortDirection validation error for List on KeyedBlog type', async () => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateKeyedBlog($input: CreateKeyedBlogInput!) { - createKeyedBlog(input: $input) { - id - name - } - }`, - { - input: { - id: 'B1', - name: 'Blog #1', - }, - }, - ); - - expect(result.data).not.toBeNull(); - expect(result.errors).toBeUndefined(); - - const listResult = await GRAPHQL_CLIENT.query( - `query ListKeyedBlogs { - listKeyedBlogs(sortDirection: ASC) { - items { - id - name - } - } - }`, - ); - - expect(listResult.data).not.toBeNull(); - expect(listResult.data.listKeyedBlogs).toBeNull(); - expect(listResult.errors).toBeDefined(); - expect(listResult.errors.length).toEqual(1); - expect(listResult.errors[0].message).toEqual('sortDirection is not supported for List operations without a Sort key defined.'); -}); - -test('sortDirection validation error for List on KeyedSortedBlog type', async () => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateKeyedSortedBlog($input: CreateKeyedSortedBlogInput!) { - createKeyedSortedBlog(input: $input) { - id - name - } - }`, - { - input: { - id: 'B1', - name: 'Blog #1', - }, - }, - ); - - expect(result.data).not.toBeNull(); - expect(result.errors).toBeUndefined(); - - const listWithErrorResult = await GRAPHQL_CLIENT.query( - `query ListKeyedSortedBlogs { - listKeyedSortedBlogs(sortDirection: ASC) { - items { - id - name - } - } - }`, - ); - - expect(listWithErrorResult.data).not.toBeNull(); - expect(listWithErrorResult.data.listKeyedSortedBlogs).toBeNull(); - expect(listWithErrorResult.errors).toBeDefined(); - expect(listWithErrorResult.errors.length).toEqual(1); - expect(listWithErrorResult.errors[0].message).toEqual("When providing argument 'sortDirection' you must also provide argument 'id'."); - - const listResult = await GRAPHQL_CLIENT.query( - `query ListKeyedSortedBlogs { - listKeyedSortedBlogs(id: "B1", sortDirection: ASC) { - items { - id - name - } - } - }`, - ); - - expect(listResult.data).not.toBeNull(); - expect(listResult.data.listKeyedSortedBlogs).not.toBeNull(); - expect(listResult.errors).toBeUndefined(); -}); - -test('create mutation with index field set to null', async () => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateTestModel($input: CreateTestModelInput!) { - createTestModel(input: $input) { - id - parentId - } - }`, - { - input: { - id: '1', - parentId: null, - }, - }, - ); - - expect(result.data).not.toBeNull(); - expect(result.errors).toBeUndefined(); - expect(result.data.createTestModel).not.toBeNull(); - expect(result.data.createTestModel.parentId).toBeNull(); -}); - -const createCustomer = async (email: string, addressList: string[], username: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateCustomer($input: CreateCustomerInput!) { - createCustomer(input: $input) { - email - addressList - username - } - }`, - { - input: { email, addressList, username }, - }, - ); - return result; -}; - -const updateCustomer = async (email: string, addressList: string[], username: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateCustomer($input: UpdateCustomerInput!) { - updateCustomer(input: $input) { - email - addressList - username - } - }`, - { - input: { email, addressList, username }, - }, - ); - return result; -}; - -const getCustomer = async (email: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query GetCustomer($email: String!) { - getCustomer(email: $email) { - email - addressList - username - } - }`, - { - email, - }, - ); - return result; -}; - -const createOrder = async (customerEmail: string, orderId: string, createdAt: string = new Date().toISOString()): Promise => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateOrder($input: CreateOrderInput!) { - createOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, orderId, createdAt }, - }, - ); - return result; -}; - -const updateOrder = async (customerEmail: string, createdAt: string, orderId: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateOrder($input: UpdateOrderInput!) { - updateOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, orderId, createdAt }, - }, - ); - return result; -}; - -const deleteOrder = async (customerEmail: string, createdAt: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `mutation DeleteOrder($input: DeleteOrderInput!) { - deleteOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, createdAt }, - }, - ); - return result; -}; - -const getOrder = async (customerEmail: string, createdAt: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query GetOrder($customerEmail: String!, $createdAt: AWSDateTime!) { - getOrder(customerEmail: $customerEmail, createdAt: $createdAt) { - customerEmail - orderId - createdAt - } - }`, - { customerEmail, createdAt }, - ); - return result; -}; - -interface ModelStringKeyConditionInput { - eq?: string; - gt?: string; - ge?: string; - lt?: string; - le?: string; - between?: string[]; - beginsWith?: string; -} - -const listOrders = async (customerEmail: string, createdAt: ModelStringKeyConditionInput, sortDirection: string): Promise => { - const input = { customerEmail, createdAt, sortDirection }; - const result = await GRAPHQL_CLIENT.query( - `query ListOrders( - $customerEmail: String, $createdAt: ModelStringKeyConditionInput, $sortDirection: ModelSortDirection) { - listOrders(customerEmail: $customerEmail, createdAt: $createdAt, sortDirection: $sortDirection) { - items { - orderId - customerEmail - createdAt - } - } - }`, - input, - ); - return result; -}; - -const createItem = async (orderId: string, status: string, name: string, createdAt: string = new Date().toISOString()): Promise => { - const input = { - status, - orderId, - name, - createdAt, - }; - const result = await GRAPHQL_CLIENT.query( - `mutation CreateItem($input: CreateItemInput!) { - createItem(input: $input) { - orderId - status - createdAt - name - } - }`, - { - input, - }, - ); - return result; -}; - -const updateItem = async (orderId: string, status: string, createdAt: string, name: string): Promise => { - const input = { - status, - orderId, - createdAt, - name, - }; - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateItem($input: UpdateItemInput!) { - updateItem(input: $input) { - orderId - status - createdAt - name - } - }`, - { - input, - }, - ); - return result; -}; - -const deleteItem = async (orderId: string, status: string, createdAt: string): Promise => { - const input = { orderId, status, createdAt }; - const result = await GRAPHQL_CLIENT.query( - `mutation DeleteItem($input: DeleteItemInput!) { - deleteItem(input: $input) { - orderId - status - createdAt - name - } - }`, - { - input, - }, - ); - return result; -}; - -const getItem = async (orderId: string, status: string, createdAt: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query GetItem($orderId: ID!, $status: Status!, $createdAt: AWSDateTime!) { - getItem(orderId: $orderId, status: $status, createdAt: $createdAt) { - orderId - status - createdAt - name - } - }`, - { orderId, status, createdAt }, - ); - return result; -}; - -interface StringKeyConditionInput { - eq?: string; - gt?: string; - ge?: string; - lt?: string; - le?: string; - between?: string[]; - beginsWith?: string; -} - -interface ItemCompositeKeyConditionInput { - eq?: ItemCompositeKeyInput; - gt?: ItemCompositeKeyInput; - ge?: ItemCompositeKeyInput; - lt?: ItemCompositeKeyInput; - le?: ItemCompositeKeyInput; - between?: ItemCompositeKeyInput[]; - beginsWith?: ItemCompositeKeyInput; -} -interface ItemCompositeKeyInput { - status?: string; - createdAt?: string; -} -const listItem = async ( - orderId?: string, - statusCreatedAt?: ItemCompositeKeyConditionInput, - limit?: number, - nextToken?: string, -): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query ListItems( - $orderId: ID, $statusCreatedAt: ModelItemPrimaryCompositeKeyConditionInput, $limit: Int, $nextToken: String) { - listItems(orderId: $orderId, statusCreatedAt: $statusCreatedAt, limit: $limit, nextToken: $nextToken) { - items { - orderId - status - createdAt - name - } - nextToken - } - }`, - { - orderId, - statusCreatedAt, - limit, - nextToken, - }, - ); - return result; -}; - -const itemsByStatus = async (status: string, createdAt?: StringKeyConditionInput, limit?: number, nextToken?: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query ListByStatus( - $status: Status!, $createdAt: ModelStringKeyConditionInput, $limit: Int, $nextToken: String) { - itemsByStatus(status: $status, createdAt: $createdAt, limit: $limit, nextToken: $nextToken) { - items { - orderId - status - createdAt - name - } - nextToken - } - }`, - { - status, - createdAt, - limit, - nextToken, - }, - ); - return result; -}; - -const itemsByCreatedAt = async (createdAt: string, status?: StringKeyConditionInput, limit?: number, nextToken?: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query ListByCreatedAt( - $createdAt: AWSDateTime!, $status: ModelStringKeyConditionInput, $limit: Int, $nextToken: String) { - itemsByCreatedAt(createdAt: $createdAt, status: $status, limit: $limit, nextToken: $nextToken) { - items { - orderId - status - createdAt - name - } - nextToken - } - }`, - { - createdAt, - status, - limit, - nextToken, - }, - ); - return result; -}; - -interface CreateShippingInput { - id?: string; - orderId?: string; - status?: string; - itemId?: string; - name?: string; -} - -const createShippingUpdate = async (input: CreateShippingInput): Promise => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateShippingUpdate($input: CreateShippingUpdateInput!) { - createShippingUpdate(input: $input) { - orderId - status - itemId - name - id - } - }`, - { - input, - }, - ); - return result; -}; - -const listGSIShippingUpdate = async (orderId: string, itemId: any, sortDirection: string): Promise => { - const input = { orderId, itemId, sortDirection }; - const result = await GRAPHQL_CLIENT.query( - `query queryGSI( - $orderId: ID!, - $itemIdStatus: ModelShippingUpdateByOrderItemStatusCompositeKeyConditionInput, - $sortDirection: ModelSortDirection) { - shippingUpdates( - orderId: $orderId, - itemIdStatus: $itemIdStatus, - sortDirection: $sortDirection) { - items { - orderId - name - status - } - } - }`, - input, - ); - return result; -}; - -interface UpdateShippingInput { - id: string; - orderId?: string; - status?: string; - itemId?: string; - name?: string; -} -const updateShippingUpdate = async (input: UpdateShippingInput): Promise => { - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateShippingUpdate($input: UpdateShippingUpdateInput!) { - updateShippingUpdate(input: $input) { - orderId - status - itemId - name - id - } - }`, - { - input, - }, - ); - return result; -}; - -const getShippingUpdates = async (orderId: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query GetShippingUpdates($orderId: ID!) { - shippingUpdates(orderId: $orderId) { - items { - id - orderId - status - itemId - name - } - nextToken - } - }`, - { orderId }, - ); - return result; -}; - -const getShippingUpdatesWithNameFilter = async (orderId: string, name: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query GetShippingUpdates($orderId: ID!, $name: String) { - shippingUpdates(orderId: $orderId, filter: { name: { eq: $name }}) { - items { - id - orderId - status - itemId - name - } - nextToken - } - }`, - { orderId, name }, - ); - return result; -}; - -const createTodo = async ( - name: string, - description: string, - begin: string, - end: string, - isTeamTodo: number, - isPublic: number, -): Promise => { - const input = { - name, - description, - begin, - end, - isTeamTodo, - isPublic, - }; - const result = await GRAPHQL_CLIENT.query( - `mutation CreateTodo($input: CreateTodoInput!) { - createTodo(input: $input) { - id - name - description - begin - end - isTeamTodo - isPublic - } - }`, - { - input, - }, - ); - return result; -}; diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/IndexWithAutoQueryField.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/IndexWithAutoQueryField.e2e.test.ts deleted file mode 100644 index ed5d2a60f1..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/IndexWithAutoQueryField.e2e.test.ts +++ /dev/null @@ -1,1094 +0,0 @@ -import { IndexTransformer, PrimaryKeyTransformer } from '@aws-amplify/graphql-index-transformer'; -import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; -import { testTransform } from '@aws-amplify/graphql-transformer-test-utils'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { Output } from 'aws-sdk/clients/cloudformation'; -// eslint-disable-next-line import/no-named-default -import { default as moment } from 'moment'; -// eslint-disable-next-line import/no-named-default -import { default as S3 } from 'aws-sdk/clients/s3'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { GraphQLClient } from '../GraphQLClient'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { S3Client } from '../S3Client'; -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); -// eslint-disable-next-line spellcheck/spell-checker -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `IndexWithAutoQueryField-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `appsync-index-with-auto-query-test-bucket-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/index_with_auth_query_field_transformer_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; - -let GRAPHQL_CLIENT; - -const outputValueSelector = (key: string) => (outputs: Output[]) => { - // eslint-disable-next-line react/destructuring-assignment - const output = outputs.find((o) => o.OutputKey === key); - return output ? output.OutputValue : null; -}; - -beforeAll(async () => { - const validSchema = /* GraphQL */ ` - type Order @model { - customerEmail: String! @primaryKey(sortKeyFields: ["createdAt"]) - createdAt: AWSDateTime! - orderId: ID! - } - type Customer @model { - email: String! @primaryKey - addressList: [String] - username: String - } - type Item @model { - orderId: ID! @primaryKey(sortKeyFields: ["status", "createdAt"]) - status: Status! @index(name: "ByStatus", sortKeyFields: ["createdAt"], queryField: "itemsByStatus") - createdAt: AWSDateTime! @index(name: "ByCreatedAt", sortKeyFields: ["status"], queryField: "itemsByCreatedAt") - name: String! - } - enum Status { - DELIVERED - IN_TRANSIT - PENDING - UNKNOWN - } - type ShippingUpdate @model { - id: ID! - orderId: ID @index(name: "ByOrderItemStatus", sortKeyFields: ["itemId", "status"], queryField: "shippingUpdates") - itemId: ID - status: Status - name: String - } - type ModelWithIdAndCreatedAtAsKey @model { - id: ID! @primaryKey(sortKeyFields: ["createdAt"]) - createdAt: AWSDateTime! - name: String! - } - type KeylessBlog @model { - id: ID! - name: String! - createdAt: AWSDateTime! - } - type KeyedBlog @model { - id: ID! @primaryKey - name: String! - createdAt: AWSDateTime - } - type KeyedSortedBlog @model { - id: ID! @primaryKey(sortKeyFields: ["createdAt"]) - name: String! - createdAt: AWSDateTime! - } - type TestModel @model { - id: ID! - parentId: ID @index(name: "parent-id-index") - } - type Employee @model { - id: ID! - managerId: ID! @index @index(sortKeyFields: ["level"]) - level: Int! - } - `; - - try { - await awsS3Client.createBucket({ Bucket: BUCKET_NAME }).promise(); - } catch (e) { - console.warn(`Could not create bucket: ${e}`); - } - - const out = testTransform({ - schema: validSchema, - transformers: [new ModelTransformer(), new PrimaryKeyTransformer(), new IndexTransformer()], - transformParameters: { - sandboxModeEnabled: true, - }, - }); - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - {}, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - // Arbitrary wait to make sure everything is ready. - await cf.wait(5, () => Promise.resolve()); - // eslint-disable-next-line jest/no-standalone-expect - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - const endpoint = getApiEndpoint(finishedStack.Outputs); - const apiKey = getApiKey(finishedStack.Outputs); - - // eslint-disable-next-line jest/no-standalone-expect - expect(apiKey).toBeDefined(); - // eslint-disable-next-line jest/no-standalone-expect - expect(endpoint).toBeDefined(); - GRAPHQL_CLIENT = new GraphQLClient(endpoint, { 'x-api-key': apiKey }); -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf); -}); - -/** - * Test queries below - */ -test('next token with key', async () => { - const status = 'PENDING'; - const createdAt = '2019-06-06T00:01:01.000Z'; - // createItems - await createItem('order1', status, 'item1', '2019-01-06T00:01:01.000Z'); - await createItem('order2', status, 'item2', '2019-02-06T00:01:01.000Z'); - await createItem('order3', status, 'item3', '2019-03-06T00:01:01.000Z'); - await createItem('order4', status, 'item4', '2019-06-06T00:01:01.000Z'); - - // query itemsByCreatedAt with limit of 2 - const items = await itemsByStatus(status, { beginsWith: '2019' }, 2); - expect(items.data).toBeDefined(); - const itemsNextToken = items.data.itemsByStatus.nextToken; - expect(itemsNextToken).toBeDefined(); - // get first two values - expect(items.data.itemsByStatus.items).toHaveLength(2); - expect(items.data.itemsByStatus.items).toEqual( - expect.arrayContaining([ - expect.objectContaining({ orderId: 'order1', name: 'item1' }), - expect.objectContaining({ orderId: 'order2', name: 'item2' }), - ]), - ); - // use next token to get other values - const items2 = await itemsByStatus(status, { beginsWith: '2019' }, 2, itemsNextToken); - expect(items2.data).toBeDefined(); - // get last two values - expect(items2.data.itemsByStatus.items).toHaveLength(2); - expect(items2.data.itemsByStatus.items).toEqual( - expect.arrayContaining([ - expect.objectContaining({ orderId: 'order3', name: 'item3' }), - expect.objectContaining({ orderId: 'order4', name: 'item4' }), - ]), - ); - // deleteItems - await deleteItem('order1', status, createdAt); - await deleteItem('order2', status, createdAt); - await deleteItem('order3', status, createdAt); - await deleteItem('order4', status, createdAt); -}); - -test('getX with a two part primary key.', async () => { - const order1 = await createOrder('test@gmail.com', '1'); - expect(order1.data.createOrder.createdAt).toBeDefined(); - const getOrder1 = await getOrder('test@gmail.com', order1.data.createOrder.createdAt); - expect(getOrder1.data.getOrder.customerEmail).toEqual('test@gmail.com'); - expect(getOrder1.data.getOrder.orderId).toEqual('1'); - expect(getOrder1.data.getOrder.createdAt).toEqual(order1.data.createOrder.createdAt); -}); - -test('updateX with a two part primary key.', async () => { - const order2 = await createOrder('test3@gmail.com', '2'); - let getOrder2 = await getOrder('test3@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder.orderId).toEqual('2'); - const updateOrder2 = await updateOrder('test3@gmail.com', order2.data.createOrder.createdAt, '3'); - expect(updateOrder2.data.updateOrder.orderId).toEqual('3'); - getOrder2 = await getOrder('test3@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder.orderId).toEqual('3'); -}); - -test('deleteX with a two part primary key.', async () => { - const order2 = await createOrder('test2@gmail.com', '2'); - let getOrder2 = await getOrder('test2@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder.orderId).toEqual('2'); - const delOrder2 = await deleteOrder('test2@gmail.com', order2.data.createOrder.createdAt); - expect(delOrder2.data.deleteOrder.orderId).toEqual('2'); - getOrder2 = await getOrder('test2@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder).toBeNull(); -}); - -test('getX with a three part primary key', async () => { - const item1 = await createItem('1', 'PENDING', 'item1'); - const getItem1 = await getItem('1', 'PENDING', item1.data.createItem.createdAt); - expect(getItem1.data.getItem.orderId).toEqual('1'); - expect(getItem1.data.getItem.status).toEqual('PENDING'); -}); - -test('updateX with a three part primary key.', async () => { - const item2 = await createItem('2', 'PENDING', 'item2'); - let getItem2 = await getItem('2', 'PENDING', item2.data.createItem.createdAt); - expect(getItem2.data.getItem.orderId).toEqual('2'); - const updateItem2 = await updateItem('2', 'PENDING', item2.data.createItem.createdAt, 'item2.1'); - expect(updateItem2.data.updateItem.name).toEqual('item2.1'); - getItem2 = await getItem('2', 'PENDING', item2.data.createItem.createdAt); - expect(getItem2.data.getItem.name).toEqual('item2.1'); -}); - -test('deleteX with a three part primary key.', async () => { - const item3 = await createItem('3', 'IN_TRANSIT', 'item3'); - let getItem3 = await getItem('3', 'IN_TRANSIT', item3.data.createItem.createdAt); - expect(getItem3.data.getItem.name).toEqual('item3'); - const delItem3 = await deleteItem('3', 'IN_TRANSIT', item3.data.createItem.createdAt); - expect(delItem3.data.deleteItem.name).toEqual('item3'); - getItem3 = await getItem('3', 'IN_TRANSIT', item3.data.createItem.createdAt); - expect(getItem3.data.getItem).toBeNull(); -}); - -test('listX with three part primary key.', async () => { - const hashKey = 'TEST_LIST_ID'; - await createItem(hashKey, 'IN_TRANSIT', 'list1', '2018-01-01T00:01:01.000Z'); - await createItem(hashKey, 'PENDING', 'list2', '2018-06-01T00:01:01.000Z'); - await createItem(hashKey, 'PENDING', 'item3', '2018-09-01T00:01:01.000Z'); - let items = await listItem(undefined); - expect(items.data.listItems.items.length).toBeGreaterThan(0); - items = await listItem(hashKey); - expect(items.data.listItems.items).toHaveLength(3); - items = await listItem(hashKey, { beginsWith: { status: 'PENDING' } }); - expect(items.data.listItems.items).toHaveLength(2); - items = await listItem(hashKey, { beginsWith: { status: 'IN_TRANSIT' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { beginsWith: { status: 'PENDING', createdAt: '2018-09' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { eq: { status: 'PENDING', createdAt: '2018-09-01T00:01:01.000Z' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { - between: [ - { status: 'PENDING', createdAt: '2018-08-01' }, - { status: 'PENDING', createdAt: '2018-10-01' }, - ], - }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { gt: { status: 'PENDING', createdAt: '2018-08-1' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { ge: { status: 'PENDING', createdAt: '2018-09-01T00:01:01.000Z' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { lt: { status: 'IN_TRANSIT', createdAt: '2018-01-02' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { le: { status: 'IN_TRANSIT', createdAt: '2018-01-01T00:01:01.000Z' } }); - expect(items.data.listItems.items).toHaveLength(1); - await deleteItem(hashKey, 'IN_TRANSIT', '2018-01-01T00:01:01.000Z'); - await deleteItem(hashKey, 'PENDING', '2018-06-01T00:01:01.000Z'); - await deleteItem(hashKey, 'PENDING', '2018-09-01T00:01:01.000Z'); -}); - -test('query with three part secondary key.', async () => { - const hashKey = 'UNKNOWN'; - await createItem('order1', 'UNKNOWN', 'list1', '2018-01-01T00:01:01.000Z'); - await createItem('order2', 'UNKNOWN', 'list2', '2018-06-01T00:01:01.000Z'); - await createItem('order3', 'UNKNOWN', 'item3', '2018-09-01T00:01:01.000Z'); - let items = await itemsByStatus(undefined); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - items = await itemsByStatus(hashKey); - expect(items.data.itemsByStatus.items).toHaveLength(3); - items = await itemsByStatus(hashKey, { beginsWith: '2018-09' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { eq: '2018-09-01T00:01:01.000Z' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { between: ['2018-08-01', '2018-10-01'] }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { gt: '2018-08-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { ge: '2018-09-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { lt: '2018-07-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(2); - items = await itemsByStatus(hashKey, { le: '2018-06-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(undefined, { le: '2018-09-01' }); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - await deleteItem('order1', hashKey, '2018-01-01T00:01:01.000Z'); - await deleteItem('order2', hashKey, '2018-06-01T00:01:01.000Z'); - await deleteItem('order3', hashKey, '2018-09-01T00:01:01.000Z'); -}); - -test('query with three part secondary key, where sort key is an enum.', async () => { - const hashKey = '2018-06-01T00:01:01.000Z'; - const sortKey = 'UNKNOWN'; - await createItem('order1', sortKey, 'list1', '2018-01-01T00:01:01.000Z'); - await createItem('order2', sortKey, 'list2', hashKey); - await createItem('order3', sortKey, 'item3', '2018-09-01T00:01:01.000Z'); - let items = await itemsByCreatedAt(undefined); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - items = await itemsByCreatedAt(hashKey); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { beginsWith: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { eq: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { between: [sortKey, sortKey] }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { gt: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(0); - items = await itemsByCreatedAt(hashKey, { ge: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { lt: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(0); - items = await itemsByCreatedAt(hashKey, { le: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(undefined, { le: sortKey }); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - await deleteItem('order1', sortKey, '2018-01-01T00:01:01.000Z'); - await deleteItem('order2', sortKey, hashKey); - await deleteItem('order3', sortKey, '2018-09-01T00:01:01.000Z'); -}); - -test('create/update mutation validation with three part secondary key.', async () => { - const createResponseMissingLastSortKey = await createShippingUpdate({ orderId: 'order1', itemId: 'item1', name: '42' }); - expect(createResponseMissingLastSortKey.data.createShippingUpdate).toBeNull(); - expect(createResponseMissingLastSortKey.errors).toHaveLength(1); - - const createResponseMissingFirstSortKey = await createShippingUpdate({ orderId: 'secondEntry', status: 'PENDING', name: '43?' }); - expect(createResponseMissingFirstSortKey.data.createShippingUpdate).toBeNull(); - expect(createResponseMissingFirstSortKey.errors).toHaveLength(1); - - await createShippingUpdate({ - orderId: 'order1', - itemId: 'item1', - status: 'PENDING', - name: 'name1', - }); - const items = await getShippingUpdates('order1'); - expect(items.data.shippingUpdates.items).toHaveLength(1); - const item = items.data.shippingUpdates.items[0]; - expect(item.name).toEqual('name1'); - - const itemsWithFilter = await getShippingUpdatesWithNameFilter('order1', 'name1'); - expect(itemsWithFilter.data.shippingUpdates.items).toHaveLength(1); - const itemWithFilter = itemsWithFilter.data.shippingUpdates.items[0]; - expect(itemWithFilter.name).toEqual('name1'); - - const itemsWithUnknownFilter = await getShippingUpdatesWithNameFilter('order1', 'unknownName'); - expect(itemsWithUnknownFilter.data.shippingUpdates.items).toHaveLength(0); - - const updateResponseMissingLastSortKey = await updateShippingUpdate({ - id: item.id, - orderId: 'order1', - itemId: 'item1', - name: 'name2', - }); - expect(updateResponseMissingLastSortKey.data.updateShippingUpdate).toBeNull(); - expect(updateResponseMissingLastSortKey.errors).toHaveLength(1); - const updateResponseMissingFirstSortKey = await updateShippingUpdate({ - id: item.id, - orderId: 'order1', - status: 'PENDING', - name: 'name3', - }); - expect(updateResponseMissingFirstSortKey.data.updateShippingUpdate).toBeNull(); - expect(updateResponseMissingFirstSortKey.errors).toHaveLength(1); - const updateResponseMissingAllSortKeys = await updateShippingUpdate({ id: item.id, orderId: 'order1', name: 'testing' }); - expect(updateResponseMissingAllSortKeys.data.updateShippingUpdate.name).toEqual('testing'); - const updateResponseMissingNoKeys = await updateShippingUpdate({ - id: item.id, - orderId: 'order1', - itemId: 'item1', - status: 'PENDING', - name: 'testing2', - }); - expect(updateResponseMissingNoKeys.data.updateShippingUpdate.name).toEqual('testing2'); -}); - -test('Customer Create with list member and secondary key', async () => { - await createCustomer('customer1@email.com', ['thing1', 'thing2'], 'customerUser1'); - const getCustomer1 = await getCustomer('customer1@email.com'); - expect(getCustomer1.data.getCustomer.addressList).toEqual(['thing1', 'thing2']); -}); - -test('cannot overwrite customer record with custom primary key', async () => { - await createCustomer('customer42@email.com', ['thing1', 'thing2'], 'customerUser42'); - const response = await createCustomer('customer42@email.com', ['thing2'], 'customerUser43'); - expect(response.errors).toBeDefined(); - expect(response.errors[0]).toEqual( - expect.objectContaining({ - errorType: 'DynamoDB:ConditionalCheckFailedException', - message: expect.stringContaining('The conditional request failed'), - }), - ); -}); - -test('Customer Mutation with list member', async () => { - await createCustomer('customer2@email.com', ['thing1', 'thing2'], 'customerUser2'); - await updateCustomer('customer2@email.com', ['thing3', 'thing4'], 'new_customerUser2'); - const getCustomer1 = await getCustomer('customer2@email.com'); - expect(getCustomer1.data.getCustomer.addressList).toEqual(['thing3', 'thing4']); -}); - -test('@primaryKey directive with customer sortDirection', async () => { - await createOrder('testOrder@email.com', '1', '2016-03-10T00:45:08+00:00'); - await createOrder('testOrder@email.com', '2', '2018-05-22T21:45:08+00:00'); - await createOrder('testOrder@email.com', '3', '2019-06-27T12:00:08+00:00'); - const newOrders = await listOrders('testOrder@email.com', { beginsWith: '201' }, 'DESC'); - const oldOrders = await listOrders('testOrder@email.com', { beginsWith: '201' }, 'ASC'); - expect(newOrders.data.listOrders.items[0].createdAt).toEqual('2019-06-27T12:00:08+00:00'); - expect(newOrders.data.listOrders.items[0].orderId).toEqual('3'); - expect(oldOrders.data.listOrders.items[0].createdAt).toEqual('2016-03-10T00:45:08+00:00'); - expect(oldOrders.data.listOrders.items[0].orderId).toEqual('1'); -}); - -// orderId: string, itemId: string, status: string, name?: string -// DELIVERED IN_TRANSIT PENDING UNKNOWN -// (orderId: string, itemId: string, sortDirection: string) -test('@index directive with sortDirection on GSI', async () => { - await createShippingUpdate({ - orderId: 'order99', - itemId: 'product1', - status: 'PENDING', - name: 'order1Name1', - }); - await createShippingUpdate({ - orderId: 'order99', - itemId: 'product2', - status: 'IN_TRANSIT', - name: 'order1Name2', - }); - await createShippingUpdate({ - orderId: 'order99', - itemId: 'product3', - status: 'DELIVERED', - name: 'order1Name3', - }); - await createShippingUpdate({ - orderId: 'order99', - itemId: 'product4', - status: 'DELIVERED', - name: 'order1Name4', - }); - const newShippingUpdates = await listGSIShippingUpdate('order99', { beginsWith: { itemId: 'product' } }, 'DESC'); - const oldShippingUpdates = await listGSIShippingUpdate('order99', { beginsWith: { itemId: 'product' } }, 'ASC'); - expect(oldShippingUpdates.data.shippingUpdates.items[0].status).toEqual('PENDING'); - expect(oldShippingUpdates.data.shippingUpdates.items[0].name).toEqual('order1Name1'); - expect(newShippingUpdates.data.shippingUpdates.items[0].status).toEqual('DELIVERED'); - expect(newShippingUpdates.data.shippingUpdates.items[0].name).toEqual('order1Name4'); -}); - -test('@primaryKey directive supports auto Id and createdAt fields in create mutation', async () => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateModelWithIdAndCreatedAtAsKey{ - createModelWithIdAndCreatedAtAsKey(input:{ name: "John Doe" }) { - id - createdAt - name - } - }`, - ); - expect(result.data.createModelWithIdAndCreatedAtAsKey.id).not.toBeNull(); - expect(result.data.createModelWithIdAndCreatedAtAsKey.createdAt).not.toBeNull(); - expect(result.data.createModelWithIdAndCreatedAtAsKey.name).toEqual('John Doe'); -}); - -test('sortDirection validation error for List on KeyedBlog type', async () => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateKeyedBlog($input: CreateKeyedBlogInput!) { - createKeyedBlog(input: $input) { - id - name - } - }`, - { - input: { - id: 'B1', - name: 'Blog #1', - }, - }, - ); - - expect(result.data).not.toBeNull(); - expect(result.errors).toBeUndefined(); - - const listResult = await GRAPHQL_CLIENT.query( - `query ListKeyedBlogs { - listKeyedBlogs(sortDirection: ASC) { - items { - id - name - } - } - }`, - ); - - expect(listResult.data).not.toBeNull(); - expect(listResult.data.listKeyedBlogs).toBeNull(); - expect(listResult.errors).toBeDefined(); - expect(listResult.errors.length).toEqual(1); - expect(listResult.errors[0].message).toEqual('sortDirection is not supported for List operations without a Sort key defined.'); -}); - -test('sortDirection validation error for List on KeyedSortedBlog type', async () => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateKeyedSortedBlog($input: CreateKeyedSortedBlogInput!) { - createKeyedSortedBlog(input: $input) { - id - name - } - }`, - { - input: { - id: 'B1', - name: 'Blog #1', - }, - }, - ); - - expect(result.data).not.toBeNull(); - expect(result.errors).toBeUndefined(); - - const listWithErrorResult = await GRAPHQL_CLIENT.query( - `query ListKeyedSortedBlogs { - listKeyedSortedBlogs(sortDirection: ASC) { - items { - id - name - } - } - }`, - ); - - expect(listWithErrorResult.data).not.toBeNull(); - expect(listWithErrorResult.data.listKeyedSortedBlogs).toBeNull(); - expect(listWithErrorResult.errors).toBeDefined(); - expect(listWithErrorResult.errors.length).toEqual(1); - expect(listWithErrorResult.errors[0].message).toEqual("When providing argument 'sortDirection' you must also provide argument 'id'."); - - const listResult = await GRAPHQL_CLIENT.query( - `query ListKeyedSortedBlogs { - listKeyedSortedBlogs(id: "B1", sortDirection: ASC) { - items { - id - name - } - } - }`, - ); - - expect(listResult.data).not.toBeNull(); - expect(listResult.data.listKeyedSortedBlogs).not.toBeNull(); - expect(listResult.errors).toBeUndefined(); -}); - -test('create mutation with index field set to null', async () => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateTestModel($input: CreateTestModelInput!) { - createTestModel(input: $input) { - id - parentId - } - }`, - { - input: { - id: '1', - parentId: null, - }, - }, - ); - - expect(result.data).not.toBeNull(); - expect(result.errors).toBeUndefined(); - expect(result.data.createTestModel).not.toBeNull(); - expect(result.data.createTestModel.parentId).toBeNull(); -}); - -test('can query by auto-generated queryField', async () => { - const manager1Id = '1'; - const manager2Id = '2'; - await createEmployee(manager1Id, 4); - await createEmployee(manager1Id, 5); - await createEmployee(manager2Id, 1); - await createEmployee(manager2Id, 1); - await createEmployee(manager2Id, 2); - const manager1Employees = await queryEmployeesByManagerId(manager1Id); - expect(manager1Employees.data.employeesByManagerId.items.length).toEqual(2); - const manager1L4Employees = await queryEmployeesByManagerIdAndLevel(manager1Id, 4); - expect(manager1L4Employees.data.employeesByManagerIdAndLevel.items.length).toEqual(1); - const manager2Employees = await queryEmployeesByManagerId(manager2Id); - expect(manager2Employees.data.employeesByManagerId.items.length).toEqual(3); - const manager2L1Employees = await queryEmployeesByManagerIdAndLevel(manager2Id, 1); - expect(manager2L1Employees.data.employeesByManagerIdAndLevel.items.length).toEqual(2); -}); - -const createCustomer = async (email: string, addressList: string[], username: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateCustomer($input: CreateCustomerInput!) { - createCustomer(input: $input) { - email - addressList - username - } - }`, - { - input: { email, addressList, username }, - }, - ); - return result; -}; - -const updateCustomer = async (email: string, addressList: string[], username: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateCustomer($input: UpdateCustomerInput!) { - updateCustomer(input: $input) { - email - addressList - username - } - }`, - { - input: { email, addressList, username }, - }, - ); - return result; -}; - -const getCustomer = async (email: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query GetCustomer($email: String!) { - getCustomer(email: $email) { - email - addressList - username - } - }`, - { - email, - }, - ); - return result; -}; - -const createOrder = async (customerEmail: string, orderId: string, createdAt: string = new Date().toISOString()): Promise => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateOrder($input: CreateOrderInput!) { - createOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, orderId, createdAt }, - }, - ); - return result; -}; - -const updateOrder = async (customerEmail: string, createdAt: string, orderId: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateOrder($input: UpdateOrderInput!) { - updateOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, orderId, createdAt }, - }, - ); - return result; -}; - -const deleteOrder = async (customerEmail: string, createdAt: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `mutation DeleteOrder($input: DeleteOrderInput!) { - deleteOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, createdAt }, - }, - ); - return result; -}; - -const getOrder = async (customerEmail: string, createdAt: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query GetOrder($customerEmail: String!, $createdAt: AWSDateTime!) { - getOrder(customerEmail: $customerEmail, createdAt: $createdAt) { - customerEmail - orderId - createdAt - } - }`, - { customerEmail, createdAt }, - ); - return result; -}; - -interface ModelStringKeyConditionInput { - eq?: string; - gt?: string; - ge?: string; - lt?: string; - le?: string; - between?: string[]; - beginsWith?: string; -} - -const listOrders = async (customerEmail: string, createdAt: ModelStringKeyConditionInput, sortDirection: string): Promise => { - const input = { customerEmail, createdAt, sortDirection }; - const result = await GRAPHQL_CLIENT.query( - `query ListOrders( - $customerEmail: String, $createdAt: ModelStringKeyConditionInput, $sortDirection: ModelSortDirection) { - listOrders(customerEmail: $customerEmail, createdAt: $createdAt, sortDirection: $sortDirection) { - items { - orderId - customerEmail - createdAt - } - } - }`, - input, - ); - return result; -}; - -const createItem = async (orderId: string, status: string, name: string, createdAt: string = new Date().toISOString()): Promise => { - const input = { - status, - orderId, - name, - createdAt, - }; - const result = await GRAPHQL_CLIENT.query( - `mutation CreateItem($input: CreateItemInput!) { - createItem(input: $input) { - orderId - status - createdAt - name - } - }`, - { - input, - }, - ); - return result; -}; - -const updateItem = async (orderId: string, status: string, createdAt: string, name: string): Promise => { - const input = { - status, - orderId, - createdAt, - name, - }; - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateItem($input: UpdateItemInput!) { - updateItem(input: $input) { - orderId - status - createdAt - name - } - }`, - { - input, - }, - ); - return result; -}; - -const deleteItem = async (orderId: string, status: string, createdAt: string): Promise => { - const input = { orderId, status, createdAt }; - const result = await GRAPHQL_CLIENT.query( - `mutation DeleteItem($input: DeleteItemInput!) { - deleteItem(input: $input) { - orderId - status - createdAt - name - } - }`, - { - input, - }, - ); - return result; -}; - -const getItem = async (orderId: string, status: string, createdAt: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query GetItem($orderId: ID!, $status: Status!, $createdAt: AWSDateTime!) { - getItem(orderId: $orderId, status: $status, createdAt: $createdAt) { - orderId - status - createdAt - name - } - }`, - { orderId, status, createdAt }, - ); - return result; -}; - -interface StringKeyConditionInput { - eq?: string; - gt?: string; - ge?: string; - lt?: string; - le?: string; - between?: string[]; - beginsWith?: string; -} - -interface ItemCompositeKeyConditionInput { - eq?: ItemCompositeKeyInput; - gt?: ItemCompositeKeyInput; - ge?: ItemCompositeKeyInput; - lt?: ItemCompositeKeyInput; - le?: ItemCompositeKeyInput; - between?: ItemCompositeKeyInput[]; - beginsWith?: ItemCompositeKeyInput; -} -interface ItemCompositeKeyInput { - status?: string; - createdAt?: string; -} -const listItem = async ( - orderId?: string, - statusCreatedAt?: ItemCompositeKeyConditionInput, - limit?: number, - nextToken?: string, -): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query ListItems( - $orderId: ID, $statusCreatedAt: ModelItemPrimaryCompositeKeyConditionInput, $limit: Int, $nextToken: String) { - listItems(orderId: $orderId, statusCreatedAt: $statusCreatedAt, limit: $limit, nextToken: $nextToken) { - items { - orderId - status - createdAt - name - } - nextToken - } - }`, - { - orderId, - statusCreatedAt, - limit, - nextToken, - }, - ); - return result; -}; - -const itemsByStatus = async (status: string, createdAt?: StringKeyConditionInput, limit?: number, nextToken?: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query ListByStatus( - $status: Status!, $createdAt: ModelStringKeyConditionInput, $limit: Int, $nextToken: String) { - itemsByStatus(status: $status, createdAt: $createdAt, limit: $limit, nextToken: $nextToken) { - items { - orderId - status - createdAt - name - } - nextToken - } - }`, - { - status, - createdAt, - limit, - nextToken, - }, - ); - return result; -}; - -const itemsByCreatedAt = async (createdAt: string, status?: StringKeyConditionInput, limit?: number, nextToken?: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query ListByCreatedAt( - $createdAt: AWSDateTime!, $status: ModelStringKeyConditionInput, $limit: Int, $nextToken: String) { - itemsByCreatedAt(createdAt: $createdAt, status: $status, limit: $limit, nextToken: $nextToken) { - items { - orderId - status - createdAt - name - } - nextToken - } - }`, - { - createdAt, - status, - limit, - nextToken, - }, - ); - return result; -}; - -interface CreateShippingInput { - id?: string; - orderId?: string; - status?: string; - itemId?: string; - name?: string; -} - -const createShippingUpdate = async (input: CreateShippingInput): Promise => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateShippingUpdate($input: CreateShippingUpdateInput!) { - createShippingUpdate(input: $input) { - orderId - status - itemId - name - id - } - }`, - { - input, - }, - ); - return result; -}; - -const listGSIShippingUpdate = async (orderId: string, itemId: any, sortDirection: string): Promise => { - const input = { orderId, itemId, sortDirection }; - const result = await GRAPHQL_CLIENT.query( - `query queryGSI( - $orderId: ID!, - $itemIdStatus: ModelShippingUpdateByOrderItemStatusCompositeKeyConditionInput, - $sortDirection: ModelSortDirection) { - shippingUpdates( - orderId: $orderId, - itemIdStatus: $itemIdStatus, - sortDirection: $sortDirection) { - items { - orderId - name - status - } - } - }`, - input, - ); - return result; -}; - -interface UpdateShippingInput { - id: string; - orderId?: string; - status?: string; - itemId?: string; - name?: string; -} -const updateShippingUpdate = async (input: UpdateShippingInput): Promise => { - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateShippingUpdate($input: UpdateShippingUpdateInput!) { - updateShippingUpdate(input: $input) { - orderId - status - itemId - name - id - } - }`, - { - input, - }, - ); - return result; -}; - -const getShippingUpdates = async (orderId: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query GetShippingUpdates($orderId: ID!) { - shippingUpdates(orderId: $orderId) { - items { - id - orderId - status - itemId - name - } - nextToken - } - }`, - { orderId }, - ); - return result; -}; - -const getShippingUpdatesWithNameFilter = async (orderId: string, name: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query GetShippingUpdates($orderId: ID!, $name: String) { - shippingUpdates(orderId: $orderId, filter: { name: { eq: $name }}) { - items { - id - orderId - status - itemId - name - } - nextToken - } - }`, - { orderId, name }, - ); - return result; -}; - -const createEmployee = async (managerId: string, level: number): Promise => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateEmployee($input: CreateEmployeeInput!) { - createEmployee(input: $input) { - managerId - level - } - }`, - { - input: { managerId, level }, - }, - ); - return result; -}; - -const queryEmployeesByManagerId = async (managerId: string): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query GetEmployeesByManagerId($managerId: ID!) { - employeesByManagerId(managerId: $managerId) { - items { - id - managerId - level - } - nextToken - } - }`, - { managerId }, - ); - return result; -}; - -const queryEmployeesByManagerIdAndLevel = async (managerId: string, level: number): Promise => { - const result = await GRAPHQL_CLIENT.query( - `query GetEmployeesByManagerIdAndLevel($managerId: ID!, $level: Int!) { - employeesByManagerIdAndLevel(managerId: $managerId, level: { eq: $level }) { - items { - id - managerId - level - } - nextToken - } - }`, - { managerId, level }, - ); - return result; -}; diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/IndexWithClaimFieldAsSortKeyAuth.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/IndexWithClaimFieldAsSortKeyAuth.e2e.test.ts deleted file mode 100644 index a4103d73cb..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/IndexWithClaimFieldAsSortKeyAuth.e2e.test.ts +++ /dev/null @@ -1,380 +0,0 @@ -import { IndexTransformer, PrimaryKeyTransformer } from '@aws-amplify/graphql-index-transformer'; -import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; -import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer'; -import { testTransform } from '@aws-amplify/graphql-transformer-test-utils'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { S3, CognitoIdentityServiceProvider as CognitoClient } from 'aws-sdk'; -import { default as moment } from 'moment'; -import AWSAppSyncClient, { AUTH_TYPE } from 'aws-appsync'; -import gql from 'graphql-tag'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { S3Client } from '../S3Client'; -import { - addUserToGroup, - authenticateUser, - configureAmplify, - createGroup, - createUserPool, - createUserPoolClient, - signupUser, -} from '../cognitoUtils'; -// to deal with bug in cognito-identity-js -(global as any).fetch = require('node-fetch'); - -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); -const cognitoClient = new CognitoClient({ apiVersion: '2016-04-19', region: region }); -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `IndexWithClaimFieldAsSortKeyAuthTest-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `appsync-index-with-claim-field-as-sk-test-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/index_sortkey_auth_transformer_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; - -let GRAPHQL_ENDPOINT: string; - -let USER_POOL_AUTH_CLIENT_1: AWSAppSyncClient; -let USER_POOL_AUTH_CLIENT_2: AWSAppSyncClient; - -let USER_POOL_ID: string; - -let USER_1_SUB: string; -let USER_2_SUB: string; - -const USERNAME1 = 'user1@test.com'; -const USERNAME2 = 'user2@test.com'; -const TMP_PASSWORD = 'Password123!'; -const REAL_PASSWORD = 'Password1234!'; - -const ADMIN_GROUP_NAME = 'Admin'; -const DEVS_GROUP_NAME = 'Devs'; - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -beforeAll(async () => { - const validSchema = ` - type Note1 @model - @auth(rules: [{ allow: owner }]) - { - noteId: String! @primaryKey - noteType: String! @index(name: "notesByNoteType", queryField:"note1sByNoteTypeAndOwner", sortKeyFields:["owner"]) - owner: String - } - type Note2 @model - @auth(rules: [{ allow: owner, identityClaim: "username" }]) - { - noteId: String! @primaryKey - noteType: String! @index(name: "notesByNoteType", queryField:"note2sByNoteTypeAndOwner", sortKeyFields:["owner"]) - owner: String - } - type Note3 @model - @auth(rules: [{ allow: groups, groupsField: "group" }]) - { - noteId: String! @primaryKey - noteType: String! @index(name: "notesByNoteType", queryField:"note3sByNoteTypeAndGroup", sortKeyFields:["group"]) - group: String - } - `; - let out; - try { - const modelTransformer = new ModelTransformer(); - const indexTransformer = new IndexTransformer(); - const authTransformer = new AuthTransformer(); - const primaryKeyTransformer = new PrimaryKeyTransformer(); - out = testTransform({ - schema: validSchema, - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - transformers: [modelTransformer, primaryKeyTransformer, indexTransformer, authTransformer], - }); - } catch (e) { - console.error(`Failed to transform schema: ${e}`); - expect(true).toEqual(false); - } - try { - await awsS3Client - .createBucket({ - Bucket: BUCKET_NAME, - }) - .promise(); - } catch (e) { - console.error(`Failed to create S3 bucket: ${e}`); - expect(true).toEqual(false); - } - const userPoolResponse = await createUserPool(cognitoClient, `UserPool${STACK_NAME}`); - USER_POOL_ID = userPoolResponse.UserPool?.Id!; - const userPoolClientResponse = await createUserPoolClient(cognitoClient, USER_POOL_ID, `UserPool${STACK_NAME}`); - const userPoolClientId = userPoolClientResponse.UserPoolClient?.ClientId!; - try { - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { AuthCognitoUserPoolId: USER_POOL_ID }, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - const apiKey = getApiKey(finishedStack.Outputs!); - GRAPHQL_ENDPOINT = getApiEndpoint(finishedStack.Outputs!)!; - expect(apiKey).not.toBeTruthy(); - - // Verify we have all the details - expect(GRAPHQL_ENDPOINT).toBeTruthy(); - expect(USER_POOL_ID).toBeTruthy(); - expect(userPoolClientId).toBeTruthy(); - // Configure Amplify - configureAmplify(USER_POOL_ID, userPoolClientId); - // Create groups - await createGroup(USER_POOL_ID, ADMIN_GROUP_NAME); - await createGroup(USER_POOL_ID, DEVS_GROUP_NAME); - // Sign up users, and sign in. - await signupUser(USER_POOL_ID, USERNAME1, TMP_PASSWORD); - await addUserToGroup(ADMIN_GROUP_NAME, USERNAME1, USER_POOL_ID); - const authRes1 = await authenticateUser(USERNAME1, TMP_PASSWORD, REAL_PASSWORD); - const idToken1 = authRes1.getIdToken().getJwtToken(); - USER_1_SUB = authRes1.idToken.payload.sub; - USER_POOL_AUTH_CLIENT_1 = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: () => idToken1, - }, - disableOffline: true, - }); - await signupUser(USER_POOL_ID, USERNAME2, TMP_PASSWORD); - await addUserToGroup(DEVS_GROUP_NAME, USERNAME2, USER_POOL_ID); - const authRes2 = await authenticateUser(USERNAME2, TMP_PASSWORD, REAL_PASSWORD); - const idToken2 = authRes2.getIdToken().getJwtToken(); - USER_2_SUB = authRes2.idToken.payload.sub; - USER_POOL_AUTH_CLIENT_2 = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: () => idToken2, - }, - disableOffline: true, - }); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf, { cognitoClient, userPoolId: USER_POOL_ID }); -}); - -/** - * Test queries below - */ - -test('when identity claim is sub::username, user1 should not access user2 records when logging in with user1 and querying with GSI', async () => { - await createNote1(USER_POOL_AUTH_CLIENT_1, { noteId: 'i1-u1', noteType: 't1' }); - await createNote1(USER_POOL_AUTH_CLIENT_1, { noteId: 'i2-u1', noteType: 't1' }); - await createNote1(USER_POOL_AUTH_CLIENT_1, { noteId: 'i3-u1', noteType: 't1' }); - await createNote1(USER_POOL_AUTH_CLIENT_2, { noteId: 'i1-u2', noteType: 't1' }); - - let resultItems; - // query without sk - const note1IndexQueryResponse = await note1ByNoteTypeAndOwner(USER_POOL_AUTH_CLIENT_1, { noteType: 't1' }); - resultItems = note1IndexQueryResponse.data.note1sByNoteTypeAndOwner.items; - expect(resultItems).toBeDefined(); - expect(resultItems.filter((item) => item.owner === USERNAME1).length).toBe(3); - expect(resultItems.filter((item) => item.owner === USERNAME2).length).toBe(0); - // query with sk - const note1IndexQueryWithSortKeyResponse = await note1ByNoteTypeAndOwner(USER_POOL_AUTH_CLIENT_1, { - noteType: 't1', - owner: { eq: `${USER_1_SUB}::${USERNAME1}` }, - }); - resultItems = note1IndexQueryWithSortKeyResponse.data.note1sByNoteTypeAndOwner.items; - expect(resultItems).toBeDefined(); - expect(resultItems.filter((item) => item.owner === USERNAME1).length).toBe(3); - expect(resultItems.filter((item) => item.owner === USERNAME2).length).toBe(0); -}); - -test('when identity claim is username, user1 should not access user2 records when logging in with user1 and querying with GSI', async () => { - await createNote2(USER_POOL_AUTH_CLIENT_1, { noteId: 'i1-u1', noteType: 't1', owner: USERNAME1 }); - await createNote2(USER_POOL_AUTH_CLIENT_1, { noteId: 'i2-u1', noteType: 't1', owner: USERNAME1 }); - await createNote2(USER_POOL_AUTH_CLIENT_1, { noteId: 'i3-u1', noteType: 't1', owner: USERNAME1 }); - await createNote2(USER_POOL_AUTH_CLIENT_2, { noteId: 'i1-u2', noteType: 't1', owner: USERNAME2 }); - - let resultItems; - const note2IndexQueryResponse = await note2ByNoteTypeAndOwner(USER_POOL_AUTH_CLIENT_1, { noteType: 't1' }); - resultItems = note2IndexQueryResponse.data.note2sByNoteTypeAndOwner.items; - expect(resultItems).toBeDefined(); - expect(resultItems.filter((item) => item.owner === USERNAME1).length).toBe(3); - expect(resultItems.filter((item) => item.owner === USERNAME2).length).toBe(0); - const note2IndexQueryWithSortKeyResponse = await note2ByNoteTypeAndOwner(USER_POOL_AUTH_CLIENT_1, { - noteType: 't1', - owner: { eq: USERNAME1 }, - }); - resultItems = note2IndexQueryWithSortKeyResponse.data.note2sByNoteTypeAndOwner.items; - expect(resultItems).toBeDefined(); - expect(resultItems.filter((item) => item.owner === USERNAME1).length).toBe(3); - expect(resultItems.filter((item) => item.owner === USERNAME2).length).toBe(0); -}); - -test('when dynamic group auth is applied, user1 should not access user2 records when logging in with user1 and querying with GSI', async () => { - await createNote3(USER_POOL_AUTH_CLIENT_1, { noteId: 'i1-u1', noteType: 't1', group: ADMIN_GROUP_NAME }); - await createNote3(USER_POOL_AUTH_CLIENT_1, { noteId: 'i2-u1', noteType: 't1', group: ADMIN_GROUP_NAME }); - await createNote3(USER_POOL_AUTH_CLIENT_1, { noteId: 'i3-u1', noteType: 't1', group: ADMIN_GROUP_NAME }); - await createNote3(USER_POOL_AUTH_CLIENT_2, { noteId: 'i1-u2', noteType: 't1', group: DEVS_GROUP_NAME }); - - let resultItems; - const note3IndexQueryResponse = await note3ByNoteTypeAndGroup(USER_POOL_AUTH_CLIENT_1, { noteType: 't1' }); - resultItems = note3IndexQueryResponse.data.note3sByNoteTypeAndGroup.items; - expect(resultItems).toBeDefined(); - expect(resultItems.filter((item) => item.group === ADMIN_GROUP_NAME).length).toBe(3); - expect(resultItems.filter((item) => item.group === DEVS_GROUP_NAME).length).toBe(0); - const note3IndexQueryWithSortKeyResponse = await note3ByNoteTypeAndGroup(USER_POOL_AUTH_CLIENT_1, { - noteType: 't1', - group: { eq: ADMIN_GROUP_NAME }, - }); - resultItems = note3IndexQueryWithSortKeyResponse.data.note3sByNoteTypeAndGroup.items; - expect(resultItems).toBeDefined(); - expect(resultItems.filter((item) => item.group === ADMIN_GROUP_NAME).length).toBe(3); - expect(resultItems.filter((item) => item.group === DEVS_GROUP_NAME).length).toBe(0); -}); - -/** - * Helper function - */ -const createNote1 = async (client: AWSAppSyncClient, variables: { noteId: string; noteType: string }): Promise => { - const result = await client.mutate({ - mutation: gql` - mutation CreateNote1($input: CreateNote1Input!) { - createNote1(input: $input) { - noteId - noteType - owner - } - } - `, - variables: { - input: variables, - }, - fetchPolicy: 'no-cache', - }); - return result; -}; -const createNote2 = async (client: AWSAppSyncClient, variables: { noteId: string; noteType: string; owner: string }): Promise => { - const result = await client.mutate({ - mutation: gql` - mutation CreateNote2($input: CreateNote2Input!) { - createNote2(input: $input) { - noteId - noteType - owner - } - } - `, - variables: { - input: variables, - }, - fetchPolicy: 'no-cache', - }); - return result; -}; -const createNote3 = async (client: AWSAppSyncClient, variables: { noteId: string; noteType: string; group: string }): Promise => { - const result = await client.mutate({ - mutation: gql` - mutation CreateNote3($input: CreateNote3Input!) { - createNote3(input: $input) { - noteId - noteType - group - } - } - `, - variables: { - input: variables, - }, - fetchPolicy: 'no-cache', - }); - return result; -}; -const note1ByNoteTypeAndOwner = async ( - client: AWSAppSyncClient, - variables: { noteType: string; owner?: { eq?: string } }, -): Promise => { - const result = await client.query({ - query: gql` - query Note1ByNoteTypeAndOwner($noteType: String!, $owner: ModelStringKeyConditionInput) { - note1sByNoteTypeAndOwner(noteType: $noteType, owner: $owner) { - items { - noteId - noteType - owner - } - } - } - `, - variables, - }); - return result; -}; -const note2ByNoteTypeAndOwner = async ( - client: AWSAppSyncClient, - variables: { noteType: string; owner?: { eq?: string } }, -): Promise => { - const result = await client.query({ - query: gql` - query Note2ByNoteTypeAndOwner($noteType: String!, $owner: ModelStringKeyConditionInput) { - note2sByNoteTypeAndOwner(noteType: $noteType, owner: $owner) { - items { - noteId - noteType - owner - } - } - } - `, - variables, - }); - return result; -}; -const note3ByNoteTypeAndGroup = async ( - client: AWSAppSyncClient, - variables: { noteType: string; group?: { eq?: string } }, -): Promise => { - const result = await client.query({ - query: gql` - query Note3ByNoteTypeAndGroup($noteType: String!, $group: ModelStringKeyConditionInput) { - note3sByNoteTypeAndGroup(noteType: $noteType, group: $group) { - items { - noteId - noteType - group - } - } - } - `, - variables, - }); - return result; -}; diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/KeyTransformer.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/KeyTransformer.e2e.test.ts deleted file mode 100644 index 4f5133e933..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/KeyTransformer.e2e.test.ts +++ /dev/null @@ -1,955 +0,0 @@ -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { KeyTransformer } from 'graphql-key-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as moment } from 'moment'; -import { default as S3 } from 'aws-sdk/clients/s3'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { GraphQLClient } from '../GraphQLClient'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { S3Client } from '../S3Client'; -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `KeyTransformerTests-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `appsync-key-transformer-test-bucket-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/key_transformer_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; - -let GRAPHQL_CLIENT = undefined; - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -beforeAll(async () => { - const validSchema = /* GraphQL */ ` - type Order @model @key(fields: ["customerEmail", "createdAt"]) { - customerEmail: String! - createdAt: AWSDateTime! - orderId: ID! - } - type Customer @model @key(fields: ["email"]) { - email: String! - addresslist: [String] - username: String - } - type Item - @model - @key(fields: ["orderId", "status", "createdAt"]) - @key(name: "ByStatus", fields: ["status", "createdAt"], queryField: "itemsByStatus") - @key(name: "ByCreatedAt", fields: ["createdAt", "status"], queryField: "itemsByCreatedAt") { - orderId: ID! - status: Status! - createdAt: AWSDateTime! - name: String! - } - enum Status { - DELIVERED - IN_TRANSIT - PENDING - UNKNOWN - } - type ShippingUpdate @model @key(name: "ByOrderItemStatus", fields: ["orderId", "itemId", "status"], queryField: "shippingUpdates") { - id: ID! - orderId: ID - itemId: ID - status: Status - name: String - } - type ModelWithIdAndCreatedAtAsKey @model @key(fields: ["id", "createdAt"]) { - id: ID! - createdAt: AWSDateTime! - name: String! - } - type KeylessBlog @model { - id: ID! - name: String! - createdAt: AWSDateTime! - } - type KeyedBlog @model @key(fields: ["id"]) { - id: ID! - name: String! - createdAt: AWSDateTime - } - type KeyedSortedBlog @model @key(fields: ["id", "createdAt"]) { - id: ID! - name: String! - createdAt: AWSDateTime! - } - `; - - try { - await awsS3Client.createBucket({ Bucket: BUCKET_NAME }).promise(); - } catch (e) { - console.warn(`Could not create bucket: ${e}`); - } - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new KeyTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { CreateAPIKey: '1', env: 'dev' }, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - // Arbitrary wait to make sure everything is ready. - await cf.wait(5, () => Promise.resolve()); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - const endpoint = getApiEndpoint(finishedStack.Outputs); - const apiKey = getApiKey(finishedStack.Outputs); - expect(apiKey).toBeDefined(); - expect(endpoint).toBeDefined(); - GRAPHQL_CLIENT = new GraphQLClient(endpoint, { 'x-api-key': apiKey }); -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf); -}); - -/** - * Test queries below - */ -test('next token with key', async () => { - const status = 'PENDING'; - const createdAt = '2019-06-06T00:01:01.000Z'; - // createItems - await createItem('order1', status, 'item1', '2019-01-06T00:01:01.000Z'); - await createItem('order2', status, 'item2', '2019-02-06T00:01:01.000Z'); - await createItem('order3', status, 'item3', '2019-03-06T00:01:01.000Z'); - await createItem('order4', status, 'item4', '2019-06-06T00:01:01.000Z'); - // query itemsByCreatedAt with limit of 2 - // const items = await itemsByCreatedAt(createdAt, { beginsWith: status }, 2); - const items = await itemsByStatus(status, { beginsWith: '2019' }, 2); - expect(items.data).toBeDefined(); - const itemsNextToken = items.data.itemsByStatus.nextToken; - expect(itemsNextToken).toBeDefined(); - // get first two values - expect(items.data.itemsByStatus.items).toHaveLength(2); - expect(items.data.itemsByStatus.items).toEqual( - expect.arrayContaining([ - expect.objectContaining({ orderId: 'order1', name: 'item1' }), - expect.objectContaining({ orderId: 'order2', name: 'item2' }), - ]), - ); - // use next token to get other values - const items2 = await itemsByStatus(status, { beginsWith: '2019' }, 2, itemsNextToken); - expect(items2.data).toBeDefined(); - // get last two values - expect(items2.data.itemsByStatus.items).toHaveLength(2); - expect(items2.data.itemsByStatus.items).toEqual( - expect.arrayContaining([ - expect.objectContaining({ orderId: 'order3', name: 'item3' }), - expect.objectContaining({ orderId: 'order4', name: 'item4' }), - ]), - ); - // deleteItems - await deleteItem('order1', status, createdAt); - await deleteItem('order2', status, createdAt); - await deleteItem('order3', status, createdAt); - await deleteItem('order4', status, createdAt); -}); - -test('getX with a two part primary key.', async () => { - const order1 = await createOrder('test@gmail.com', '1'); - const getOrder1 = await getOrder('test@gmail.com', order1.data.createOrder.createdAt); - expect(getOrder1.data.getOrder.orderId).toEqual('1'); -}); - -test('updateX with a two part primary key.', async () => { - const order2 = await createOrder('test3@gmail.com', '2'); - let getOrder2 = await getOrder('test3@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder.orderId).toEqual('2'); - const updateOrder2 = await updateOrder('test3@gmail.com', order2.data.createOrder.createdAt, '3'); - expect(updateOrder2.data.updateOrder.orderId).toEqual('3'); - getOrder2 = await getOrder('test3@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder.orderId).toEqual('3'); -}); - -test('deleteX with a two part primary key.', async () => { - const order2 = await createOrder('test2@gmail.com', '2'); - let getOrder2 = await getOrder('test2@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder.orderId).toEqual('2'); - const delOrder2 = await deleteOrder('test2@gmail.com', order2.data.createOrder.createdAt); - expect(delOrder2.data.deleteOrder.orderId).toEqual('2'); - getOrder2 = await getOrder('test2@gmail.com', order2.data.createOrder.createdAt); - expect(getOrder2.data.getOrder).toBeNull(); -}); - -test('getX with a three part primary key', async () => { - const item1 = await createItem('1', 'PENDING', 'item1'); - const getItem1 = await getItem('1', 'PENDING', item1.data.createItem.createdAt); - expect(getItem1.data.getItem.orderId).toEqual('1'); - expect(getItem1.data.getItem.status).toEqual('PENDING'); -}); - -test('updateX with a three part primary key.', async () => { - const item2 = await createItem('2', 'PENDING', 'item2'); - let getItem2 = await getItem('2', 'PENDING', item2.data.createItem.createdAt); - expect(getItem2.data.getItem.orderId).toEqual('2'); - const updateItem2 = await updateItem('2', 'PENDING', item2.data.createItem.createdAt, 'item2.1'); - expect(updateItem2.data.updateItem.name).toEqual('item2.1'); - getItem2 = await getItem('2', 'PENDING', item2.data.createItem.createdAt); - expect(getItem2.data.getItem.name).toEqual('item2.1'); -}); - -test('deleteX with a three part primary key.', async () => { - const item3 = await createItem('3', 'IN_TRANSIT', 'item3'); - let getItem3 = await getItem('3', 'IN_TRANSIT', item3.data.createItem.createdAt); - expect(getItem3.data.getItem.name).toEqual('item3'); - const delItem3 = await deleteItem('3', 'IN_TRANSIT', item3.data.createItem.createdAt); - expect(delItem3.data.deleteItem.name).toEqual('item3'); - getItem3 = await getItem('3', 'IN_TRANSIT', item3.data.createItem.createdAt); - expect(getItem3.data.getItem).toBeNull(); -}); - -test('listX with three part primary key.', async () => { - const hashKey = 'TEST_LIST_ID'; - await createItem(hashKey, 'IN_TRANSIT', 'list1', '2018-01-01T00:01:01.000Z'); - await createItem(hashKey, 'PENDING', 'list2', '2018-06-01T00:01:01.000Z'); - await createItem(hashKey, 'PENDING', 'item3', '2018-09-01T00:01:01.000Z'); - let items = await listItem(undefined); - expect(items.data.listItems.items.length).toBeGreaterThan(0); - items = await listItem(hashKey); - expect(items.data.listItems.items).toHaveLength(3); - items = await listItem(hashKey, { beginsWith: { status: 'PENDING' } }); - expect(items.data.listItems.items).toHaveLength(2); - items = await listItem(hashKey, { beginsWith: { status: 'IN_TRANSIT' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { beginsWith: { status: 'PENDING', createdAt: '2018-09' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { eq: { status: 'PENDING', createdAt: '2018-09-01T00:01:01.000Z' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { - between: [ - { status: 'PENDING', createdAt: '2018-08-01' }, - { status: 'PENDING', createdAt: '2018-10-01' }, - ], - }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { gt: { status: 'PENDING', createdAt: '2018-08-1' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { ge: { status: 'PENDING', createdAt: '2018-09-01T00:01:01.000Z' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { lt: { status: 'IN_TRANSIT', createdAt: '2018-01-02' } }); - expect(items.data.listItems.items).toHaveLength(1); - items = await listItem(hashKey, { le: { status: 'IN_TRANSIT', createdAt: '2018-01-01T00:01:01.000Z' } }); - expect(items.data.listItems.items).toHaveLength(1); - await deleteItem(hashKey, 'IN_TRANSIT', '2018-01-01T00:01:01.000Z'); - await deleteItem(hashKey, 'PENDING', '2018-06-01T00:01:01.000Z'); - await deleteItem(hashKey, 'PENDING', '2018-09-01T00:01:01.000Z'); -}); - -test('query with three part secondary key.', async () => { - const hashKey = 'UNKNOWN'; - await createItem('order1', 'UNKNOWN', 'list1', '2018-01-01T00:01:01.000Z'); - await createItem('order2', 'UNKNOWN', 'list2', '2018-06-01T00:01:01.000Z'); - await createItem('order3', 'UNKNOWN', 'item3', '2018-09-01T00:01:01.000Z'); - let items = await itemsByStatus(undefined); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - items = await itemsByStatus(hashKey); - expect(items.data.itemsByStatus.items).toHaveLength(3); - items = await itemsByStatus(hashKey, { beginsWith: '2018-09' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { eq: '2018-09-01T00:01:01.000Z' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { between: ['2018-08-01', '2018-10-01'] }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { gt: '2018-08-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { ge: '2018-09-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(hashKey, { lt: '2018-07-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(2); - items = await itemsByStatus(hashKey, { le: '2018-06-01' }); - expect(items.data.itemsByStatus.items).toHaveLength(1); - items = await itemsByStatus(undefined, { le: '2018-09-01' }); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - await deleteItem('order1', hashKey, '2018-01-01T00:01:01.000Z'); - await deleteItem('order2', hashKey, '2018-06-01T00:01:01.000Z'); - await deleteItem('order3', hashKey, '2018-09-01T00:01:01.000Z'); -}); - -test('query with three part secondary key, where sort key is an enum.', async () => { - const hashKey = '2018-06-01T00:01:01.000Z'; - const sortKey = 'UNKNOWN'; - await createItem('order1', sortKey, 'list1', '2018-01-01T00:01:01.000Z'); - await createItem('order2', sortKey, 'list2', hashKey); - await createItem('order3', sortKey, 'item3', '2018-09-01T00:01:01.000Z'); - let items = await itemsByCreatedAt(undefined); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - items = await itemsByCreatedAt(hashKey); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { beginsWith: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { eq: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { between: [sortKey, sortKey] }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { gt: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(0); - items = await itemsByCreatedAt(hashKey, { ge: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(hashKey, { lt: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(0); - items = await itemsByCreatedAt(hashKey, { le: sortKey }); - expect(items.data.itemsByCreatedAt.items).toHaveLength(1); - items = await itemsByCreatedAt(undefined, { le: sortKey }); - expect(items.data).toBeNull(); - expect(items.errors.length).toBeGreaterThan(0); - await deleteItem('order1', sortKey, '2018-01-01T00:01:01.000Z'); - await deleteItem('order2', sortKey, hashKey); - await deleteItem('order3', sortKey, '2018-09-01T00:01:01.000Z'); -}); - -test('create/update mutation validation with three part secondary key.', async () => { - const createResponseMissingLastSortKey = await createShippingUpdate({ orderId: 'order1', itemId: 'item1', name: '42' }); - expect(createResponseMissingLastSortKey.data.createShippingUpdate).toBeNull(); - expect(createResponseMissingLastSortKey.errors).toHaveLength(1); - - const createResponseMissingFirstSortKey = await createShippingUpdate({ orderId: '2ndtry', status: 'PENDING', name: '43?' }); - expect(createResponseMissingFirstSortKey.data.createShippingUpdate).toBeNull(); - expect(createResponseMissingFirstSortKey.errors).toHaveLength(1); - - await createShippingUpdate({ orderId: 'order1', itemId: 'item1', status: 'PENDING', name: 'name1' }); - const items = await getShippingUpdates('order1'); - expect(items.data.shippingUpdates.items).toHaveLength(1); - const item = items.data.shippingUpdates.items[0]; - expect(item.name).toEqual('name1'); - - const itemsWithFilter = await getShippingUpdatesWithNameFilter('order1', 'name1'); - expect(itemsWithFilter.data.shippingUpdates.items).toHaveLength(1); - const itemWithFilter = itemsWithFilter.data.shippingUpdates.items[0]; - expect(itemWithFilter.name).toEqual('name1'); - - const itemsWithUnknownFilter = await getShippingUpdatesWithNameFilter('order1', 'unknownname'); - expect(itemsWithUnknownFilter.data.shippingUpdates.items).toHaveLength(0); - - const updateResponseMissingLastSortKey = await updateShippingUpdate({ id: item.id, orderId: 'order1', itemId: 'item1', name: 'name2' }); - expect(updateResponseMissingLastSortKey.data.updateShippingUpdate).toBeNull(); - expect(updateResponseMissingLastSortKey.errors).toHaveLength(1); - const updateResponseMissingFirstSortKey = await updateShippingUpdate({ - id: item.id, - orderId: 'order1', - status: 'PENDING', - name: 'name3', - }); - expect(updateResponseMissingFirstSortKey.data.updateShippingUpdate).toBeNull(); - expect(updateResponseMissingFirstSortKey.errors).toHaveLength(1); - const updateResponseMissingAllSortKeys = await updateShippingUpdate({ id: item.id, orderId: 'order1', name: 'testing' }); - expect(updateResponseMissingAllSortKeys.data.updateShippingUpdate.name).toEqual('testing'); - const updateResponseMissingNoKeys = await updateShippingUpdate({ - id: item.id, - orderId: 'order1', - itemId: 'item1', - status: 'PENDING', - name: 'testing2', - }); - expect(updateResponseMissingNoKeys.data.updateShippingUpdate.name).toEqual('testing2'); -}); - -test('Customer Create with list member and secondary key', async () => { - await createCustomer('customer1@email.com', ['thing1', 'thing2'], 'customerusr1'); - const getCustomer1 = await getCustomer('customer1@email.com'); - expect(getCustomer1.data.getCustomer.addresslist).toEqual(['thing1', 'thing2']); -}); - -test('cannot overwrite customer record with custom primary key', async () => { - await createCustomer('customer42@email.com', ['thing1', 'thing2'], 'customerusr42'); - const response = await createCustomer('customer42@email.com', ['thing2'], 'customerusr43'); - expect(response.errors).toBeDefined(); - expect(response.errors[0]).toEqual( - expect.objectContaining({ - errorType: 'DynamoDB:ConditionalCheckFailedException', - message: expect.stringContaining('The conditional request failed'), - }), - ); -}); - -test('Customer Mutation with list member', async () => { - await updateCustomer('customer1@email.com', ['thing3', 'thing4'], 'new_customerusr1'); - const getCustomer1 = await getCustomer('customer1@email.com'); - expect(getCustomer1.data.getCustomer.addresslist).toEqual(['thing3', 'thing4']); -}); - -test('Customer Mutation with list member', async () => { - await updateCustomer('customer1@email.com', ['thing3', 'thing4'], 'new_customerusr1'); - const getCustomer1 = await getCustomer('customer1@email.com'); - expect(getCustomer1.data.getCustomer.addresslist).toEqual(['thing3', 'thing4']); -}); - -test('@key directive with customer sortDirection', async () => { - await createOrder('testorder1@email.com', '1', '2016-03-10T00:45:08+00:00'); - await createOrder('testorder1@email.com', '2', '2018-05-22T21:45:08+00:00'); - await createOrder('testorder1@email.com', '3', '2019-06-27T12:00:08+00:00'); - const newOrders = await listOrders('testorder1@email.com', { beginsWith: '201' }, 'DESC'); - const oldOrders = await listOrders('testorder1@email.com', { beginsWith: '201' }, 'ASC'); - expect(newOrders.data.listOrders.items[0].createdAt).toEqual('2019-06-27T12:00:08+00:00'); - expect(newOrders.data.listOrders.items[0].orderId).toEqual('3'); - expect(oldOrders.data.listOrders.items[0].createdAt).toEqual('2016-03-10T00:45:08+00:00'); - expect(oldOrders.data.listOrders.items[0].orderId).toEqual('1'); -}); - -// orderId: string, itemId: string, status: string, name?: string -// DELIVERED IN_TRANSIT PENDING UNKNOWN -// (orderId: string, itemId: string, sortDirection: string) -test('@key directive with sortDirection on GSI', async () => { - await createShippingUpdate({ orderId: 'order1', itemId: 'product1', status: 'PENDING', name: 'order1Name1' }); - await createShippingUpdate({ orderId: 'order1', itemId: 'product2', status: 'IN_TRANSIT', name: 'order1Name2' }); - await createShippingUpdate({ orderId: 'order1', itemId: 'product3', status: 'DELIVERED', name: 'order1Name3' }); - await createShippingUpdate({ orderId: 'order1', itemId: 'product4', status: 'DELIVERED', name: 'order1Name4' }); - const newShippingUpdates = await listGSIShippingUpdate('order1', { beginsWith: { itemId: 'product' } }, 'DESC'); - const oldShippingUpdates = await listGSIShippingUpdate('order1', { beginsWith: { itemId: 'product' } }, 'ASC'); - expect(oldShippingUpdates.data.shippingUpdates.items[0].status).toEqual('PENDING'); - expect(oldShippingUpdates.data.shippingUpdates.items[0].name).toEqual('testing2'); - expect(newShippingUpdates.data.shippingUpdates.items[0].status).toEqual('DELIVERED'); - expect(newShippingUpdates.data.shippingUpdates.items[0].name).toEqual('order1Name4'); -}); - -test('@key directive supports auto Id and createdAt fields in create mutation', async () => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateModelWithIdAndCreatedAtAsKey{ - createModelWithIdAndCreatedAtAsKey(input:{ name: "John Doe" }) { - id - createdAt - name - } - }`, - ); - expect(result.data.createModelWithIdAndCreatedAtAsKey.id).not.toBeNull(); - expect(result.data.createModelWithIdAndCreatedAtAsKey.createdAt).not.toBeNull(); - expect(result.data.createModelWithIdAndCreatedAtAsKey.name).toEqual('John Doe'); -}); - -test('sortDirection validation error for List on KeyedBlog type', async () => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateKeyedBlog($input: CreateKeyedBlogInput!) { - createKeyedBlog(input: $input) { - id - name - } - }`, - { - input: { - id: 'B1', - name: 'Blog #1', - }, - }, - ); - - expect(result.data).not.toBeNull(); - expect(result.errors).toBeUndefined(); - - const listResult = await GRAPHQL_CLIENT.query( - `query ListKeyedBlogs { - listKeyedBlogs(sortDirection: ASC) { - items { - id - name - } - } - }`, - ); - - expect(listResult.data).not.toBeNull(); - expect(listResult.data.listKeyedBlogs).toBeNull(); - expect(listResult.errors).toBeDefined(); - expect(listResult.errors.length).toEqual(1); - expect(listResult.errors[0].message).toEqual('sortDirection is not supported for List operations without a Sort key defined.'); -}); - -test('sortDirection validation error for List on KeyedSortedBlog type', async () => { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateKeyedSortedBlog($input: CreateKeyedSortedBlogInput!) { - createKeyedSortedBlog(input: $input) { - id - name - } - }`, - { - input: { - id: 'B1', - name: 'Blog #1', - }, - }, - ); - - expect(result.data).not.toBeNull(); - expect(result.errors).toBeUndefined(); - - const listWithErrorResult = await GRAPHQL_CLIENT.query( - `query ListKeyedSortedBlogs { - listKeyedSortedBlogs(sortDirection: ASC) { - items { - id - name - } - } - }`, - ); - - expect(listWithErrorResult.data).not.toBeNull(); - expect(listWithErrorResult.data.listKeyedSortedBlogs).toBeNull(); - expect(listWithErrorResult.errors).toBeDefined(); - expect(listWithErrorResult.errors.length).toEqual(1); - expect(listWithErrorResult.errors[0].message).toEqual("When providing argument 'sortDirection' you must also provide argument 'id'."); - - const listResult = await GRAPHQL_CLIENT.query( - `query ListKeyedSortedBlogs { - listKeyedSortedBlogs(id: "B1", sortDirection: ASC) { - items { - id - name - } - } - }`, - ); - - expect(listResult.data).not.toBeNull(); - expect(listResult.data.listKeyedSortedBlogs).not.toBeNull(); - expect(listResult.errors).toBeUndefined; -}); - -async function createCustomer(email: string, addresslist: string[], username: string) { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateCustomer($input: CreateCustomerInput!) { - createCustomer(input: $input) { - email - addresslist - username - } - }`, - { - input: { email, addresslist, username }, - }, - ); - return result; -} - -async function updateCustomer(email: string, addresslist: string[], username: string) { - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateCustomer($input: UpdateCustomerInput!) { - updateCustomer(input: $input) { - email - addresslist - username - } - }`, - { - input: { email, addresslist, username }, - }, - ); - return result; -} - -async function getCustomer(email: string) { - const result = await GRAPHQL_CLIENT.query( - `query GetCustomer($email: String!) { - getCustomer(email: $email) { - email - addresslist - username - } - }`, - { - email, - }, - ); - return result; -} - -async function createOrder(customerEmail: string, orderId: string, createdAt: string = new Date().toISOString()) { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateOrder($input: CreateOrderInput!) { - createOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, orderId, createdAt }, - }, - ); - return result; -} - -async function updateOrder(customerEmail: string, createdAt: string, orderId: string) { - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateOrder($input: UpdateOrderInput!) { - updateOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, orderId, createdAt }, - }, - ); - return result; -} - -async function deleteOrder(customerEmail: string, createdAt: string) { - const result = await GRAPHQL_CLIENT.query( - `mutation DeleteOrder($input: DeleteOrderInput!) { - deleteOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, createdAt }, - }, - ); - return result; -} - -async function getOrder(customerEmail: string, createdAt: string) { - const result = await GRAPHQL_CLIENT.query( - `query GetOrder($customerEmail: String!, $createdAt: AWSDateTime!) { - getOrder(customerEmail: $customerEmail, createdAt: $createdAt) { - customerEmail - orderId - createdAt - } - }`, - { customerEmail, createdAt }, - ); - return result; -} - -interface ModelStringKeyConditionInput { - eq?: string; - gt?: string; - ge?: string; - lt?: string; - le?: string; - between?: string[]; - beginsWith?: string; -} - -async function listOrders(customerEmail: string, createdAt: ModelStringKeyConditionInput, sortDirection: string) { - const input = { customerEmail, createdAt, sortDirection }; - const result = await GRAPHQL_CLIENT.query( - `query ListOrders( - $customerEmail: String, $createdAt: ModelStringKeyConditionInput, $sortDirection: ModelSortDirection) { - listOrders(customerEmail: $customerEmail, createdAt: $createdAt, sortDirection: $sortDirection) { - items { - orderId - customerEmail - createdAt - } - } - }`, - input, - ); - return result; -} - -async function createItem(orderId: string, status: string, name: string, createdAt: string = new Date().toISOString()) { - const input = { status, orderId, name, createdAt }; - const result = await GRAPHQL_CLIENT.query( - `mutation CreateItem($input: CreateItemInput!) { - createItem(input: $input) { - orderId - status - createdAt - name - } - }`, - { - input, - }, - ); - return result; -} - -async function updateItem(orderId: string, status: string, createdAt: string, name: string) { - const input = { status, orderId, createdAt, name }; - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateItem($input: UpdateItemInput!) { - updateItem(input: $input) { - orderId - status - createdAt - name - } - }`, - { - input, - }, - ); - return result; -} - -async function deleteItem(orderId: string, status: string, createdAt: string) { - const input = { orderId, status, createdAt }; - const result = await GRAPHQL_CLIENT.query( - `mutation DeleteItem($input: DeleteItemInput!) { - deleteItem(input: $input) { - orderId - status - createdAt - name - } - }`, - { - input, - }, - ); - return result; -} - -async function getItem(orderId: string, status: string, createdAt: string) { - const result = await GRAPHQL_CLIENT.query( - `query GetItem($orderId: ID!, $status: Status!, $createdAt: AWSDateTime!) { - getItem(orderId: $orderId, status: $status, createdAt: $createdAt) { - orderId - status - createdAt - name - } - }`, - { orderId, status, createdAt }, - ); - return result; -} - -interface StringKeyConditionInput { - eq?: string; - gt?: string; - ge?: string; - lt?: string; - le?: string; - between?: string[]; - beginsWith?: string; -} - -interface ItemCompositeKeyConditionInput { - eq?: ItemCompositeKeyInput; - gt?: ItemCompositeKeyInput; - ge?: ItemCompositeKeyInput; - lt?: ItemCompositeKeyInput; - le?: ItemCompositeKeyInput; - between?: ItemCompositeKeyInput[]; - beginsWith?: ItemCompositeKeyInput; -} -interface ItemCompositeKeyInput { - status?: string; - createdAt?: string; -} -async function listItem(orderId?: string, statusCreatedAt?: ItemCompositeKeyConditionInput, limit?: number, nextToken?: string) { - const result = await GRAPHQL_CLIENT.query( - `query ListItems( - $orderId: ID, $statusCreatedAt: ModelItemPrimaryCompositeKeyConditionInput, $limit: Int, $nextToken: String) { - listItems(orderId: $orderId, statusCreatedAt: $statusCreatedAt, limit: $limit, nextToken: $nextToken) { - items { - orderId - status - createdAt - name - } - nextToken - } - }`, - { orderId, statusCreatedAt, limit, nextToken }, - ); - return result; -} - -async function itemsByStatus(status: string, createdAt?: StringKeyConditionInput, limit?: number, nextToken?: string) { - const result = await GRAPHQL_CLIENT.query( - `query ListByStatus( - $status: Status!, $createdAt: ModelStringKeyConditionInput, $limit: Int, $nextToken: String) { - itemsByStatus(status: $status, createdAt: $createdAt, limit: $limit, nextToken: $nextToken) { - items { - orderId - status - createdAt - name - } - nextToken - } - }`, - { status, createdAt, limit, nextToken }, - ); - return result; -} - -async function itemsByCreatedAt(createdAt: string, status?: StringKeyConditionInput, limit?: number, nextToken?: string) { - const result = await GRAPHQL_CLIENT.query( - `query ListByCreatedAt( - $createdAt: AWSDateTime!, $status: ModelStringKeyConditionInput, $limit: Int, $nextToken: String) { - itemsByCreatedAt(createdAt: $createdAt, status: $status, limit: $limit, nextToken: $nextToken) { - items { - orderId - status - createdAt - name - } - nextToken - } - }`, - { createdAt, status, limit, nextToken }, - ); - return result; -} - -interface CreateShippingInput { - id?: string; - orderId?: string; - status?: string; - itemId?: string; - name?: string; -} - -async function createShippingUpdate(input: CreateShippingInput) { - const result = await GRAPHQL_CLIENT.query( - `mutation CreateShippingUpdate($input: CreateShippingUpdateInput!) { - createShippingUpdate(input: $input) { - orderId - status - itemId - name - id - } - }`, - { - input, - }, - ); - return result; -} - -async function listGSIShippingUpdate(orderId: string, itemId: object, sortDirection: string) { - const input = { orderId, itemId, sortDirection }; - const result = await GRAPHQL_CLIENT.query( - `query queryGSI( - $orderId: ID, - $itemIdStatus: ModelShippingUpdateByOrderItemStatusCompositeKeyConditionInput, - $sortDirection: ModelSortDirection) { - shippingUpdates( - orderId: $orderId, - itemIdStatus: $itemIdStatus, - sortDirection: $sortDirection) { - items { - orderId - name - status - } - } - }`, - input, - ); - return result; -} - -interface UpdateShippingInput { - id: string; - orderId?: string; - status?: string; - itemId?: string; - name?: string; -} -async function updateShippingUpdate(input: UpdateShippingInput) { - const result = await GRAPHQL_CLIENT.query( - `mutation UpdateShippingUpdate($input: UpdateShippingUpdateInput!) { - updateShippingUpdate(input: $input) { - orderId - status - itemId - name - id - } - }`, - { - input, - }, - ); - return result; -} - -async function getShippingUpdates(orderId: string) { - const result = await GRAPHQL_CLIENT.query( - `query GetShippingUpdates($orderId: ID!) { - shippingUpdates(orderId: $orderId) { - items { - id - orderId - status - itemId - name - } - nextToken - } - }`, - { orderId }, - ); - return result; -} - -async function getShippingUpdatesWithNameFilter(orderId: string, name: string) { - const result = await GRAPHQL_CLIENT.query( - `query GetShippingUpdates($orderId: ID!, $name: String) { - shippingUpdates(orderId: $orderId, filter: { name: { eq: $name }}) { - items { - id - orderId - status - itemId - name - } - nextToken - } - }`, - { orderId, name }, - ); - return result; -} diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/KeyTransformerLocal.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/KeyTransformerLocal.e2e.test.ts deleted file mode 100644 index 16a1440954..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/KeyTransformerLocal.e2e.test.ts +++ /dev/null @@ -1,511 +0,0 @@ -import { GraphQLTransform, FeatureFlagProvider } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { KeyTransformer } from 'graphql-key-transformer'; -import { parse, FieldDefinitionNode, ObjectTypeDefinitionNode, Kind, InputObjectTypeDefinitionNode } from 'graphql'; -import { - expectArguments, - expectNonNullFields, - expectNullableFields, - expectNonNullInputValues, - expectNullableInputValues, - expectInputValueToHandle, -} from '../testUtil'; - -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -test('that a primary @key with a single field changes the hash key.', () => { - const validSchema = ` - type Test @model @key(fields: ["email"]) { - email: String! - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - }); - - const out = transformer.transform(validSchema); - let tableResource = out.stacks.Test.Resources.TestTable; - expect(tableResource).toBeDefined(); - expect(tableResource.Properties.KeySchema[0].AttributeName).toEqual('email'); - expect(tableResource.Properties.KeySchema[0].KeyType).toEqual('HASH'); - expect(tableResource.Properties.AttributeDefinitions[0].AttributeType).toEqual('S'); - const schema = parse(out.schema); - const queryType = schema.definitions.find((def: any) => def.name && def.name.value === 'Query') as ObjectTypeDefinitionNode; - const getTestField = queryType.fields.find((f) => f.name && f.name.value === 'getTest') as FieldDefinitionNode; - expect(getTestField.arguments).toHaveLength(1); - expectArguments(getTestField, ['email']); -}); - -test('that a primary @key with 2 fields changes the hash and sort key.', () => { - const validSchema = ` - type Test @model @key(fields: ["email", "kind"]) { - email: String! - kind: Int! - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - }); - - const out = transformer.transform(validSchema); - let tableResource = out.stacks.Test.Resources.TestTable; - expect(tableResource).toBeDefined(); - const hashKey = tableResource.Properties.KeySchema.find((o) => o.KeyType === 'HASH'); - const hashKeyAttr = tableResource.Properties.AttributeDefinitions.find((o) => o.AttributeName === 'email'); - const rangeKey = tableResource.Properties.KeySchema.find((o) => o.KeyType === 'RANGE'); - const rangeKeyAttr = tableResource.Properties.AttributeDefinitions.find((o) => o.AttributeName === 'kind'); - expect(tableResource.Properties.AttributeDefinitions).toHaveLength(2); - expect(hashKey.AttributeName).toEqual('email'); - expect(rangeKey.AttributeName).toEqual('kind'); - expect(hashKeyAttr.AttributeType).toEqual('S'); - expect(rangeKeyAttr.AttributeType).toEqual('N'); - - const schema = parse(out.schema); - const queryType = schema.definitions.find((def: any) => def.name && def.name.value === 'Query') as ObjectTypeDefinitionNode; - const getTestField = queryType.fields.find((f) => f.name && f.name.value === 'getTest') as FieldDefinitionNode; - expect(getTestField.arguments).toHaveLength(2); - expectArguments(getTestField, ['email', 'kind']); -}); - -test('that a primary @key with id as hashKey does not have it required in createInput', () => { - const validSchema = ` - type Test @model @key(fields: ["id", "kind"]) { - id: ID! - email: String! - kind: Int! - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - }); - - const out = transformer.transform(validSchema); - const schema = parse(out.schema); - const createInput = schema.definitions.find((def: any) => def.name && def.name.value === 'CreateTestInput') as ObjectTypeDefinitionNode; - expectNonNullFields(createInput, ['kind', 'email']); - expectNullableFields(createInput, ['id']); - - const updateInput = schema.definitions.find((def: any) => def.name && def.name.value === 'UpdateTestInput') as ObjectTypeDefinitionNode; - expectNonNullFields(updateInput, ['id', 'kind']); - expectNullableFields(updateInput, ['email']); - - const deleteInput = schema.definitions.find((def: any) => def.name && def.name.value === 'DeleteTestInput') as ObjectTypeDefinitionNode; - expectNonNullFields(deleteInput, ['id', 'kind']); -}); - -test('that a primary @key with id and createdAt it is not a required in createInput', () => { - const validSchema = ` - type Test @model @key(fields: ["id", "createdAt"]) { - id: ID! - email: String! - createdAt: AWSDateTime! - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - }); - - const out = transformer.transform(validSchema); - const schema = parse(out.schema); - const createInput = schema.definitions.find((def: any) => def.name && def.name.value === 'CreateTestInput') as ObjectTypeDefinitionNode; - expectNonNullFields(createInput, ['email']); - expectNullableFields(createInput, ['id', 'createdAt']); - - const updateInput = schema.definitions.find((def: any) => def.name && def.name.value === 'UpdateTestInput') as ObjectTypeDefinitionNode; - expectNonNullFields(updateInput, ['id', 'createdAt']); - expectNullableFields(updateInput, ['email']); - - const deleteInput = schema.definitions.find((def: any) => def.name && def.name.value === 'DeleteTestInput') as ObjectTypeDefinitionNode; - expectNonNullFields(deleteInput, ['id', 'createdAt']); -}); - -test('that a primary @key with emailId and location makes it a required in createInput', () => { - const validSchema = ` - type Test @model @key(fields: ["emailId", "location"]) { - emailId: AWSEmail! - location: String! - name: String - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - }); - - const out = transformer.transform(validSchema); - const schema = parse(out.schema); - const createInput = schema.definitions.find((def: any) => def.name && def.name.value === 'CreateTestInput') as ObjectTypeDefinitionNode; - expectNonNullFields(createInput, ['emailId', 'location']); - expectNullableFields(createInput, ['name']); - - const updateInput = schema.definitions.find((def: any) => def.name && def.name.value === 'UpdateTestInput') as ObjectTypeDefinitionNode; - expectNonNullFields(updateInput, ['emailId', 'location']); - expectNullableFields(updateInput, ['name']); - - const deleteInput = schema.definitions.find((def: any) => def.name && def.name.value === 'DeleteTestInput') as ObjectTypeDefinitionNode; - expectNonNullFields(deleteInput, ['emailId', 'location']); -}); - -test('that a primary @key with 3 fields changes the hash and sort keys.', () => { - const validSchema = ` - type Test @model @key(fields: ["email", "kind", "date"]) { - email: String! - kind: Int! - date: AWSDateTime! - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - }); - - const out = transformer.transform(validSchema); - let tableResource = out.stacks.Test.Resources.TestTable; - expect(tableResource).toBeDefined(); - const hashKey = tableResource.Properties.KeySchema.find((o) => o.KeyType === 'HASH'); - const hashKeyAttr = tableResource.Properties.AttributeDefinitions.find((o) => o.AttributeName === 'email'); - const rangeKey = tableResource.Properties.KeySchema.find((o) => o.KeyType === 'RANGE'); - const rangeKeyAttr = tableResource.Properties.AttributeDefinitions.find((o) => o.AttributeName === 'kind#date'); - expect(tableResource.Properties.AttributeDefinitions).toHaveLength(2); - expect(hashKey.AttributeName).toEqual('email'); - expect(rangeKey.AttributeName).toEqual('kind#date'); - expect(hashKeyAttr.AttributeType).toEqual('S'); - // composite keys will always be strings. - expect(rangeKeyAttr.AttributeType).toEqual('S'); - - const schema = parse(out.schema); - const queryType = schema.definitions.find((def: any) => def.name && def.name.value === 'Query') as ObjectTypeDefinitionNode; - const getTestField = queryType.fields.find((f) => f.name && f.name.value === 'getTest') as FieldDefinitionNode; - expect(getTestField.arguments).toHaveLength(3); - expectArguments(getTestField, ['email', 'kind', 'date']); - - const listTestField = queryType.fields.find((f) => f.name && f.name.value === 'listTests') as FieldDefinitionNode; - expect(listTestField.arguments).toHaveLength(6); - expectArguments(listTestField, ['email', 'kindDate', 'filter', 'nextToken', 'limit', 'sortDirection']); -}); - -test('that a secondary @key with 3 fields changes the hash and sort keys and adds a query fields correctly.', () => { - const validSchema = ` - type Test @model @key(name: "GSI", fields: ["email", "kind", "date"], queryField: "listByEmailKindDate") { - email: String! - kind: Int! - date: AWSDateTime! - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - }); - - const out = transformer.transform(validSchema); - let tableResource = out.stacks.Test.Resources.TestTable; - expect(tableResource).toBeDefined(); - const hashKey = tableResource.Properties.KeySchema.find((o) => o.KeyType === 'HASH'); - const hashKeyAttr = tableResource.Properties.AttributeDefinitions.find((o) => o.AttributeName === 'email'); - expect(tableResource.Properties.AttributeDefinitions).toHaveLength(3); - expect(hashKey.AttributeName).toEqual('id'); - expect(hashKeyAttr.AttributeType).toEqual('S'); - // composite keys will always be strings. - - const gsi = tableResource.Properties.GlobalSecondaryIndexes.find((o) => o.IndexName === 'GSI'); - const gsiHashKey = gsi.KeySchema.find((o) => o.KeyType === 'HASH'); - const gsiHashKeyAttr = tableResource.Properties.AttributeDefinitions.find((o) => o.AttributeName === 'email'); - const gsiRangeKey = gsi.KeySchema.find((o) => o.KeyType === 'RANGE'); - const gsiRangeKeyAttr = tableResource.Properties.AttributeDefinitions.find((o) => o.AttributeName === 'kind#date'); - expect(gsiHashKey.AttributeName).toEqual('email'); - expect(gsiRangeKey.AttributeName).toEqual('kind#date'); - expect(gsiHashKeyAttr.AttributeType).toEqual('S'); - expect(gsiRangeKeyAttr.AttributeType).toEqual('S'); - - const schema = parse(out.schema); - const queryType = schema.definitions.find((def: any) => def.name && def.name.value === 'Query') as ObjectTypeDefinitionNode; - const getTestField = queryType.fields.find((f) => f.name && f.name.value === 'getTest') as FieldDefinitionNode; - expect(getTestField.arguments).toHaveLength(1); - expectArguments(getTestField, ['id']); - - const queryField = queryType.fields.find((f) => f.name && f.name.value === 'listByEmailKindDate') as FieldDefinitionNode; - expect(queryField.arguments).toHaveLength(6); - expectArguments(queryField, ['email', 'kindDate', 'filter', 'nextToken', 'limit', 'sortDirection']); - - const listTestField = queryType.fields.find((f) => f.name && f.name.value === 'listTests') as FieldDefinitionNode; - expect(listTestField.arguments).toHaveLength(3); - expectArguments(listTestField, ['filter', 'nextToken', 'limit']); -}); - -test('that a secondary @key with a single field adds a GSI.', () => { - const validSchema = ` - type Test @model @key(name: "GSI_Email", fields: ["email"], queryField: "testsByEmail") { - id: ID! - email: String! - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - }); - - const out = transformer.transform(validSchema); - let tableResource = out.stacks.Test.Resources.TestTable; - expect(tableResource).toBeDefined(); - expect(tableResource.Properties.GlobalSecondaryIndexes[0].KeySchema[0].AttributeName).toEqual('email'); - expect(tableResource.Properties.GlobalSecondaryIndexes[0].KeySchema[0].KeyType).toEqual('HASH'); - expect(tableResource.Properties.AttributeDefinitions.find((ad) => ad.AttributeName === 'email').AttributeType).toEqual('S'); - const schema = parse(out.schema); - const queryType = schema.definitions.find((def: any) => def.name && def.name.value === 'Query') as ObjectTypeDefinitionNode; - const getField = queryType.fields.find((f) => f.name.value === 'getTest'); - expect(getField.arguments).toHaveLength(1); - expectArguments(getField, ['id']); - const listTestsField = queryType.fields.find((f) => f.name && f.name.value === 'listTests') as FieldDefinitionNode; - expect(listTestsField.arguments).toHaveLength(3); - expectArguments(listTestsField, ['filter', 'nextToken', 'limit']); - const queryIndexField = queryType.fields.find((f) => f.name && f.name.value === 'testsByEmail') as FieldDefinitionNode; - expect(queryIndexField.arguments).toHaveLength(5); - expectArguments(queryIndexField, ['email', 'filter', 'nextToken', 'limit', 'sortDirection']); -}); - -test('that a secondary @key with a multiple field adds an GSI.', () => { - const validSchema = ` - type Test @model @key(fields: ["email", "createdAt"]) - @key(name: "CategoryGSI", fields: ["category", "createdAt"], queryField: "testsByCategory") { - email: String! - createdAt: AWSDateTime! - category: String! - description: String - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - }); - - const out = transformer.transform(validSchema); - let tableResource = out.stacks.Test.Resources.TestTable; - expect(tableResource).toBeDefined(); - expect(tableResource.Properties.GlobalSecondaryIndexes[0].KeySchema[0].AttributeName).toEqual('category'); - expect(tableResource.Properties.GlobalSecondaryIndexes[0].KeySchema[0].KeyType).toEqual('HASH'); - expect(tableResource.Properties.GlobalSecondaryIndexes[0].KeySchema[1].AttributeName).toEqual('createdAt'); - expect(tableResource.Properties.GlobalSecondaryIndexes[0].KeySchema[1].KeyType).toEqual('RANGE'); - expect(tableResource.Properties.AttributeDefinitions.find((ad) => ad.AttributeName === 'email').AttributeType).toEqual('S'); - expect(tableResource.Properties.AttributeDefinitions.find((ad) => ad.AttributeName === 'category').AttributeType).toEqual('S'); - expect(tableResource.Properties.AttributeDefinitions.find((ad) => ad.AttributeName === 'createdAt').AttributeType).toEqual('S'); - const schema = parse(out.schema); - const queryType = schema.definitions.find((def: any) => def.name && def.name.value === 'Query') as ObjectTypeDefinitionNode; - const queryIndexField = queryType.fields.find((f) => f.name && f.name.value === 'testsByCategory') as FieldDefinitionNode; - expect(queryIndexField.arguments).toHaveLength(6); - expectArguments(queryIndexField, ['category', 'createdAt', 'filter', 'nextToken', 'limit', 'sortDirection']); - - // When using a complex primary key args are added to the list field. They are optional and if provided, will use a Query instead of a Scan. - const listTestsField = queryType.fields.find((f) => f.name && f.name.value === 'listTests') as FieldDefinitionNode; - expect(listTestsField.arguments).toHaveLength(6); - expectArguments(listTestsField, ['email', 'createdAt', 'filter', 'nextToken', 'limit', 'sortDirection']); - - // Check the create, update, delete inputs. - const createInput = schema.definitions.find((def: any) => def.name && def.name.value === 'CreateTestInput') as ObjectTypeDefinitionNode; - expectNonNullFields(createInput, ['email', 'category']); - expectNullableFields(createInput, ['description']); - expect(createInput.fields).toHaveLength(4); - const updateInput = schema.definitions.find((def: any) => def.name && def.name.value === 'UpdateTestInput') as ObjectTypeDefinitionNode; - expectNonNullFields(updateInput, ['email', 'createdAt']); - expectNullableFields(updateInput, ['category', 'description']); - expect(updateInput.fields).toHaveLength(4); - const deleteInput = schema.definitions.find((def: any) => def.name && def.name.value === 'DeleteTestInput') as ObjectTypeDefinitionNode; - expectNonNullFields(deleteInput, ['email', 'createdAt']); - expect(deleteInput.fields).toHaveLength(2); -}); - -test('that a secondary @key with a multiple field adds an LSI with GSI FF turned off', () => { - const validSchema = ` - type Test - @model @key(fields: ["email", "createdAt"]) - @key(name: "GSI_Email_UpdatedAt", fields: ["email", "updatedAt"], queryField: "testsByEmailByUpdatedAt") { - email: String! - createdAt: AWSDateTime! - updatedAt: AWSDateTime! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - featureFlags: { - getBoolean: (featureName: string, defaultValue: boolean) => { - if (featureName === 'secondaryKeyAsGSI') return false; - if (featureName === 'improvePluralization') return true; - return defaultValue || false; - }, - } as unknown as FeatureFlagProvider, - }); - - const out = transformer.transform(validSchema); - let tableResource = out.stacks.Test.Resources.TestTable; - expect(tableResource).toBeDefined(); - expect(tableResource.Properties.LocalSecondaryIndexes[0].KeySchema[0].AttributeName).toEqual('email'); - expect(tableResource.Properties.LocalSecondaryIndexes[0].KeySchema[0].KeyType).toEqual('HASH'); - expect(tableResource.Properties.LocalSecondaryIndexes[0].KeySchema[1].AttributeName).toEqual('updatedAt'); - expect(tableResource.Properties.LocalSecondaryIndexes[0].KeySchema[1].KeyType).toEqual('RANGE'); - expect(tableResource.Properties.AttributeDefinitions.find((ad) => ad.AttributeName === 'email').AttributeType).toEqual('S'); - expect(tableResource.Properties.AttributeDefinitions.find((ad) => ad.AttributeName === 'updatedAt').AttributeType).toEqual('S'); - expect(tableResource.Properties.AttributeDefinitions.find((ad) => ad.AttributeName === 'createdAt').AttributeType).toEqual('S'); - const schema = parse(out.schema); - const queryType = schema.definitions.find((def: any) => def.name && def.name.value === 'Query') as ObjectTypeDefinitionNode; - const queryIndexField = queryType.fields.find((f) => f.name && f.name.value === 'testsByEmailByUpdatedAt') as FieldDefinitionNode; - expect(queryIndexField.arguments).toHaveLength(6); - expectArguments(queryIndexField, ['email', 'updatedAt', 'filter', 'nextToken', 'limit', 'sortDirection']); - - // When using a complex primary key args are added to the list field. They are optional and if provided, will use a Query instead of a Scan. - const listTestsField = queryType.fields.find((f) => f.name && f.name.value === 'listTests') as FieldDefinitionNode; - expect(listTestsField.arguments).toHaveLength(6); - expectArguments(listTestsField, ['email', 'createdAt', 'filter', 'nextToken', 'limit', 'sortDirection']); -}); - -test('that a secondary @key with a multiple field adds an GSI based on enabled feature flag.', () => { - const validSchema = ` - type Test - @model @key(fields: ["email", "createdAt"]) - @key(name: "GSI_Email_UpdatedAt", fields: ["email", "updatedAt"], queryField: "testsByEmailByUpdatedAt") { - email: String! - createdAt: AWSDateTime! - updatedAt: AWSDateTime! - } - `; - - const transformer = new GraphQLTransform({ - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - featureFlags: { - getBoolean: (featureName: string, defaultValue: boolean) => { - if (featureName === 'secondaryKeyAsGSI') return true; - if (featureName === 'improvePluralization') return true; - return defaultValue || false; - }, - } as unknown as FeatureFlagProvider, - }); - - const out = transformer.transform(validSchema); - let tableResource = out.stacks.Test.Resources.TestTable; - expect(tableResource).toBeDefined(); - expect(tableResource.Properties.GlobalSecondaryIndexes[0].KeySchema[0].AttributeName).toEqual('email'); - expect(tableResource.Properties.GlobalSecondaryIndexes[0].KeySchema[0].KeyType).toEqual('HASH'); - expect(tableResource.Properties.GlobalSecondaryIndexes[0].KeySchema[1].AttributeName).toEqual('updatedAt'); - expect(tableResource.Properties.GlobalSecondaryIndexes[0].KeySchema[1].KeyType).toEqual('RANGE'); - expect(tableResource.Properties.AttributeDefinitions.find((ad) => ad.AttributeName === 'email').AttributeType).toEqual('S'); - expect(tableResource.Properties.AttributeDefinitions.find((ad) => ad.AttributeName === 'updatedAt').AttributeType).toEqual('S'); - expect(tableResource.Properties.AttributeDefinitions.find((ad) => ad.AttributeName === 'createdAt').AttributeType).toEqual('S'); - const schema = parse(out.schema); - const queryType = schema.definitions.find((def: any) => def.name && def.name.value === 'Query') as ObjectTypeDefinitionNode; - const queryIndexField = queryType.fields.find((f) => f.name && f.name.value === 'testsByEmailByUpdatedAt') as FieldDefinitionNode; - expect(queryIndexField.arguments).toHaveLength(6); - expectArguments(queryIndexField, ['email', 'updatedAt', 'filter', 'nextToken', 'limit', 'sortDirection']); - - // When using a complex primary key args are added to the list field. They are optional and if provided, will use a Query instead of a Scan. - const listTestsField = queryType.fields.find((f) => f.name && f.name.value === 'listTests') as FieldDefinitionNode; - expect(listTestsField.arguments).toHaveLength(6); - expectArguments(listTestsField, ['email', 'createdAt', 'filter', 'nextToken', 'limit', 'sortDirection']); -}); - -test('that a primary @key with complex fields will update the input objects.', () => { - const validSchema = ` - type Test @model @key(fields: ["email"]) { - email: String! - listInput: [String] - nonNullListInput: [String]! - nonNullListInputOfNonNullStrings: [String!]! - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - }); - - const out = transformer.transform(validSchema); - let tableResource = out.stacks.Test.Resources.TestTable; - expect(tableResource).toBeDefined(); - expect(tableResource.Properties.KeySchema[0].AttributeName).toEqual('email'); - expect(tableResource.Properties.KeySchema[0].KeyType).toEqual('HASH'); - expect(tableResource.Properties.AttributeDefinitions[0].AttributeType).toEqual('S'); - const schema = parse(out.schema); - const createInput = schema.definitions.find( - (def: any) => def.name && def.name.value === 'CreateTestInput', - ) as InputObjectTypeDefinitionNode; - const updateInput = schema.definitions.find( - (def: any) => def.name && def.name.value === 'UpdateTestInput', - ) as InputObjectTypeDefinitionNode; - const deleteInput = schema.definitions.find( - (def: any) => def.name && def.name.value === 'DeleteTestInput', - ) as InputObjectTypeDefinitionNode; - expect(createInput).toBeDefined(); - expectNonNullInputValues(createInput, ['email', 'nonNullListInput', 'nonNullListInputOfNonNullStrings']); - expectNullableInputValues(createInput, ['listInput']); - expectInputValueToHandle(createInput, (f: any) => { - if (f.name.value === 'nonNullListInputOfNonNullStrings') { - return f.type.kind === Kind.NON_NULL_TYPE && f.type.type.kind === Kind.LIST_TYPE && f.type.type.type.kind === Kind.NON_NULL_TYPE; - } else if (f.name.value === 'nonNullListInput') { - return f.type.kind === Kind.NON_NULL_TYPE && f.type.type.kind === Kind.LIST_TYPE; - } else if (f.name.value === 'listInput') { - return f.type.kind === Kind.LIST_TYPE; - } - return true; - }); - - expectNonNullInputValues(updateInput, ['email']); - expectNullableInputValues(updateInput, ['listInput', 'nonNullListInput', 'nonNullListInputOfNonNullStrings']); - expectInputValueToHandle(updateInput, (f: any) => { - if (f.name.value === 'nonNullListInputOfNonNullStrings') { - return f.type.kind === Kind.LIST_TYPE && f.type.type.kind === Kind.NON_NULL_TYPE; - } else if (f.name.value === 'nonNullListInput') { - return f.type.kind === Kind.LIST_TYPE; - } else if (f.name.value === 'listInput') { - return f.type.kind === Kind.LIST_TYPE; - } - return true; - }); - - expectNonNullInputValues(deleteInput, ['email']); -}); - -test('that connection type is generated for custom query when queries is set to null.', () => { - const validSchema = ` - type ContentCategory @model(queries: null, mutations: { create: "addContentToCategory", delete: "deleteContentFromCategory"}) - @key(name: "ContentByCategory", fields: ["category", "type", "language", "datetime"], queryField: "listContentByCategory") - { - id: ID! - category: Int! - datetime: String! - type: String! - language: String! - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [new DynamoDBModelTransformer(), new KeyTransformer()], - }); - - const out = transformer.transform(validSchema); - const schema = parse(out.schema); - const modelContentCategoryConnection = schema.definitions.find( - (def: any) => def.name && def.name.value === 'ModelContentCategoryConnection', - ) as ObjectTypeDefinitionNode; - - expect(modelContentCategoryConnection).toBeDefined(); -}); diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/KeyWithAuth.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/KeyWithAuth.e2e.test.ts deleted file mode 100644 index 6e2e81e2ca..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/KeyWithAuth.e2e.test.ts +++ /dev/null @@ -1,376 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { KeyTransformer } from 'graphql-key-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as CognitoClient } from 'aws-sdk/clients/cognitoidentityserviceprovider'; -import { default as S3 } from 'aws-sdk/clients/s3'; -import { default as moment } from 'moment'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { GraphQLClient } from '../GraphQLClient'; -import { S3Client } from '../S3Client'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { - createUserPool, - createUserPoolClient, - createGroup, - addUserToGroup, - configureAmplify, - signupUser, - authenticateUser, -} from '../cognitoUtils'; -import 'isomorphic-fetch'; - -// to deal with bug in cognito-identity-js -(global as any).fetch = require('node-fetch'); - -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `KeyWithAuth-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `appsync-key-with-auth-test-bucket-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/key_auth_transform_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; - -let GRAPHQL_ENDPOINT = undefined; - -/** - * Client 1 is logged in and is a member of the Admin group. - */ -let GRAPHQL_CLIENT_1 = undefined; - -/** - * Client 1 is logged in and is a member of the Admin group via an access token. - */ -let GRAPHQL_CLIENT_1_ACCESS = undefined; - -/** - * Client 2 is logged in and is a member of the Devs group. - */ -let GRAPHQL_CLIENT_2 = undefined; - -/** - * Client 3 is logged in and has no group memberships. - */ -let GRAPHQL_CLIENT_3 = undefined; - -let USER_POOL_ID = undefined; - -const USERNAME1 = 'user1@test.com'; -const USERNAME2 = 'user2@test.com'; -const USERNAME3 = 'user3@test.com'; -const TMP_PASSWORD = 'Password123!'; -const REAL_PASSWORD = 'Password1234!'; - -const ADMIN_GROUP_NAME = 'Admin'; -const DEVS_GROUP_NAME = 'Devs'; -const PARTICIPANT_GROUP_NAME = 'Participant'; -const WATCHER_GROUP_NAME = 'Watcher'; - -const cognitoClient = new CognitoClient({ apiVersion: '2016-04-19', region: region }); -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -function deleteDirectory(directory: string) { - const files = fs.readdirSync(directory); - for (const file of files) { - const contentPath = path.join(directory, file); - if (fs.lstatSync(contentPath).isDirectory()) { - deleteDirectory(contentPath); - fs.rmdirSync(contentPath); - } else { - fs.unlinkSync(contentPath); - } - } -} - -beforeAll(async () => { - // Create a stack for the post model with auth enabled. - const validSchema = ` - type Order - @model - @key(fields: ["customerEmail", "orderId"]) - @key(name: "GSI", fields: ["orderId"], queryField: "ordersByOrderId") - @auth(rules: [{ allow: owner, ownerField: "customerEmail" }, { allow: groups, groups: ["Admin"] }]) - { - customerEmail: String! - createdAt: AWSDateTime - orderId: String! - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new KeyTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - try { - await awsS3Client.createBucket({ Bucket: BUCKET_NAME }).promise(); - } catch (e) { - console.error(`Failed to create bucket: ${e}`); - } - const userPoolResponse = await createUserPool(cognitoClient, `UserPool${STACK_NAME}`); - USER_POOL_ID = userPoolResponse.UserPool.Id; - const userPoolClientResponse = await createUserPoolClient(cognitoClient, USER_POOL_ID, `UserPool${STACK_NAME}`); - const userPoolClientId = userPoolClientResponse.UserPoolClient.ClientId; - try { - // Clean the bucket - const out = transformer.transform(validSchema); - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { AuthCognitoUserPoolId: USER_POOL_ID }, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - GRAPHQL_ENDPOINT = getApiEndpoint(finishedStack.Outputs); - - const apiKey = getApiKey(finishedStack.Outputs); - expect(apiKey).not.toBeTruthy(); - - // Verify we have all the details - expect(GRAPHQL_ENDPOINT).toBeTruthy(); - expect(USER_POOL_ID).toBeTruthy(); - expect(userPoolClientId).toBeTruthy(); - - // Configure Amplify, create users, and sign in. - configureAmplify(USER_POOL_ID, userPoolClientId); - - await signupUser(USER_POOL_ID, USERNAME1, TMP_PASSWORD); - await signupUser(USER_POOL_ID, USERNAME2, TMP_PASSWORD); - await signupUser(USER_POOL_ID, USERNAME3, TMP_PASSWORD); - await createGroup(USER_POOL_ID, ADMIN_GROUP_NAME); - await createGroup(USER_POOL_ID, PARTICIPANT_GROUP_NAME); - await createGroup(USER_POOL_ID, WATCHER_GROUP_NAME); - await createGroup(USER_POOL_ID, DEVS_GROUP_NAME); - await addUserToGroup(ADMIN_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(PARTICIPANT_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(WATCHER_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(DEVS_GROUP_NAME, USERNAME2, USER_POOL_ID); - const authResAfterGroup: any = await authenticateUser(USERNAME1, TMP_PASSWORD, REAL_PASSWORD); - - const idToken = authResAfterGroup.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_1 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken }); - - const accessToken = authResAfterGroup.getAccessToken().getJwtToken(); - GRAPHQL_CLIENT_1_ACCESS = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: accessToken }); - - const authRes2AfterGroup: any = await authenticateUser(USERNAME2, TMP_PASSWORD, REAL_PASSWORD); - const idToken2 = authRes2AfterGroup.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_2 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken2 }); - - const authRes3: any = await authenticateUser(USERNAME3, TMP_PASSWORD, REAL_PASSWORD); - const idToken3 = authRes3.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_3 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken3 }); - - // Wait for any propagation to avoid random - // "The security token included in the request is invalid" errors - await new Promise((res) => setTimeout(() => res(), 5000)); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf, { cognitoClient, userPoolId: USER_POOL_ID }); -}); - -/** - * Test queries below - */ -test('createOrder mutation as admin', async () => { - const response = await createOrder(GRAPHQL_CLIENT_1, USERNAME2, 'order1'); - expect(response.data.createOrder.customerEmail).toBeDefined(); - expect(response.data.createOrder.orderId).toEqual('order1'); - expect(response.data.createOrder.createdAt).toBeDefined(); -}); - -test('createOrder mutation as owner', async () => { - const response = await createOrder(GRAPHQL_CLIENT_2, USERNAME2, 'order2'); - expect(response.data.createOrder.customerEmail).toBeDefined(); - expect(response.data.createOrder.orderId).toEqual('order2'); - expect(response.data.createOrder.createdAt).toBeDefined(); -}); - -test('createOrder mutation as owner', async () => { - const response = await createOrder(GRAPHQL_CLIENT_3, USERNAME2, 'order3'); - expect(response.data.createOrder).toBeNull(); - expect(response.errors).toHaveLength(1); -}); - -test('list orders as owner', async () => { - await createOrder(GRAPHQL_CLIENT_3, USERNAME3, 'owned1'); - await createOrder(GRAPHQL_CLIENT_3, USERNAME3, 'owned2'); - const listResponse = await listOrders(GRAPHQL_CLIENT_3, USERNAME3, { beginsWith: 'owned' }); - expect(listResponse.data.listOrders.items).toHaveLength(2); -}); - -test('list orders as non owner', async () => { - await createOrder(GRAPHQL_CLIENT_3, USERNAME3, 'unowned1'); - await createOrder(GRAPHQL_CLIENT_3, USERNAME3, 'unowned2'); - const listResponse = await listOrders(GRAPHQL_CLIENT_2, USERNAME3, { beginsWith: 'unowned' }); - expect(listResponse.data.listOrders.items).toHaveLength(0); -}); - -test('get orders as owner', async () => { - await createOrder(GRAPHQL_CLIENT_2, USERNAME2, 'myobj'); - const getResponse = await getOrder(GRAPHQL_CLIENT_2, USERNAME2, 'myobj'); - expect(getResponse.data.getOrder.orderId).toEqual('myobj'); -}); - -test('get orders as non-owner', async () => { - await createOrder(GRAPHQL_CLIENT_2, USERNAME2, 'notmyobj'); - const getResponse = await getOrder(GRAPHQL_CLIENT_3, USERNAME2, 'notmyobj'); - expect(getResponse.data.getOrder).toBeNull(); - expect(getResponse.errors).toHaveLength(1); -}); - -test('query orders as owner', async () => { - await createOrder(GRAPHQL_CLIENT_3, USERNAME3, 'ownedby3a'); - const listResponse = await ordersByOrderId(GRAPHQL_CLIENT_3, 'ownedby3a'); - expect(listResponse.data.ordersByOrderId.items).toHaveLength(1); -}); - -test('query orders as non owner', async () => { - await createOrder(GRAPHQL_CLIENT_3, USERNAME3, 'notownedby2a'); - const listResponse = await ordersByOrderId(GRAPHQL_CLIENT_2, 'notownedby2a'); - expect(listResponse.data.ordersByOrderId.items).toHaveLength(0); -}); - -async function createOrder(client: GraphQLClient, customerEmail: string, orderId: string) { - const result = await client.query( - `mutation CreateOrder($input: CreateOrderInput!) { - createOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, orderId }, - }, - ); - return result; -} - -async function updateOrder(client: GraphQLClient, customerEmail: string, orderId: string) { - const result = await client.query( - `mutation UpdateOrder($input: UpdateOrderInput!) { - updateOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, orderId }, - }, - ); - return result; -} - -async function deleteOrder(client: GraphQLClient, customerEmail: string, orderId: string) { - const result = await client.query( - `mutation DeleteOrder($input: DeleteOrderInput!) { - deleteOrder(input: $input) { - customerEmail - orderId - createdAt - } - }`, - { - input: { customerEmail, orderId }, - }, - ); - return result; -} - -async function getOrder(client: GraphQLClient, customerEmail: string, orderId: string) { - const result = await client.query( - `query GetOrder($customerEmail: String!, $orderId: String!) { - getOrder(customerEmail: $customerEmail, orderId: $orderId) { - customerEmail - orderId - createdAt - } - }`, - { customerEmail, orderId }, - ); - return result; -} - -async function listOrders(client: GraphQLClient, customerEmail: string, orderId: { beginsWith: string }) { - const result = await client.query( - `query ListOrder($customerEmail: String, $orderId: ModelStringKeyConditionInput) { - listOrders(customerEmail: $customerEmail, orderId: $orderId) { - items { - customerEmail - orderId - createdAt - } - nextToken - } - }`, - { customerEmail, orderId }, - ); - return result; -} - -async function ordersByOrderId(client: GraphQLClient, orderId: string) { - const result = await client.query( - `query OrdersByOrderId($orderId: String!) { - ordersByOrderId(orderId: $orderId) { - items { - customerEmail - orderId - createdAt - } - nextToken - } - }`, - { orderId }, - ); - return result; -} diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/ModelAuthTransformer.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/ModelAuthTransformer.e2e.test.ts deleted file mode 100644 index ffe4683ce7..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/ModelAuthTransformer.e2e.test.ts +++ /dev/null @@ -1,3333 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { KeyTransformer } from 'graphql-key-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as CognitoClient } from 'aws-sdk/clients/cognitoidentityserviceprovider'; -import { default as S3 } from 'aws-sdk/clients/s3'; -import { default as moment } from 'moment'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { GraphQLClient } from '../GraphQLClient'; -import { S3Client } from '../S3Client'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { - createUserPool, - createUserPoolClient, - createGroup, - addUserToGroup, - configureAmplify, - signupUser, - authenticateUser, -} from '../cognitoUtils'; -import 'isomorphic-fetch'; - -// to deal with bug in cognito-identity-js -(global as any).fetch = require('node-fetch'); - -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -describe(`ModelAuthTests`, () => { - const cf = new CloudFormationClient(region); - - const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); - const STACK_NAME = `ModelAuthTransformerTest-${BUILD_TIMESTAMP}`; - const BUCKET_NAME = `appsync-auth-transformer-test-bucket-${BUILD_TIMESTAMP}`; - const LOCAL_FS_BUILD_DIR = '/tmp/model_auth_transform_tests/'; - const S3_ROOT_DIR_KEY = 'deployments'; - - let GRAPHQL_ENDPOINT = undefined; - - /** - * Client 1 is logged in and is a member of the Admin group. - */ - let GRAPHQL_CLIENT_1: GraphQLClient = undefined; - - /** - * Client 1 is logged in and is a member of the Admin group via an access token. - */ - let GRAPHQL_CLIENT_1_ACCESS: GraphQLClient = undefined; - - /** - * Client 2 is logged in and is a member of the Devs group. - */ - let GRAPHQL_CLIENT_2: GraphQLClient = undefined; - - /** - * Client 3 is logged in and is a member of the Devs-Admin group via an access token. - */ - let GRAPHQL_CLIENT_3: GraphQLClient = undefined; - - let USER_POOL_ID = undefined; - - const USERNAME1 = 'user1@test.com'; - const USERNAME2 = 'user2@test.com'; - const USERNAME3 = 'user3@test.com'; - const TMP_PASSWORD = 'Password123!'; - const REAL_PASSWORD = 'Password1234!'; - - const ADMIN_GROUP_NAME = 'Admin'; - const DEVS_GROUP_NAME = 'Devs'; - const DEVS_ADMIN_GROUP_NAME = 'Devs-Admin'; - const PARTICIPANT_GROUP_NAME = 'Participant'; - const WATCHER_GROUP_NAME = 'Watcher'; - - const cognitoClient = new CognitoClient({ apiVersion: '2016-04-19', region: region }); - const customS3Client = new S3Client(region); - const awsS3Client = new S3({ region: region }); - - function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; - } - - function deleteDirectory(directory: string) { - const files = fs.readdirSync(directory); - for (const file of files) { - const contentPath = path.join(directory, file); - if (fs.lstatSync(contentPath).isDirectory()) { - deleteDirectory(contentPath); - fs.rmdirSync(contentPath); - } else { - fs.unlinkSync(contentPath); - } - } - } - - beforeAll(async () => { - // Create a stack for the post model with auth enabled. - const validSchema = ` - type Post @model @auth(rules: [{ allow: owner }]) { - id: ID! - title: String! - createdAt: AWSDateTime - updatedAt: AWSDateTime - owner: String - } - type Salary @model @auth( - rules: [ - {allow: owner}, - {allow: groups, groups: ["Admin"]} - ] - ) { - id: ID! - wage: Int - owner: String - } - type AdminNote @model @auth( - rules: [ - {allow: groups, groups: ["Admin"], groupClaim: "cognito:groups"} - ] - ) { - id: ID! - content: String! - } - type ManyGroupProtected @model @auth(rules: [{allow: groups, groupsField: "groups"}]) { - id: ID! - value: Int - groups: [String] - } - type SingleGroupProtected @model @auth(rules: [{allow: groups, groupsField: "group"}]) { - id: ID! - value: Int - group: String - } - type PWProtected - @auth(rules: [ - {allow: groups, groupsField: "participants", mutations: [update, delete], queries: [get, list]}, - {allow: groups, groupsField: "watchers", mutations: [], queries: [get, list]} - ]) - @model - { - id: ID! - content: String! - participants: String - watchers: String - } - type AllThree - @auth(rules: [ - {allow: owner, identityField: "username" }, - {allow: owner, ownerField: "editors", identityField: "cognito:username" }, - {allow: groups, groups: ["Admin"]}, - {allow: groups, groups: ["Execs"]}, - {allow: groups, groupsField: "groups"}, - {allow: groups, groupsField: "alternativeGroup"} - ]) - @model - { - id: ID! - owner: String - editors: [String] - groups: [String] - alternativeGroup: String - } - # The owner should always start with https://cognito-idp - type TestIdentity @model @auth(rules: [{ allow: owner, identityField: "iss" }]) { - id: ID! - title: String! - owner: String - } - type OwnerReadProtected @model @auth(rules: [{ allow: owner, operations: [read] }]) @key(fields: ["id", "sk"]) { - id: ID! - sk: String! - content: String - owner: String - } - type OwnerCreateUpdateDeleteProtected @model @auth(rules: [{ allow: owner, operations: [create, update, delete] }]) { - id: ID! - content: String - owner: String - } - type Performance @model @auth(rules: [{ allow: groups, groups: ["Admin"]}, { allow: private, operations: [read] }]) { - id: ID - performer: String! - description: String! - time: AWSDateTime - stage: Stage @connection - } - type Stage @model @auth(rules: [{ allow: groups, groups: ["Admin"]}, { allow: private, operations: [read] }]) { - id: ID! - name: String! - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelConnectionTransformer(), - new KeyTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - try { - await awsS3Client.createBucket({ Bucket: BUCKET_NAME }).promise(); - } catch (e) { - console.error(`Failed to create bucket: ${e}`); - } - const userPoolResponse = await createUserPool(cognitoClient, `UserPool${STACK_NAME}`); - USER_POOL_ID = userPoolResponse.UserPool.Id; - const userPoolClientResponse = await createUserPoolClient(cognitoClient, USER_POOL_ID, `UserPool${STACK_NAME}`); - const userPoolClientId = userPoolClientResponse.UserPoolClient.ClientId; - try { - // Clean the bucket - const out = transformer.transform(validSchema); - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { AuthCognitoUserPoolId: USER_POOL_ID }, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - GRAPHQL_ENDPOINT = getApiEndpoint(finishedStack.Outputs); - - const apiKey = getApiKey(finishedStack.Outputs); - expect(apiKey).not.toBeTruthy(); - - // Verify we have all the details - expect(GRAPHQL_ENDPOINT).toBeTruthy(); - expect(USER_POOL_ID).toBeTruthy(); - expect(userPoolClientId).toBeTruthy(); - - // Configure Amplify, create users, and sign in. - configureAmplify(USER_POOL_ID, userPoolClientId); - - await signupUser(USER_POOL_ID, USERNAME1, TMP_PASSWORD); - await signupUser(USER_POOL_ID, USERNAME2, TMP_PASSWORD); - await signupUser(USER_POOL_ID, USERNAME3, TMP_PASSWORD); - await createGroup(USER_POOL_ID, ADMIN_GROUP_NAME); - await createGroup(USER_POOL_ID, PARTICIPANT_GROUP_NAME); - await createGroup(USER_POOL_ID, WATCHER_GROUP_NAME); - await createGroup(USER_POOL_ID, DEVS_GROUP_NAME); - await createGroup(USER_POOL_ID, DEVS_ADMIN_GROUP_NAME); - await addUserToGroup(ADMIN_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(PARTICIPANT_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(WATCHER_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(DEVS_GROUP_NAME, USERNAME2, USER_POOL_ID); - await addUserToGroup(DEVS_ADMIN_GROUP_NAME, USERNAME3, USER_POOL_ID); - const authResAfterGroup: any = await authenticateUser(USERNAME1, TMP_PASSWORD, REAL_PASSWORD); - - const idToken = authResAfterGroup.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_1 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken }); - - const accessToken = authResAfterGroup.getAccessToken().getJwtToken(); - GRAPHQL_CLIENT_1_ACCESS = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: accessToken }); - - const authRes2AfterGroup: any = await authenticateUser(USERNAME2, TMP_PASSWORD, REAL_PASSWORD); - const idToken2 = authRes2AfterGroup.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_2 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken2 }); - - const authRes3AfterGroup: any = await authenticateUser(USERNAME3, TMP_PASSWORD, REAL_PASSWORD); - const idToken3 = authRes3AfterGroup.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_3 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken3 }); - - // Wait for any propagation to avoid random - // "The security token included in the request is invalid" errors - await new Promise((res) => setTimeout(() => res(), 5000)); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } - }); - - afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf, { cognitoClient, userPoolId: USER_POOL_ID }); - }); - - /** - * Test queries below - */ - test('createPost mutation', async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.owner).toEqual(USERNAME1); - - const response2 = await GRAPHQL_CLIENT_1_ACCESS.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(response2.data.createPost.id).toBeDefined(); - expect(response2.data.createPost.title).toEqual('Hello, World!'); - expect(response2.data.createPost.createdAt).toBeDefined(); - expect(response2.data.createPost.updatedAt).toBeDefined(); - expect(response2.data.createPost.owner).toEqual(USERNAME1); - }); - - test('getPost query when authorized', async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.owner).toEqual(USERNAME1); - const getResponse = await GRAPHQL_CLIENT_1.query( - `query { - getPost(id: "${response.data.createPost.id}") { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(getResponse.data.getPost.id).toBeDefined(); - expect(getResponse.data.getPost.title).toEqual('Hello, World!'); - expect(getResponse.data.getPost.createdAt).toBeDefined(); - expect(getResponse.data.getPost.updatedAt).toBeDefined(); - expect(getResponse.data.getPost.owner).toEqual(USERNAME1); - - const getResponseAccess = await GRAPHQL_CLIENT_1_ACCESS.query( - `query { - getPost(id: "${response.data.createPost.id}") { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(getResponseAccess.data.getPost.id).toBeDefined(); - expect(getResponseAccess.data.getPost.title).toEqual('Hello, World!'); - expect(getResponseAccess.data.getPost.createdAt).toBeDefined(); - expect(getResponseAccess.data.getPost.updatedAt).toBeDefined(); - expect(getResponseAccess.data.getPost.owner).toEqual(USERNAME1); - }); - - test('getPost query when not authorized', async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.owner).toBeDefined(); - const getResponse = await GRAPHQL_CLIENT_2.query( - `query { - getPost(id: "${response.data.createPost.id}") { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(getResponse.data.getPost).toEqual(null); - expect(getResponse.errors.length).toEqual(1); - expect((getResponse.errors[0] as any).errorType).toEqual('Unauthorized'); - }); - - test('updatePost mutation when authorized', async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.owner).toEqual(USERNAME1); - const updateResponse = await GRAPHQL_CLIENT_1.query( - `mutation { - updatePost(input: { id: "${response.data.createPost.id}", title: "Bye, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(updateResponse.data.updatePost.id).toEqual(response.data.createPost.id); - expect(updateResponse.data.updatePost.title).toEqual('Bye, World!'); - expect(updateResponse.data.updatePost.updatedAt > response.data.createPost.updatedAt).toEqual(true); - - const updateResponseAccess = await GRAPHQL_CLIENT_1_ACCESS.query( - `mutation { - updatePost(input: { id: "${response.data.createPost.id}", title: "Bye, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(updateResponseAccess.data.updatePost.id).toEqual(response.data.createPost.id); - expect(updateResponseAccess.data.updatePost.title).toEqual('Bye, World!'); - expect(updateResponseAccess.data.updatePost.updatedAt > response.data.createPost.updatedAt).toEqual(true); - }); - - test('updatePost mutation when not authorized', async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.owner).toBeDefined(); - const updateResponse = await GRAPHQL_CLIENT_2.query( - `mutation { - updatePost(input: { id: "${response.data.createPost.id}", title: "Bye, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(updateResponse.data.updatePost).toEqual(null); - expect(updateResponse.errors.length).toEqual(1); - expect((updateResponse.errors[0] as any).data).toBeNull(); - expect((updateResponse.errors[0] as any).errorType).toEqual('DynamoDB:ConditionalCheckFailedException'); - }); - - test('deletePost mutation when authorized', async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.owner).toEqual(USERNAME1); - const deleteResponse = await GRAPHQL_CLIENT_1.query( - `mutation { - deletePost(input: { id: "${response.data.createPost.id}" }) { - id - } - }`, - {}, - ); - expect(deleteResponse.data.deletePost.id).toEqual(response.data.createPost.id); - - const responseAccess = await GRAPHQL_CLIENT_1_ACCESS.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(responseAccess.data.createPost.id).toBeDefined(); - expect(responseAccess.data.createPost.title).toEqual('Hello, World!'); - expect(responseAccess.data.createPost.createdAt).toBeDefined(); - expect(responseAccess.data.createPost.updatedAt).toBeDefined(); - expect(responseAccess.data.createPost.owner).toEqual(USERNAME1); - const deleteResponseAccess = await GRAPHQL_CLIENT_1_ACCESS.query( - `mutation { - deletePost(input: { id: "${responseAccess.data.createPost.id}" }) { - id - } - }`, - {}, - ); - expect(deleteResponseAccess.data.deletePost.id).toEqual(responseAccess.data.createPost.id); - }); - - test('deletePost mutation when not authorized', async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.owner).toEqual(USERNAME1); - const deleteResponse = await GRAPHQL_CLIENT_2.query( - `mutation { - deletePost(input: { id: "${response.data.createPost.id}" }) { - id - } - }`, - {}, - ); - expect(deleteResponse.data.deletePost).toEqual(null); - expect(deleteResponse.errors.length).toEqual(1); - expect((deleteResponse.errors[0] as any).data).toBeNull(); - expect((deleteResponse.errors[0] as any).errorType).toEqual('DynamoDB:ConditionalCheckFailedException'); - }); - - test('listPosts query when authorized', async () => { - const firstPost = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "testing list" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - expect(firstPost.data.createPost.id).toBeDefined(); - expect(firstPost.data.createPost.title).toEqual('testing list'); - expect(firstPost.data.createPost.createdAt).toBeDefined(); - expect(firstPost.data.createPost.updatedAt).toBeDefined(); - expect(firstPost.data.createPost.owner).toEqual(USERNAME1); - const secondPost = await GRAPHQL_CLIENT_2.query( - `mutation { - createPost(input: { title: "testing list" }) { - id - title - createdAt - updatedAt - owner - } - }`, - {}, - ); - // There are two posts but only 1 created by me. - const listResponse = await GRAPHQL_CLIENT_1.query( - `query { - listPosts(filter: { title: { eq: "testing list" } }, limit: 25) { - items { - id - } - } - }`, - {}, - ); - expect(listResponse.data.listPosts.items.length).toEqual(1); - - const listResponseAccess = await GRAPHQL_CLIENT_1_ACCESS.query( - `query { - listPosts(filter: { title: { eq: "testing list" } }, limit: 25) { - items { - id - } - } - }`, - {}, - ); - expect(listResponseAccess.data.listPosts.items.length).toEqual(1); - }); - - /** - * Static Group Auth - */ - test(`createSalary w/ Admin group protection authorized`, async () => { - const req = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createSalary(input: { wage: 10 }) { - id - wage - } - } - `, - {}, - ); - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(10); - }); - - test(`update my own salary without admin permission`, async () => { - const req = await GRAPHQL_CLIENT_2.query( - ` - mutation { - createSalary(input: { wage: 10 }) { - id - wage - } - } - `, - {}, - ); - - expect(req.data.createSalary.wage).toEqual(10); - const req2 = await GRAPHQL_CLIENT_2.query( - ` - mutation { - updateSalary(input: { id: "${req.data.createSalary.id}", wage: 14 }) { - id - wage - } - } - `, - {}, - ); - - expect(req2.data.updateSalary.wage).toEqual(14); - }); - - test(`updating someone else's salary as an admin`, async () => { - const req = await GRAPHQL_CLIENT_2.query( - ` - mutation { - createSalary(input: { wage: 11 }) { - id - wage - } - } - `, - {}, - ); - - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(11); - const req2 = await GRAPHQL_CLIENT_1.query( - ` - mutation { - updateSalary(input: { id: "${req.data.createSalary.id}", wage: 12 }) { - id - wage - } - } - `, - {}, - ); - - expect(req2.data.updateSalary.id).toEqual(req.data.createSalary.id); - expect(req2.data.updateSalary.wage).toEqual(12); - }); - - test(`updating someone else's salary when I am not admin.`, async () => { - const req = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createSalary(input: { wage: 13 }) { - id - wage - } - } - `, - {}, - ); - - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(13); - const req2 = await GRAPHQL_CLIENT_2.query( - ` - mutation { - updateSalary(input: { id: "${req.data.createSalary.id}", wage: 14 }) { - id - wage - } - } - `, - {}, - ); - expect(req2.data.updateSalary).toEqual(null); - expect(req2.errors.length).toEqual(1); - expect((req2.errors[0] as any).data).toBeNull(); - expect((req2.errors[0] as any).errorType).toEqual('DynamoDB:ConditionalCheckFailedException'); - }); - - test(`deleteSalary w/ Admin group protection authorized`, async () => { - const req = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createSalary(input: { wage: 15 }) { - id - wage - } - } - `, - {}, - ); - - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(15); - const req2 = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteSalary(input: { id: "${req.data.createSalary.id}" }) { - id - wage - } - } - `, - {}, - ); - - expect(req2.data.deleteSalary.id).toEqual(req.data.createSalary.id); - expect(req2.data.deleteSalary.wage).toEqual(15); - }); - - test(`deleteSalary w/ Admin group protection not authorized`, async () => { - const req = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createSalary(input: { wage: 16 }) { - id - wage - } - } - `, - {}, - ); - - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(16); - const req2 = await GRAPHQL_CLIENT_2.query( - ` - mutation { - deleteSalary(input: { id: "${req.data.createSalary.id}" }) { - id - wage - } - } - `, - {}, - ); - expect(req2.data.deleteSalary).toEqual(null); - expect(req2.errors.length).toEqual(1); - expect((req2.errors[0] as any).data).toBeNull(); - expect((req2.errors[0] as any).errorType).toEqual('DynamoDB:ConditionalCheckFailedException'); - }); - - test(`and Admin can get a salary created by any user`, async () => { - const req = await GRAPHQL_CLIENT_2.query( - ` - mutation { - createSalary(input: { wage: 15 }) { - id - wage - } - } - `, - {}, - ); - - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(15); - const req2 = await GRAPHQL_CLIENT_1.query( - ` - query { - getSalary(id: "${req.data.createSalary.id}") { - id - wage - } - } - `, - {}, - ); - expect(req2.data.getSalary.id).toEqual(req.data.createSalary.id); - expect(req2.data.getSalary.wage).toEqual(15); - }); - - test(`owner can create and get a salary when not admin`, async () => { - const req = await GRAPHQL_CLIENT_2.query( - ` - mutation { - createSalary(input: { wage: 15 }) { - id - wage - } - } - `, - {}, - ); - - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(15); - const req2 = await GRAPHQL_CLIENT_2.query( - ` - query { - getSalary(id: "${req.data.createSalary.id}") { - id - wage - } - } - `, - {}, - ); - expect(req2.data.getSalary.id).toEqual(req.data.createSalary.id); - expect(req2.data.getSalary.wage).toEqual(15); - }); - - test(`getSalary w/ Admin group protection not authorized`, async () => { - const req = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createSalary(input: { wage: 16 }) { - id - wage - } - } - `, - {}, - ); - - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(16); - const req2 = await GRAPHQL_CLIENT_2.query( - ` - query { - getSalary(id: "${req.data.createSalary.id}") { - id - wage - } - } - `, - {}, - ); - expect(req2.data.getSalary).toEqual(null); - expect(req2.errors.length).toEqual(1); - expect((req2.errors[0] as any).errorType).toEqual('Unauthorized'); - }); - - test(`listSalaries w/ Admin group protection authorized`, async () => { - const req = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createSalary(input: { wage: 101 }) { - id - wage - } - } - `, - {}, - ); - - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(101); - const req2 = await GRAPHQL_CLIENT_1.query( - ` - query { - listSalaries(filter: { wage: { eq: 101 }}) { - items { - id - wage - } - } - } - `, - {}, - ); - expect(req2.data.listSalaries.items.length).toEqual(1); - expect(req2.data.listSalaries.items[0].id).toEqual(req.data.createSalary.id); - expect(req2.data.listSalaries.items[0].wage).toEqual(101); - }); - - test(`listSalaries w/ Admin group protection not authorized`, async () => { - const req = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createSalary(input: { wage: 102 }) { - id - wage - } - } - `, - {}, - ); - - expect(req.data.createSalary.id).toBeDefined(); - expect(req.data.createSalary.wage).toEqual(102); - const req2 = await GRAPHQL_CLIENT_2.query( - ` - query { - listSalaries(filter: { wage: { eq: 102 }}) { - items { - id - wage - } - } - } - `, - {}, - ); - expect(req2.data.listSalaries.items).toEqual([]); - }); - - /** - * Dynamic Group Auth - */ - test(`createManyGroupProtected w/ dynamic group protection authorized`, async () => { - const req = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createManyGroupProtected(input: { value: 10, groups: ["Admin"] }) { - id - value - groups - } - } - `, - {}, - ); - - expect(req.data.createManyGroupProtected.id).toBeDefined(); - expect(req.data.createManyGroupProtected.value).toEqual(10); - expect(req.data.createManyGroupProtected.groups).toEqual(['Admin']); - }); - - test(`createManyGroupProtected w/ dynamic group protection when not authorized`, async () => { - const req = await GRAPHQL_CLIENT_2.query( - ` - mutation { - createManyGroupProtected(input: { value: 10, groups: ["Admin"] }) { - id - value - groups - } - } - `, - {}, - ); - - expect(req.data.createManyGroupProtected).toEqual(null); - expect(req.errors.length).toEqual(1); - expect((req.errors[0] as any).errorType).toEqual('Unauthorized'); - }); - - test(`updateSingleGroupProtected when user is not authorized but has a group that is a substring of the allowed group`, async () => { - const req = await GRAPHQL_CLIENT_3.query( - `mutation { - createSingleGroupProtected(input: { value: 11, group: "Devs-Admin" }) { - id - value - group - } - } - `, - {}, - ); - - const req2 = await GRAPHQL_CLIENT_2.query( - `mutation { - updateSingleGroupProtected(input: {id: "${req.data.createSingleGroupProtected.id}", value: 5 }) { - id - value - group - } - } - `, - {}, - ); - - const req3 = await GRAPHQL_CLIENT_3.query( - `query { - getSingleGroupProtected(id: "${req.data.createSingleGroupProtected.id}") { - id - value - group - } - } - `, - {}, - ); - - expect(req.data.createSingleGroupProtected.value).toEqual(11); - expect(req.data.createSingleGroupProtected.value).toEqual(req3.data.getSingleGroupProtected.value); - expect((req2.errors[0] as any).data).toBeNull(); - expect((req2.errors[0] as any).errorType).toEqual('DynamoDB:ConditionalCheckFailedException'); - }); - - test(`createSingleGroupProtected w/ dynamic group protection authorized`, async () => { - const req = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createSingleGroupProtected(input: { value: 10, group: "Admin" }) { - id - value - group - } - } - `, - {}, - ); - - expect(req.data.createSingleGroupProtected.id).toBeDefined(); - expect(req.data.createSingleGroupProtected.value).toEqual(10); - expect(req.data.createSingleGroupProtected.group).toEqual('Admin'); - }); - - test(`createSingleGroupProtected w/ dynamic group protection when not authorized`, async () => { - const req = await GRAPHQL_CLIENT_2.query( - ` - mutation { - createSingleGroupProtected(input: { value: 10, group: "Admin" }) { - id - value - group - } - } - `, - {}, - ); - - expect(req.data.createSingleGroupProtected).toEqual(null); - expect(req.errors.length).toEqual(1); - expect((req.errors[0] as any).errorType).toEqual('Unauthorized'); - }); - - test(`listPWProtecteds when the user is authorized.`, async () => { - const req = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createPWProtected(input: { content: "Foobie", participants: "${PARTICIPANT_GROUP_NAME}", watchers: "${WATCHER_GROUP_NAME}" }) { - id - content - participants - watchers - } - } - `, - {}, - ); - - expect(req.data.createPWProtected).toBeTruthy(); - - const uReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - updatePWProtected(input: { id: "${req.data.createPWProtected.id}", content: "Foobie2" }) { - id - content - participants - watchers - } - } - `, - {}, - ); - expect(uReq.data.updatePWProtected).toBeTruthy(); - - const req2 = await GRAPHQL_CLIENT_1.query( - ` - query { - listPWProtecteds { - items { - id - content - participants - watchers - } - nextToken - } - } - `, - {}, - ); - expect(req2.data.listPWProtecteds.items.length).toEqual(1); - expect(req2.data.listPWProtecteds.items[0].id).toEqual(req.data.createPWProtected.id); - expect(req2.data.listPWProtecteds.items[0].content).toEqual('Foobie2'); - - const req3 = await GRAPHQL_CLIENT_1.query( - ` - query { - getPWProtected(id: "${req.data.createPWProtected.id}") { - id - content - participants - watchers - } - } - `, - {}, - ); - - expect(req3.data.getPWProtected).toBeTruthy(); - - const dReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deletePWProtected(input: { id: "${req.data.createPWProtected.id}" }) { - id - content - participants - watchers - } - } - `, - {}, - ); - expect(dReq.data.deletePWProtected).toBeTruthy(); - }); - - test(`listPWProtecteds when groups is null in dynamodb.`, async () => { - const req = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createPWProtected(input: { content: "Foobie" }) { - id - content - participants - watchers - } - } - `, - {}, - ); - - expect(req.data.createPWProtected).toBeTruthy(); - - const req2 = await GRAPHQL_CLIENT_1.query( - ` - query { - listPWProtecteds { - items { - id - content - participants - watchers - } - nextToken - } - } - `, - {}, - ); - expect(req2.data.listPWProtecteds.items.length).toEqual(0); - - const req3 = await GRAPHQL_CLIENT_1.query( - ` - query { - getPWProtected(id: "${req.data.createPWProtected.id}") { - id - content - participants - watchers - } - } - `, - {}, - ); - - expect(req3.data.getPWProtected).toEqual(null); - expect(req3.errors.length).toEqual(1); - expect((req3.errors[0] as any).errorType).toEqual('Unauthorized'); - }); - - test(`Protecteds when the user is not authorized.`, async () => { - const req = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createPWProtected(input: { content: "Barbie", participants: "${PARTICIPANT_GROUP_NAME}", watchers: "${WATCHER_GROUP_NAME}" }) { - id - content - participants - watchers - } - } - `, - {}, - ); - - expect(req.data.createPWProtected).toBeTruthy(); - - const req2 = await GRAPHQL_CLIENT_2.query( - ` - query { - listPWProtecteds { - items { - id - content - participants - watchers - } - nextToken - } - } - `, - {}, - ); - - expect(req2.data.listPWProtecteds.items.length).toEqual(0); - expect(req2.data.listPWProtecteds.nextToken).toBeNull(); - - const uReq = await GRAPHQL_CLIENT_2.query( - ` - mutation { - updatePWProtected(input: { id: "${req.data.createPWProtected.id}", content: "Foobie2" }) { - id - content - participants - watchers - } - } - `, - {}, - ); - expect(uReq.data.updatePWProtected).toBeNull(); - - const req3 = await GRAPHQL_CLIENT_2.query( - ` - query { - getPWProtected(id: "${req.data.createPWProtected.id}") { - id - content - participants - watchers - } - } - `, - {}, - ); - - expect(req3.data.getPWProtected).toBeNull(); - - const dReq = await GRAPHQL_CLIENT_2.query( - ` - mutation { - deletePWProtected(input: { id: "${req.data.createPWProtected.id}" }) { - id - content - participants - watchers - } - } - `, - {}, - ); - expect(dReq.data.deletePWProtected).toBeNull(); - - // The record should still exist after delete. - const getReq = await GRAPHQL_CLIENT_1.query( - ` - query { - getPWProtected(id: "${req.data.createPWProtected.id}") { - id - content - participants - watchers - } - } - `, - {}, - ); - expect(getReq.data.getPWProtected).toBeTruthy(); - }); - - test(`creating, updating, and deleting an admin note as an admin`, async () => { - const req = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAdminNote(input: { content: "Hello" }) { - id - content - } - } - `, - {}, - ); - - expect(req.data.createAdminNote.id).toBeDefined(); - expect(req.data.createAdminNote.content).toEqual('Hello'); - const req2 = await GRAPHQL_CLIENT_1.query( - ` - mutation { - updateAdminNote(input: { id: "${req.data.createAdminNote.id}", content: "Hello 2" }) { - id - content - } - } - `, - {}, - ); - - expect(req2.data.updateAdminNote.id).toEqual(req.data.createAdminNote.id); - expect(req2.data.updateAdminNote.content).toEqual('Hello 2'); - const req3 = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAdminNote(input: { id: "${req.data.createAdminNote.id}" }) { - id - content - } - } - `, - {}, - ); - - expect(req3.data.deleteAdminNote.id).toEqual(req.data.createAdminNote.id); - expect(req3.data.deleteAdminNote.content).toEqual('Hello 2'); - }); - - test(`creating, updating, and deleting an admin note as a non admin`, async () => { - const adminReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAdminNote(input: { content: "Hello" }) { - id - content - } - } - `, - {}, - ); - expect(adminReq.data.createAdminNote.id).toBeDefined(); - expect(adminReq.data.createAdminNote.content).toEqual('Hello'); - - const req = await GRAPHQL_CLIENT_2.query( - ` - mutation { - createAdminNote(input: { content: "Hello" }) { - id - content - } - } - `, - {}, - ); - - expect(req.errors.length).toEqual(1); - expect((req.errors[0] as any).errorType).toEqual('Unauthorized'); - - const req2 = await GRAPHQL_CLIENT_2.query( - ` - mutation { - updateAdminNote(input: { id: "${adminReq.data.createAdminNote.id}", content: "Hello 2" }) { - id - content - } - } - `, - {}, - ); - - expect(req2.errors.length).toEqual(1); - expect((req2.errors[0] as any).errorType).toEqual('Unauthorized'); - - const req3 = await GRAPHQL_CLIENT_2.query( - ` - mutation { - deleteAdminNote(input: { id: "${adminReq.data.createAdminNote.id}" }) { - id - content - } - } - `, - {}, - ); - - expect(req3.errors.length).toEqual(1); - expect((req3.errors[0] as any).errorType).toEqual('Unauthorized'); - }); - - /** - * Get Query Tests - */ - - test(`getAllThree as admin.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAllThree(input: { - owner: "user2@test.com" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - - const fetchOwnedBy2AsAdmin = await GRAPHQL_CLIENT_1.query( - ` - query { - getAllThree(id: "${ownedBy2.data.createAllThree.id}") { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(fetchOwnedBy2AsAdmin.data.getAllThree).toBeTruthy(); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); - }); - - test(`getAllThree as owner.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAllThree(input: { - owner: "user2@test.com" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - - const fetchOwnedBy2AsOwner = await GRAPHQL_CLIENT_2.query( - ` - query { - getAllThree(id: "${ownedBy2.data.createAllThree.id}") { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(fetchOwnedBy2AsOwner.data.getAllThree).toBeTruthy(); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); - }); - - test(`getAllThree as one of a set of editors.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAllThree(input: { - editors: ["user2@test.com"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - - const fetchOwnedBy2AsEditor = await GRAPHQL_CLIENT_2.query( - ` - query { - getAllThree(id: "${ownedBy2.data.createAllThree.id}") { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(fetchOwnedBy2AsEditor.data.getAllThree).toBeTruthy(); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); - }); - - test(`getAllThree as a member of a dynamic group.`, async () => { - const ownedByAdmins = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAllThree(input: { - groups: ["Devs"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByAdmins.data.createAllThree).toBeTruthy(); - - const fetchOwnedByAdminsAsAdmin = await GRAPHQL_CLIENT_2.query( - ` - query { - getAllThree(id: "${ownedByAdmins.data.createAllThree.id}") { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(fetchOwnedByAdminsAsAdmin.data.getAllThree).toBeTruthy(); - - const fetchOwnedByAdminsAsNonAdmin = await GRAPHQL_CLIENT_3.query( - ` - query { - getAllThree(id: "${ownedByAdmins.data.createAllThree.id}") { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(fetchOwnedByAdminsAsNonAdmin.errors.length).toEqual(1); - expect((fetchOwnedByAdminsAsNonAdmin.errors[0] as any).errorType).toEqual('Unauthorized'); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedByAdmins.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByAdmins.data.createAllThree.id); - }); - - test(`getAllThree as a member of the alternative group.`, async () => { - const ownedByAdmins = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAllThree(input: { - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByAdmins.data.createAllThree).toBeTruthy(); - - const fetchOwnedByAdminsAsAdmin = await GRAPHQL_CLIENT_2.query( - ` - query { - getAllThree(id: "${ownedByAdmins.data.createAllThree.id}") { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(fetchOwnedByAdminsAsAdmin.data.getAllThree).toBeTruthy(); - - const fetchOwnedByAdminsAsNonAdmin = await GRAPHQL_CLIENT_3.query( - ` - query { - getAllThree(id: "${ownedByAdmins.data.createAllThree.id}") { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(fetchOwnedByAdminsAsNonAdmin.errors.length).toEqual(1); - expect((fetchOwnedByAdminsAsNonAdmin.errors[0] as any).errorType).toEqual('Unauthorized'); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedByAdmins.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByAdmins.data.createAllThree.id); - }); - - /** - * List Query Tests - */ - - test(`listAllThrees as admin.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAllThree(input: { - owner: "user2@test.com" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - - const fetchOwnedBy2AsAdmin = await GRAPHQL_CLIENT_1.query( - ` - query { - listAllThrees { - items { - id - owner - editors - groups - alternativeGroup - } - } - } - `, - {}, - ); - expect(fetchOwnedBy2AsAdmin.data.listAllThrees.items).toHaveLength(1); - expect(fetchOwnedBy2AsAdmin.data.listAllThrees.items[0].id).toEqual(ownedBy2.data.createAllThree.id); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); - }); - - test(`listAllThrees as owner.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAllThree(input: { - owner: "user2@test.com" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - - const fetchOwnedBy2AsOwner = await GRAPHQL_CLIENT_2.query( - ` - query { - listAllThrees { - items { - id - owner - editors - groups - alternativeGroup - } - } - } - `, - {}, - ); - expect(fetchOwnedBy2AsOwner.data.listAllThrees.items).toHaveLength(1); - expect(fetchOwnedBy2AsOwner.data.listAllThrees.items[0].id).toEqual(ownedBy2.data.createAllThree.id); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); - }); - - test(`listAllThrees as one of a set of editors.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAllThree(input: { - editors: ["user2@test.com"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - - const fetchOwnedBy2AsEditor = await GRAPHQL_CLIENT_2.query( - ` - query { - listAllThrees { - items { - id - owner - editors - groups - alternativeGroup - } - } - } - `, - {}, - ); - expect(fetchOwnedBy2AsEditor.data.listAllThrees.items).toHaveLength(1); - expect(fetchOwnedBy2AsEditor.data.listAllThrees.items[0].id).toEqual(ownedBy2.data.createAllThree.id); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); - }); - - test(`listAllThrees as a member of a dynamic group.`, async () => { - const ownedByAdmins = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAllThree(input: { - groups: ["Devs"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByAdmins.data.createAllThree).toBeTruthy(); - - const fetchOwnedByAdminsAsAdmin = await GRAPHQL_CLIENT_2.query( - ` - query { - listAllThrees { - items { - id - owner - editors - groups - alternativeGroup - } - } - } - `, - {}, - ); - expect(fetchOwnedByAdminsAsAdmin.data.listAllThrees.items).toHaveLength(1); - expect(fetchOwnedByAdminsAsAdmin.data.listAllThrees.items[0].id).toEqual(ownedByAdmins.data.createAllThree.id); - - const fetchOwnedByAdminsAsNonAdmin = await GRAPHQL_CLIENT_3.query( - ` - query { - listAllThrees { - items { - id - owner - editors - groups - alternativeGroup - } - } - } - `, - {}, - ); - expect(fetchOwnedByAdminsAsNonAdmin.data.listAllThrees.items).toHaveLength(0); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedByAdmins.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByAdmins.data.createAllThree.id); - }); - - test(`getAllThree as a member of the alternative group.`, async () => { - const ownedByAdmins = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAllThree(input: { - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByAdmins.data.createAllThree).toBeTruthy(); - - const fetchOwnedByAdminsAsAdmin = await GRAPHQL_CLIENT_2.query( - ` - query { - listAllThrees { - items { - id - owner - editors - groups - alternativeGroup - } - } - } - `, - {}, - ); - expect(fetchOwnedByAdminsAsAdmin.data.listAllThrees.items).toHaveLength(1); - expect(fetchOwnedByAdminsAsAdmin.data.listAllThrees.items[0].id).toEqual(ownedByAdmins.data.createAllThree.id); - - const fetchOwnedByAdminsAsNonAdmin = await GRAPHQL_CLIENT_3.query( - ` - query { - listAllThrees { - items { - id - owner - editors - groups - alternativeGroup - } - } - } - `, - {}, - ); - expect(fetchOwnedByAdminsAsNonAdmin.data.listAllThrees.items).toHaveLength(0); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedByAdmins.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByAdmins.data.createAllThree.id); - }); - - /** - * Create Mutation Tests - */ - - test(`createAllThree as admin.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAllThree(input: { - owner: "user2@test.com" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - // set by input - expect(ownedBy2.data.createAllThree.owner).toEqual('user2@test.com'); - // auto filled as logged in user. - expect(ownedBy2.data.createAllThree.editors[0]).toEqual('user1@test.com'); - expect(ownedBy2.data.createAllThree.groups).toBeNull(); - expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedBy2NoEditors = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAllThree(input: { - owner: "user2@test.com", - editors: [] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedBy2NoEditors.data.createAllThree).toBeTruthy(); - // set by input - expect(ownedBy2NoEditors.data.createAllThree.owner).toEqual('user2@test.com'); - // set by input - expect(ownedBy2NoEditors.data.createAllThree.editors).toHaveLength(0); - expect(ownedBy2NoEditors.data.createAllThree.groups).toBeNull(); - expect(ownedBy2NoEditors.data.createAllThree.alternativeGroup).toBeNull(); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); - - const deleteReq2 = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedBy2NoEditors.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq2.data.deleteAllThree.id).toEqual(ownedBy2NoEditors.data.createAllThree.id); - }); - - test(`createAllThree as owner.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_2.query( - ` - mutation { - createAllThree(input: { - owner: "user2@test.com", - editors: [] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - expect(ownedBy2.data.createAllThree.owner).toEqual('user2@test.com'); - expect(ownedBy2.data.createAllThree.editors).toHaveLength(0); - expect(ownedBy2.data.createAllThree.groups).toBeNull(); - expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedBy1 = await GRAPHQL_CLIENT_2.query( - ` - mutation { - createAllThree(input: { - owner: "user1@test.com", - editors: [] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedBy1.errors.length).toEqual(1); - expect((ownedBy1.errors[0] as any).errorType).toEqual('Unauthorized'); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); - }); - - test(`createAllThree as one of a set of editors.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_2.query( - ` - mutation { - createAllThree(input: { - owner: null, - editors: ["user2@test.com"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - expect(ownedBy2.data.createAllThree.owner).toBeNull(); - expect(ownedBy2.data.createAllThree.editors[0]).toEqual('user2@test.com'); - expect(ownedBy2.data.createAllThree.groups).toBeNull(); - expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedBy2WithDefaultOwner = await GRAPHQL_CLIENT_2.query( - ` - mutation { - createAllThree(input: { - editors: ["user2@test.com"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedBy2WithDefaultOwner.data.createAllThree).toBeTruthy(); - expect(ownedBy2WithDefaultOwner.data.createAllThree.owner).toEqual('user2@test.com'); - expect(ownedBy2WithDefaultOwner.data.createAllThree.editors[0]).toEqual('user2@test.com'); - expect(ownedBy2WithDefaultOwner.data.createAllThree.groups).toBeNull(); - expect(ownedBy2WithDefaultOwner.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedByEditorsUnauthed = await GRAPHQL_CLIENT_2.query( - ` - mutation { - createAllThree(input: { - owner: null, - editors: ["user1@test.com"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByEditorsUnauthed.errors.length).toEqual(1); - expect((ownedByEditorsUnauthed.errors[0] as any).errorType).toEqual('Unauthorized'); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); - - const deleteReq2 = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedBy2WithDefaultOwner.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq2.data.deleteAllThree.id).toEqual(ownedBy2WithDefaultOwner.data.createAllThree.id); - }); - - test(`createAllThree as a member of a dynamic group.`, async () => { - const ownedByDevs = await GRAPHQL_CLIENT_2.query( - ` - mutation { - createAllThree(input: { - owner: null, - editors: [], - groups: ["Devs"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByDevs.data.createAllThree).toBeTruthy(); - expect(ownedByDevs.data.createAllThree.owner).toBeNull(); - expect(ownedByDevs.data.createAllThree.editors).toHaveLength(0); - expect(ownedByDevs.data.createAllThree.groups[0]).toEqual('Devs'); - expect(ownedByDevs.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedByAdminsUnauthed = await GRAPHQL_CLIENT_3.query( - ` - mutation { - createAllThree(input: { - owner: null, - editors: [], - groups: ["Devs"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByAdminsUnauthed.errors.length).toEqual(1); - expect((ownedByAdminsUnauthed.errors[0] as any).errorType).toEqual('Unauthorized'); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedByDevs.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByDevs.data.createAllThree.id); - }); - - test(`createAllThree as a member of the alternative group.`, async () => { - const ownedByAdmins = await GRAPHQL_CLIENT_2.query( - ` - mutation { - createAllThree(input: { - owner: null, - editors: [], - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByAdmins.data.createAllThree).toBeTruthy(); - expect(ownedByAdmins.data.createAllThree.owner).toBeNull(); - expect(ownedByAdmins.data.createAllThree.editors).toHaveLength(0); - expect(ownedByAdmins.data.createAllThree.alternativeGroup).toEqual('Devs'); - - const ownedByAdminsUnauthed = await GRAPHQL_CLIENT_3.query( - ` - mutation { - createAllThree(input: { - owner: null, - editors: [], - alternativeGroup: "Admin" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByAdminsUnauthed.errors.length).toEqual(1); - expect((ownedByAdminsUnauthed.errors[0] as any).errorType).toEqual('Unauthorized'); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedByAdmins.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByAdmins.data.createAllThree.id); - }); - - /** - * Update Mutation Tests - */ - - test(`updateAllThree and deleteAllThree as admin.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAllThree(input: { - editors: [] - owner: "user2@test.com" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - // set by input - expect(ownedBy2.data.createAllThree.owner).toEqual('user2@test.com'); - // auto filled as logged in user. - expect(ownedBy2.data.createAllThree.editors).toHaveLength(0); - expect(ownedBy2.data.createAllThree.groups).toBeNull(); - expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedByTwoUpdate = await GRAPHQL_CLIENT_1.query( - ` - mutation { - updateAllThree(input: { - id: "${ownedBy2.data.createAllThree.id}", - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByTwoUpdate.data.updateAllThree).toBeTruthy(); - // set by input - expect(ownedByTwoUpdate.data.updateAllThree.owner).toEqual('user2@test.com'); - // set by input - expect(ownedByTwoUpdate.data.updateAllThree.editors).toHaveLength(0); - expect(ownedByTwoUpdate.data.updateAllThree.groups).toBeNull(); - expect(ownedByTwoUpdate.data.updateAllThree.alternativeGroup).toEqual('Devs'); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); - }); - - test(`updateAllThree and deleteAllThree as owner.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_2.query( - ` - mutation { - createAllThree(input: { - owner: "user2@test.com", - editors: [] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - expect(ownedBy2.data.createAllThree.owner).toEqual('user2@test.com'); - expect(ownedBy2.data.createAllThree.editors).toHaveLength(0); - expect(ownedBy2.data.createAllThree.groups).toBeNull(); - expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedBy2Update = await GRAPHQL_CLIENT_2.query( - ` - mutation { - updateAllThree(input: { - id: "${ownedBy2.data.createAllThree.id}", - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedBy2Update.data.updateAllThree).toBeTruthy(); - // set by input - expect(ownedBy2Update.data.updateAllThree.owner).toEqual('user2@test.com'); - // set by input - expect(ownedBy2Update.data.updateAllThree.editors).toHaveLength(0); - expect(ownedBy2Update.data.updateAllThree.groups).toBeNull(); - expect(ownedBy2Update.data.updateAllThree.alternativeGroup).toEqual('Devs'); - - const deleteReq = await GRAPHQL_CLIENT_2.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); - }); - - test(`updateAllThree and deleteAllThree as one of a set of editors.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_2.query( - ` - mutation { - createAllThree(input: { - owner: null, - editors: ["user2@test.com"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedBy2.data.createAllThree).toBeTruthy(); - expect(ownedBy2.data.createAllThree.owner).toBeNull(); - expect(ownedBy2.data.createAllThree.editors[0]).toEqual('user2@test.com'); - expect(ownedBy2.data.createAllThree.groups).toBeNull(); - expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedByUpdate = await GRAPHQL_CLIENT_2.query( - ` - mutation { - updateAllThree(input: { - id: "${ownedBy2.data.createAllThree.id}", - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByUpdate.data.updateAllThree).toBeTruthy(); - // set by input - expect(ownedByUpdate.data.updateAllThree.owner).toBeNull(); - // set by input - expect(ownedByUpdate.data.updateAllThree.editors[0]).toEqual('user2@test.com'); - expect(ownedByUpdate.data.updateAllThree.groups).toBeNull(); - expect(ownedByUpdate.data.updateAllThree.alternativeGroup).toEqual('Devs'); - - const deleteReq = await GRAPHQL_CLIENT_2.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); - }); - - test(`updateAllThree and deleteAllThree as a member of a dynamic group.`, async () => { - const ownedByDevs = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAllThree(input: { - owner: null, - editors: [], - groups: ["Devs"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByDevs.data.createAllThree).toBeTruthy(); - expect(ownedByDevs.data.createAllThree.owner).toBeNull(); - expect(ownedByDevs.data.createAllThree.editors).toHaveLength(0); - expect(ownedByDevs.data.createAllThree.groups[0]).toEqual('Devs'); - expect(ownedByDevs.data.createAllThree.alternativeGroup).toBeNull(); - - const ownedByUpdate = await GRAPHQL_CLIENT_2.query( - ` - mutation { - updateAllThree(input: { - id: "${ownedByDevs.data.createAllThree.id}", - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByUpdate.data.updateAllThree).toBeTruthy(); - // set by input - expect(ownedByUpdate.data.updateAllThree.owner).toBeNull(); - // set by input - expect(ownedByUpdate.data.updateAllThree.editors).toHaveLength(0); - expect(ownedByUpdate.data.updateAllThree.groups[0]).toEqual('Devs'); - expect(ownedByUpdate.data.updateAllThree.alternativeGroup).toEqual('Devs'); - - const ownedByAdminsUnauthed = await GRAPHQL_CLIENT_3.query( - ` - mutation { - createAllThree(input: { - owner: null, - editors: [], - groups: ["Devs"] - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByAdminsUnauthed.errors.length).toEqual(1); - expect((ownedByAdminsUnauthed.errors[0] as any).errorType).toEqual('Unauthorized'); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedByDevs.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByDevs.data.createAllThree.id); - }); - - test(`updateAllThree and deleteAllThree as a member of the alternative group.`, async () => { - const ownedByDevs = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAllThree(input: { - owner: null, - editors: [], - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByDevs.data.createAllThree).toBeTruthy(); - expect(ownedByDevs.data.createAllThree.owner).toBeNull(); - expect(ownedByDevs.data.createAllThree.editors).toHaveLength(0); - expect(ownedByDevs.data.createAllThree.alternativeGroup).toEqual('Devs'); - - const ownedByUpdate = await GRAPHQL_CLIENT_2.query( - ` - mutation { - updateAllThree(input: { - id: "${ownedByDevs.data.createAllThree.id}", - alternativeGroup: "Admin" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByUpdate.data.updateAllThree).toBeTruthy(); - // set by input - expect(ownedByUpdate.data.updateAllThree.owner).toBeNull(); - // set by input - expect(ownedByUpdate.data.updateAllThree.editors).toHaveLength(0); - expect(ownedByUpdate.data.updateAllThree.groups).toBeNull(); - expect(ownedByUpdate.data.updateAllThree.alternativeGroup).toEqual('Admin'); - - const ownedByAdminsUnauthed = await GRAPHQL_CLIENT_2.query( - ` - mutation { - updateAllThree(input: { - id: "${ownedByDevs.data.createAllThree.id}", - alternativeGroup: "Dev" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByAdminsUnauthed.errors.length).toEqual(1); - expect((ownedByAdminsUnauthed.errors[0] as any).data).toBeNull(); - expect((ownedByAdminsUnauthed.errors[0] as any).errorType).toEqual('DynamoDB:ConditionalCheckFailedException'); - - const ownedByDevs2 = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createAllThree(input: { - owner: null, - editors: [], - alternativeGroup: "Devs" - }) { - id - owner - editors - groups - alternativeGroup - } - } - `, - {}, - ); - expect(ownedByDevs2.data.createAllThree).toBeTruthy(); - expect(ownedByDevs2.data.createAllThree.owner).toBeNull(); - expect(ownedByDevs2.data.createAllThree.editors).toHaveLength(0); - expect(ownedByDevs2.data.createAllThree.alternativeGroup).toEqual('Devs'); - - const deleteReq2 = await GRAPHQL_CLIENT_2.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedByDevs2.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq2.data.deleteAllThree.id).toEqual(ownedByDevs2.data.createAllThree.id); - - const deleteReq = await GRAPHQL_CLIENT_1.query( - ` - mutation { - deleteAllThree(input: { id: "${ownedByDevs.data.createAllThree.id}" }) { - id - } - } - `, - {}, - ); - expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByDevs.data.createAllThree.id); - }); - - test(`createTestIdentity as admin.`, async () => { - const ownedBy2 = await GRAPHQL_CLIENT_1.query( - ` - mutation { - createTestIdentity(input: { - title: "Test title" - }) { - id - title - owner - } - } - `, - {}, - ); - expect(ownedBy2.data.createTestIdentity).toBeTruthy(); - expect(ownedBy2.data.createTestIdentity.title).toEqual('Test title'); - expect(ownedBy2.data.createTestIdentity.owner.slice(0, 19)).toEqual('https://cognito-idp'); - - // user 2 should be able to update because they share the same issuer. - const update = await GRAPHQL_CLIENT_3.query( - ` - mutation { - updateTestIdentity(input: { - id: "${ownedBy2.data.createTestIdentity.id}", - title: "Test title update" - }) { - id - title - owner - } - } - `, - {}, - ); - expect(update.data.updateTestIdentity).toBeTruthy(); - expect(update.data.updateTestIdentity.title).toEqual('Test title update'); - expect(update.data.updateTestIdentity.owner.slice(0, 19)).toEqual('https://cognito-idp'); - - // user 2 should be able to get because they share the same issuer. - const getReq = await GRAPHQL_CLIENT_3.query( - ` - query { - getTestIdentity(id: "${ownedBy2.data.createTestIdentity.id}") { - id - title - owner - } - } - `, - {}, - ); - expect(getReq.data.getTestIdentity).toBeTruthy(); - expect(getReq.data.getTestIdentity.title).toEqual('Test title update'); - expect(getReq.data.getTestIdentity.owner.slice(0, 19)).toEqual('https://cognito-idp'); - - const listResponse = await GRAPHQL_CLIENT_3.query( - `query { - listTestIdentities(filter: { title: { eq: "Test title update" } }, limit: 100) { - items { - id - title - owner - } - } - }`, - {}, - ); - const relevantPost = listResponse.data.listTestIdentities.items.find((p) => p.id === getReq.data.getTestIdentity.id); - expect(relevantPost).toBeTruthy(); - expect(relevantPost.title).toEqual('Test title update'); - expect(relevantPost.owner.slice(0, 19)).toEqual('https://cognito-idp'); - - // user 2 should be able to delete because they share the same issuer. - const delReq = await GRAPHQL_CLIENT_3.query( - ` - mutation { - deleteTestIdentity(input: { - id: "${ownedBy2.data.createTestIdentity.id}" - }) { - id - title - owner - } - } - `, - {}, - ); - expect(delReq.data.deleteTestIdentity).toBeTruthy(); - expect(delReq.data.deleteTestIdentity.title).toEqual('Test title update'); - expect(delReq.data.deleteTestIdentity.owner.slice(0, 19)).toEqual('https://cognito-idp'); - }); - - /** - * Test 'operations' argument - */ - test("get and list with 'read' operation set", async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createNoOwner: createOwnerReadProtected(input: { id: "1", sk: "1", content: "Hello, World! - No Owner" }) { - id - content - owner - } - createOwnerReadProtected(input: { id: "1", sk: "2", content: "Hello, World!", owner: "${USERNAME1}" }) { - id - content - owner - } - createNoOwner2: createOwnerReadProtected(input: { id: "1", sk: "3", content: "Hello, World! - No Owner 2" }) { - id - content - owner - } - }`, - {}, - ); - - expect(response.data.createOwnerReadProtected.id).toBeDefined(); - expect(response.data.createOwnerReadProtected.content).toEqual('Hello, World!'); - expect(response.data.createOwnerReadProtected.owner).toEqual(USERNAME1); - - const response2 = await GRAPHQL_CLIENT_2.query( - `query { - getOwnerReadProtected(id: "${response.data.createOwnerReadProtected.id}", sk:"2") { - id content owner - } - }`, - {}, - ); - expect(response2.data.getOwnerReadProtected).toBeNull(); - expect(response2.errors).toHaveLength(1); - - const response3 = await GRAPHQL_CLIENT_1.query( - `query { - getOwnerReadProtected(id: "${response.data.createOwnerReadProtected.id}", sk:"2") { - id content owner - } - }`, - {}, - ); - expect(response3.data.getOwnerReadProtected.id).toBeDefined(); - expect(response3.data.getOwnerReadProtected.content).toEqual('Hello, World!'); - expect(response3.data.getOwnerReadProtected.owner).toEqual(USERNAME1); - - const response4 = await GRAPHQL_CLIENT_1.query( - `query { - listOwnerReadProtecteds(id: "1") { - items { - id content owner - } - } - }`, - {}, - ); - expect(response4.data.listOwnerReadProtecteds.items.length).toEqual(1); - - const response5 = await GRAPHQL_CLIENT_2.query( - `query { - listOwnerReadProtecteds { - items { - id content owner - } - } - }`, - {}, - ); - expect(response5.data.listOwnerReadProtecteds.items).toHaveLength(0); - }); - - test("createOwnerCreateUpdateDeleteProtected with 'create' operation set", async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createOwnerCreateUpdateDeleteProtected(input: { content: "Hello, World!", owner: "${USERNAME1}" }) { - id - content - owner - } - }`, - {}, - ); - expect(response.data.createOwnerCreateUpdateDeleteProtected.id).toBeDefined(); - expect(response.data.createOwnerCreateUpdateDeleteProtected.content).toEqual('Hello, World!'); - expect(response.data.createOwnerCreateUpdateDeleteProtected.owner).toEqual(USERNAME1); - - const response2 = await GRAPHQL_CLIENT_1.query( - `mutation { - createOwnerCreateUpdateDeleteProtected(input: { content: "Hello, World!", owner: "${USERNAME2}" }) { - id - content - owner - } - }`, - {}, - ); - expect(response2.data.createOwnerCreateUpdateDeleteProtected).toBeNull(); - expect(response2.errors).toHaveLength(1); - }); - - test("updateOwnerCreateUpdateDeleteProtected with 'update' operation set", async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createOwnerCreateUpdateDeleteProtected(input: { content: "Hello, World!", owner: "${USERNAME1}" }) { - id - content - owner - } - }`, - {}, - ); - expect(response.data.createOwnerCreateUpdateDeleteProtected.id).toBeDefined(); - expect(response.data.createOwnerCreateUpdateDeleteProtected.content).toEqual('Hello, World!'); - expect(response.data.createOwnerCreateUpdateDeleteProtected.owner).toEqual(USERNAME1); - - const response2 = await GRAPHQL_CLIENT_2.query( - `mutation { - updateOwnerCreateUpdateDeleteProtected( - input: { - id: "${response.data.createOwnerCreateUpdateDeleteProtected.id}", - content: "Bye, World!" - } - ) { - id - content - owner - } - }`, - {}, - ); - expect(response2.data.updateOwnerCreateUpdateDeleteProtected).toBeNull(); - expect(response2.errors).toHaveLength(1); - - const response3 = await GRAPHQL_CLIENT_1.query( - `mutation { - updateOwnerCreateUpdateDeleteProtected( - input: { - id: "${response.data.createOwnerCreateUpdateDeleteProtected.id}", - content: "Bye, World!" - } - ) { - id - content - owner - } - }`, - {}, - ); - expect(response3.data.updateOwnerCreateUpdateDeleteProtected.id).toBeDefined(); - expect(response3.data.updateOwnerCreateUpdateDeleteProtected.content).toEqual('Bye, World!'); - expect(response3.data.updateOwnerCreateUpdateDeleteProtected.owner).toEqual(USERNAME1); - }); - - test("deleteOwnerCreateUpdateDeleteProtected with 'update' operation set", async () => { - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createOwnerCreateUpdateDeleteProtected(input: { content: "Hello, World!", owner: "${USERNAME1}" }) { - id - content - owner - } - }`, - {}, - ); - expect(response.data.createOwnerCreateUpdateDeleteProtected.id).toBeDefined(); - expect(response.data.createOwnerCreateUpdateDeleteProtected.content).toEqual('Hello, World!'); - expect(response.data.createOwnerCreateUpdateDeleteProtected.owner).toEqual(USERNAME1); - - const response2 = await GRAPHQL_CLIENT_2.query( - `mutation { - deleteOwnerCreateUpdateDeleteProtected( - input: { - id: "${response.data.createOwnerCreateUpdateDeleteProtected.id}" - } - ) { - id - content - owner - } - }`, - {}, - ); - expect(response2.data.deleteOwnerCreateUpdateDeleteProtected).toBeNull(); - expect(response2.errors).toHaveLength(1); - - const response3 = await GRAPHQL_CLIENT_1.query( - `mutation { - deleteOwnerCreateUpdateDeleteProtected( - input: { - id: "${response.data.createOwnerCreateUpdateDeleteProtected.id}" - } - ) { - id - content - owner - } - }`, - {}, - ); - expect(response3.data.deleteOwnerCreateUpdateDeleteProtected.id).toBeDefined(); - expect(response3.data.deleteOwnerCreateUpdateDeleteProtected.content).toEqual('Hello, World!'); - expect(response3.data.deleteOwnerCreateUpdateDeleteProtected.owner).toEqual(USERNAME1); - }); - - test('allow private combined with groups as Admin and non-admin users', async () => { - const create = `mutation { - p1: createPerformance(input: { - id: "P1" - performer: "Perf #1" - description: "Description" - time: "2019-11-11T00:00:00Z" - performanceStageId: "S1" - }) { - id - } - - p2: createPerformance(input: { - id: "P2" - performer: "Perf #2" - description: "Description" - time: "2019-11-11T00:00:00Z" - performanceStageId: "S1" - }) { - id - } - - s1: createStage(input: { - id: "S1" - name: "Stage #1" - }) { - id - } - } - `; - - // Create as non-admin user, should fail - const response1 = await GRAPHQL_CLIENT_3.query(create, {}); - - expect(response1.data.p1).toBeNull(); - expect(response1.data.p2).toBeNull(); - expect(response1.data.s1).toBeNull(); - expect(response1.errors.length).toEqual(3); - expect((response1.errors[0] as any).errorType).toEqual('Unauthorized'); - expect((response1.errors[1] as any).errorType).toEqual('Unauthorized'); - expect((response1.errors[2] as any).errorType).toEqual('Unauthorized'); - - // Create as Admin, should succeed - const response2 = await GRAPHQL_CLIENT_1.query(create, {}); - - expect(response2.data.p1.id).toEqual('P1'); - expect(response2.data.p2.id).toEqual('P2'); - expect(response2.data.s1.id).toEqual('S1'); - - const update = `mutation { - updatePerformance(input: { - id: "P1" - performer: "Best Perf #1" - }) { - id - performer - } - } - `; - - // Update as non-admin user, should fail - const response3 = await GRAPHQL_CLIENT_3.query(update, {}); - - expect(response3.data.updatePerformance).toBeNull(); - expect(response3.errors.length).toEqual(1); - expect((response3.errors[0] as any).errorType).toEqual('Unauthorized'); - - // Update as Admin, should succeed - const response4 = await GRAPHQL_CLIENT_1.query(update, {}); - - expect(response4.data.updatePerformance.id).toEqual('P1'); - expect(response4.data.updatePerformance.performer).toEqual('Best Perf #1'); - - // List as non-admin and Admin user as well, should succeed - const list = `query List { - listPerformances { - items { - id - performer - description - time - stage { - name - } - } - } - } - `; - - const response5 = await GRAPHQL_CLIENT_3.query(list, {}); - - expect(response5.data.listPerformances).toBeDefined(); - expect(response5.data.listPerformances.items).toBeDefined(); - expect(response5.data.listPerformances.items.length).toEqual(2); - expect(response5.data.listPerformances.items[0].id).toEqual('P2'); - expect(response5.data.listPerformances.items[0].performer).toEqual('Perf #2'); - expect(response5.data.listPerformances.items[0].stage).toBeDefined(); - expect(response5.data.listPerformances.items[0].stage.name).toEqual('Stage #1'); - expect(response5.data.listPerformances.items[1].id).toEqual('P1'); - expect(response5.data.listPerformances.items[1].performer).toEqual('Best Perf #1'); - expect(response5.data.listPerformances.items[1].stage).toBeDefined(); - expect(response5.data.listPerformances.items[1].stage.name).toEqual('Stage #1'); - - const response6 = await GRAPHQL_CLIENT_1.query(list, {}); - - expect(response6.data.listPerformances).toBeDefined(); - expect(response6.data.listPerformances.items).toBeDefined(); - expect(response6.data.listPerformances.items.length).toEqual(2); - expect(response6.data.listPerformances.items[0].id).toEqual('P2'); - expect(response6.data.listPerformances.items[0].performer).toEqual('Perf #2'); - expect(response6.data.listPerformances.items[0].stage).toBeDefined(); - expect(response6.data.listPerformances.items[0].stage.name).toEqual('Stage #1'); - expect(response6.data.listPerformances.items[1].id).toEqual('P1'); - expect(response6.data.listPerformances.items[1].performer).toEqual('Best Perf #1'); - expect(response6.data.listPerformances.items[1].stage.name).toEqual('Stage #1'); - expect(response6.data.listPerformances.items[1].stage).toBeDefined(); - - // Get as non-admin and Admin user as well, should succeed - const get = `query Get { - getPerformance(id: "P1") { - id - performer - description - time - stage { - name - } - } - } - `; - - const response7 = await GRAPHQL_CLIENT_3.query(get, {}); - - expect(response7.data.getPerformance).toBeDefined(); - expect(response7.data.getPerformance.id).toEqual('P1'); - expect(response7.data.getPerformance.performer).toEqual('Best Perf #1'); - expect(response7.data.getPerformance.stage).toBeDefined(); - expect(response7.data.getPerformance.stage.name).toEqual('Stage #1'); - - const response8 = await GRAPHQL_CLIENT_1.query(get, {}); - - expect(response8.data.getPerformance).toBeDefined(); - expect(response8.data.getPerformance.id).toEqual('P1'); - expect(response8.data.getPerformance.performer).toEqual('Best Perf #1'); - expect(response8.data.getPerformance.stage).toBeDefined(); - expect(response8.data.getPerformance.stage.name).toEqual('Stage #1'); - - const deleteMutation = `mutation { - deletePerformance(input: { - id: "P1" - }) { - id - } - } - `; - - // Delete as non-admin user, should fail - const response9 = await GRAPHQL_CLIENT_3.query(deleteMutation, {}); - - expect(response9.data.deletePerformance).toBeNull(); - expect(response9.errors.length).toEqual(1); - expect((response9.errors[0] as any).errorType).toEqual('Unauthorized'); - - // Delete as Admin, should succeed - const response10 = await GRAPHQL_CLIENT_1.query(deleteMutation, {}); - - expect(response10.data.deletePerformance).toBeDefined(); - expect(response10.data.deletePerformance.id).toEqual('P1'); - }); - - test('authorized user can get Performance with no created stage', async () => { - const createPerf = `mutation { - create: createPerformance(input: { - id: "P3" - performer: "Perf #3" - description: "desc" - time: "2021-11-11T00:00:00Z" - }) { - id - performer - description - time - createdAt - updatedAt - } - }`; - - const getPerf = `query { - g1: getPerformance(id: "P3") { - id - performer - description - time - stage { - id - name - createdAt - updatedAt - } - createdAt - updatedAt - } - } - `; - - const createStage = `mutation { - createStage(input: {name: "stage3", id: "003"}) { - createdAt - id - name - updatedAt - } - }`; - - const updatePerf = `mutation { - u1: updatePerformance(input: {id: "P3", performanceStageId: "003"}) { - createdAt - description - id - performer - time - updatedAt - stage { - id - name - } - } - }`; - - // first make a query to the record 'P3' - const response1 = await GRAPHQL_CLIENT_1.query(getPerf, {}); - expect(response1).toBeDefined(); - expect(response1.data.g1).toBeNull(); - - // create performance and expect stage to be null - await GRAPHQL_CLIENT_1.query(createPerf, {}); - const response2 = await GRAPHQL_CLIENT_1.query(getPerf, {}); - expect(response2).toBeDefined(); - expect(response2.data.g1).toBeDefined(); - expect(response2.data.g1.id).toEqual('P3'); - expect(response2.data.g1.description).toEqual('desc'); - expect(response2.data.g1.stage).toBeNull(); - - // create stage and then add it to perf should show stage in perf - await GRAPHQL_CLIENT_1.query(createStage, {}); - const response3 = await GRAPHQL_CLIENT_1.query(updatePerf, {}); - expect(response3).toBeDefined(); - expect(response3.data.u1).toBeDefined(); - expect(response3.data.u1.id).toEqual('P3'); - expect(response3.data.u1.stage).toMatchObject({ - id: '003', - name: 'stage3', - }); - }); -}); diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/ModelConnectionTransformer.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/ModelConnectionTransformer.e2e.test.ts deleted file mode 100644 index 94062c50ca..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/ModelConnectionTransformer.e2e.test.ts +++ /dev/null @@ -1,594 +0,0 @@ -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as S3 } from 'aws-sdk/clients/s3'; -import { default as moment } from 'moment'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { GraphQLClient } from '../GraphQLClient'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { S3Client } from '../S3Client'; -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `ModelConnectionTransformerTest-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `appsync-connection-transformer-test-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/model_connection_transform_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; - -let GRAPHQL_CLIENT = undefined; - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -beforeAll(async () => { - const validSchema = ` - type Post @model { - id: ID! - title: String! - createdAt: AWSDateTime - updatedAt: AWSDateTime - comments: [Comment] @connection(name: "PostComments", keyField: "postId", limit:50) - sortedComments: [SortedComment] @connection(name: "SortedPostComments", keyField: "postId", sortField: "when") - } - type Comment @model { - id: ID! - content: String! - post: Post @connection(name: "PostComments", keyField: "postId") - } - type SortedComment @model { - id: ID! - content: String! - when: String! - post: Post @connection(name: "SortedPostComments", keyField: "postId", sortField: "when") - } - type Album @model { - id: ID! - title: String! - parent: Album @connection(name: "AlbumAlbums", keyField: "parentId") - children: [Album] @connection(name: "AlbumAlbums", keyField: "parentId") - photos: [Photo] @connection(name: "AlbumPhotos", keyField: "albumId") - } - type Photo @model { - id: ID! - album: Album @connection (name: "AlbumPhotos", keyField: "albumId") - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelConnectionTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - - try { - await awsS3Client - .createBucket({ - Bucket: BUCKET_NAME, - }) - .promise(); - } catch (e) { - console.error(`Failed to create S3 bucket: ${e}`); - } - try { - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { CreateAPIKey: '1' }, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - - // Arbitrary wait to make sure everything is ready. - await cf.wait(5, () => Promise.resolve()); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - const endpoint = getApiEndpoint(finishedStack.Outputs); - const apiKey = getApiKey(finishedStack.Outputs); - expect(apiKey).toBeDefined(); - expect(endpoint).toBeDefined(); - GRAPHQL_CLIENT = new GraphQLClient(endpoint, { 'x-api-key': apiKey }); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf); -}); - -/** - * Test queries below - */ - -test('queryPost query', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Query" }) { - id - title - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Query'); - const createCommentResponse = await GRAPHQL_CLIENT.query( - `mutation { - createComment(input: { content: "A comment!", postId: "${createResponse.data.createPost.id}" }) { - id - content - post { - id - title - } - } - }`, - {}, - ); - expect(createCommentResponse.data.createComment.id).toBeDefined(); - expect(createCommentResponse.data.createComment.content).toEqual('A comment!'); - expect(createCommentResponse.data.createComment.post.id).toEqual(createResponse.data.createPost.id); - expect(createCommentResponse.data.createComment.post.title).toEqual(createResponse.data.createPost.title); - const queryResponse = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - comments { - items { - id - content - } - } - } - }`, - {}, - ); - expect(queryResponse.data.getPost).toBeDefined(); - const items = queryResponse.data.getPost.comments.items; - expect(items.length).toEqual(1); - expect(items[0].id).toEqual(createCommentResponse.data.createComment.id); -}); - -const title = 'Test Query with Sort Field'; -const comment1 = 'a comment and a date! - 1'; -const comment2 = 'a comment and a date! - 2'; -const whenpast = '2017-10-01T00:00:00.000Z'; -const when1 = '2018-10-01T00:00:00.000Z'; -const whenmid = '2018-12-01T00:00:00.000Z'; -const when2 = '2019-10-01T00:00:01.000Z'; -const whenfuture = '2020-10-01T00:00:00.000Z'; - -test('queryPost query with sortField', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "${title}" }) { - id - title - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual(title); - const createCommentResponse1 = await GRAPHQL_CLIENT.query( - `mutation { - createSortedComment(input: - { content: "${comment1}", - when: "${when1}" - postId: "${createResponse.data.createPost.id}" - }) { - id - content - post { - id - title - } - } - }`, - {}, - ); - expect(createCommentResponse1.data.createSortedComment.id).toBeDefined(); - expect(createCommentResponse1.data.createSortedComment.content).toEqual(comment1); - expect(createCommentResponse1.data.createSortedComment.post.id).toEqual(createResponse.data.createPost.id); - expect(createCommentResponse1.data.createSortedComment.post.title).toEqual(createResponse.data.createPost.title); - - // create 2nd comment, 1 second later - const createCommentResponse2 = await GRAPHQL_CLIENT.query( - `mutation { - createSortedComment(input: - { content: "${comment2}", - when: "${when2}" - postId: "${createResponse.data.createPost.id}" - }) { - id - content - post { - id - title - } - } - }`, - {}, - ); - expect(createCommentResponse2.data.createSortedComment.id).toBeDefined(); - expect(createCommentResponse2.data.createSortedComment.content).toEqual(comment2); - expect(createCommentResponse2.data.createSortedComment.post.id).toEqual(createResponse.data.createPost.id); - expect(createCommentResponse2.data.createSortedComment.post.title).toEqual(createResponse.data.createPost.title); - - const queryResponse = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponse.data.getPost).toBeDefined(); - const items = queryResponse.data.getPost.sortedComments.items; - expect(items.length).toEqual(2); - expect(items[0].id).toEqual(createCommentResponse1.data.createSortedComment.id); - expect(items[1].id).toEqual(createCommentResponse2.data.createSortedComment.id); - - const queryResponseDesc = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments(sortDirection: DESC) { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponseDesc.data.getPost).toBeDefined(); - const itemsDesc = queryResponseDesc.data.getPost.sortedComments.items; - expect(itemsDesc.length).toEqual(2); - expect(itemsDesc[0].id).toEqual(createCommentResponse2.data.createSortedComment.id); - expect(itemsDesc[1].id).toEqual(createCommentResponse1.data.createSortedComment.id); - - const queryResponseWithKeyCondition = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments(when: { beginsWith: "2018"}) { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponseWithKeyCondition.data.getPost).toBeDefined(); - const itemsDescWithKeyCondition = queryResponseWithKeyCondition.data.getPost.sortedComments.items; - expect(itemsDescWithKeyCondition.length).toEqual(1); - expect(itemsDescWithKeyCondition[0].id).toEqual(createCommentResponse1.data.createSortedComment.id); - - const queryResponseWithKeyConditionEq = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments(when: { eq: "${when1}"}) { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponseWithKeyConditionEq.data.getPost).toBeDefined(); - const itemsDescWithKeyConditionEq = queryResponseWithKeyConditionEq.data.getPost.sortedComments.items; - expect(itemsDescWithKeyConditionEq.length).toEqual(1); - expect(itemsDescWithKeyConditionEq[0].id).toEqual(createCommentResponse1.data.createSortedComment.id); - - const queryResponseWithKeyConditionGt = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments(when: { gt: "${when1}"}) { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponseWithKeyConditionGt.data.getPost).toBeDefined(); - const itemsDescWithKeyConditionGt = queryResponseWithKeyConditionGt.data.getPost.sortedComments.items; - expect(itemsDescWithKeyConditionGt.length).toEqual(1); - expect(itemsDescWithKeyConditionGt[0].id).toEqual(createCommentResponse2.data.createSortedComment.id); - - const queryResponseWithKeyConditionGe = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments(when: { ge: "${when1}"}) { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponseWithKeyConditionGe.data.getPost).toBeDefined(); - const itemsDescWithKeyConditionGe = queryResponseWithKeyConditionGe.data.getPost.sortedComments.items; - expect(itemsDescWithKeyConditionGe.length).toEqual(2); - expect(itemsDescWithKeyConditionGe[0].id).toEqual(createCommentResponse1.data.createSortedComment.id); - expect(itemsDescWithKeyConditionGe[1].id).toEqual(createCommentResponse2.data.createSortedComment.id); - - const queryResponseWithKeyConditionLe = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments(when: { le: "${when2}"}) { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponseWithKeyConditionLe.data.getPost).toBeDefined(); - const itemsDescWithKeyConditionLe = queryResponseWithKeyConditionLe.data.getPost.sortedComments.items; - expect(itemsDescWithKeyConditionLe.length).toEqual(2); - expect(itemsDescWithKeyConditionLe[0].id).toEqual(createCommentResponse1.data.createSortedComment.id); - expect(itemsDescWithKeyConditionLe[1].id).toEqual(createCommentResponse2.data.createSortedComment.id); - - const queryResponseWithKeyConditionLt = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments(when: { lt: "${when2}"}) { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponseWithKeyConditionLt.data.getPost).toBeDefined(); - const itemsDescWithKeyConditionLt = queryResponseWithKeyConditionLt.data.getPost.sortedComments.items; - expect(itemsDescWithKeyConditionLt.length).toEqual(1); - expect(itemsDescWithKeyConditionLt[0].id).toEqual(createCommentResponse1.data.createSortedComment.id); - - const queryResponseWithKeyConditionBetween = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createResponse.data.createPost.id}") { - id - title - sortedComments(when: { between: ["${whenmid}", "${whenfuture}"]}) { - items { - id - when - content - } - } - } - }`, - {}, - ); - expect(queryResponseWithKeyConditionBetween.data.getPost).toBeDefined(); - const itemsDescWithKeyConditionBetween = queryResponseWithKeyConditionBetween.data.getPost.sortedComments.items; - expect(itemsDescWithKeyConditionBetween.length).toEqual(1); - expect(itemsDescWithKeyConditionBetween[0].id).toEqual(createCommentResponse2.data.createSortedComment.id); -}); - -test('create comment without a post and then querying the comment.', async () => { - try { - const createCommentResponse1 = await GRAPHQL_CLIENT.query( - `mutation { - createComment(input: - { content: "${comment1}" }) { - id - content - post { - id - title - } - } - }`, - {}, - ); - expect(createCommentResponse1.data.createComment.id).toBeDefined(); - expect(createCommentResponse1.data.createComment.content).toEqual(comment1); - expect(createCommentResponse1.data.createComment.post).toBeNull(); - - const queryResponseDesc = await GRAPHQL_CLIENT.query( - `query { - getComment(id: "${createCommentResponse1.data.createComment.id}") { - id - content - post { - id - } - } - }`, - {}, - ); - expect(queryResponseDesc.data.getComment).toBeDefined(); - expect(queryResponseDesc.data.getComment.post).toBeNull(); - } catch (e) { - console.error(e); - // fail - expect(e).toBeUndefined(); - } -}); - -test('album self connection.', async () => { - const createAlbum = await GRAPHQL_CLIENT.query( - `mutation { - createAlbum(input: { title: "Test Album" }) { - id - title - } - }`, - {}, - ); - expect(createAlbum.data.createAlbum.id).toBeDefined(); - expect(createAlbum.data.createAlbum.title).toEqual('Test Album'); - - const createSelfAlbum = await GRAPHQL_CLIENT.query( - `mutation { - createAlbum(input: { title: "A Album!", parentId: "${createAlbum.data.createAlbum.id}" }) { - id - title - parent { - id - title - } - } - }`, - {}, - ); - expect(createSelfAlbum.data.createAlbum.id).toBeDefined(); - expect(createSelfAlbum.data.createAlbum.title).toEqual('A Album!'); - expect(createSelfAlbum.data.createAlbum.parent.id).toEqual(createAlbum.data.createAlbum.id); - expect(createSelfAlbum.data.createAlbum.parent.title).toEqual(createAlbum.data.createAlbum.title); - - const queryAlbum = await GRAPHQL_CLIENT.query( - `query { - getAlbum(id: "${createAlbum.data.createAlbum.id}") { - id - title - } - }`, - {}, - ); - expect(queryAlbum.data.getAlbum).toBeDefined(); - expect(queryAlbum.data.getAlbum.title).toEqual('Test Album'); -}); - -test('default limit is 50', async () => { - // create Auth logic around this - const postID = 'e2eConnectionPost'; - const postTitle = 'samplePost'; - const createPost = await GRAPHQL_CLIENT.query( - `mutation CreatePost { - createPost(input: {title: "${postTitle}", id: "${postID}"}) { - id - title - } - } - `, - {}, - ); - expect(createPost.data.createPost).toBeDefined(); - expect(createPost.data.createPost.id).toEqual(postID); - expect(createPost.data.createPost.title).toEqual(postTitle); - - for (let i = 0; i < 51; i++) { - await GRAPHQL_CLIENT.query( - ` - mutation CreateComment { - createComment(input: {postId: "${postID}", content: "content_${i}"}) { - content - id - post { - title - } - } - } - `, - {}, - ); - } - - const getPost = await GRAPHQL_CLIENT.query( - ` - query GetPost($id: ID!) { - getPost(id: $id) { - id - title - createdAt - updatedAt - comments { - items { - id - content - } - nextToken - } - } - }`, - { id: postID }, - ); - - expect(getPost.data.getPost.comments.items.length).toEqual(50); -}); diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/ModelConnectionWithKeyTransformer.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/ModelConnectionWithKeyTransformer.e2e.test.ts deleted file mode 100644 index cb142587e6..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/ModelConnectionWithKeyTransformer.e2e.test.ts +++ /dev/null @@ -1,767 +0,0 @@ -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { KeyTransformer } from 'graphql-key-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as S3 } from 'aws-sdk/clients/s3'; -import { default as moment } from 'moment'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { GraphQLClient } from '../GraphQLClient'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { S3Client } from '../S3Client'; -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `ModelConnectionKeyTransformerTest-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `appsync-connection-key-transformer-test-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/model_connection_key_transform_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; - -let GRAPHQL_CLIENT = undefined; - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -beforeAll(async () => { - const validSchema = ` - type AProject - @model(subscriptions: null) - @key(fields: ["projectId"]) - { - projectId: String! - name: String - team: ATeam @connection - } - - type ATeam - @model(subscriptions: null) - @key(fields: ["teamId"]) - { - teamId: String! - name: String - } - - type BProject - @model(subscriptions: null) - @key(fields: ["projectId"]) - { - projectId: String! - name: String - teams: [BTeam] @connection - } - - type BTeam - @model(subscriptions: null) - @key(fields: ["teamId"]) - { - teamId: String! - name: String - } - - type CProject - @model(subscriptions: null) - @key(fields: ["projectId"]) - { - projectId: ID! - name: String - team: CTeam @connection(name: "CProjectCTeam") - } - - type CTeam - @model(subscriptions: null) - @key(fields: ["teamId"]) - { - teamId: ID! - name: String - project: CProject @connection(name: "CProjectCTeam") - } - - type DProject - @model(subscriptions: null) - @key(fields: ["projectId"]) - { - projectId: ID! - name: String - teams: [DTeam] @connection(name: "DProjectDTeam") - } - - type DTeam - @model(subscriptions: null) - @key(fields: ["teamId"]) - { - teamId: ID! - name: String - project: DProject @connection(name: "DProjectDTeam") - } - - type Model1 - @model(subscriptions: null) - @key(fields: ["id", "sort"]) - @key(name: "byName", fields: ["name", "id"]) - @key(name: "byNameIdAndSort", fields: ["name","id","sort"]) - { - id: ID! - sort: Int! - name: String! - } - type Model2 @model(subscriptions: null) - { - id: ID! - connection: Model1 @connection(sortField: "modelOneSort") - modelOneSort: Int - } - - type Model3 @model(subscriptions: null) - { - id: ID! - connectionPK: ID - connectionSort: Int - connectionSK: String - connectionName: String - connection: Model1 @connection(keyField:"connectionPK", sortField: "connectionSort") - connections: [Model1] @connection(keyName: "byName", fields: ["connectionSK"]) - connectionsWithCompositeKey: [Model4] - @connection( - keyName: "byNameIdAndSort" - fields: ["connectionName", "connectionPK", "connectionSort"]) - } - - type Model4 @model(subscriptions: null) @key(name: "byNameIdAndSort", fields: ["name", "id", "sort"]) - { - id: ID! - sort: Int! - name: String! - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new KeyTransformer(), - new ModelConnectionTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - - try { - await awsS3Client - .createBucket({ - Bucket: BUCKET_NAME, - }) - .promise(); - } catch (e) { - console.error(`Failed to create S3 bucket: ${e}`); - } - try { - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { CreateAPIKey: '1' }, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - - // Arbitrary wait to make sure everything is ready. - await cf.wait(5, () => Promise.resolve()); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - const endpoint = getApiEndpoint(finishedStack.Outputs); - const apiKey = getApiKey(finishedStack.Outputs); - expect(apiKey).toBeDefined(); - expect(endpoint).toBeDefined(); - GRAPHQL_CLIENT = new GraphQLClient(endpoint, { 'x-api-key': apiKey }); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf); -}); - -/** - * Test queries below - */ - -test('Unnamed connection 1 way navigation, with primary @key directive 1:1', async () => { - await GRAPHQL_CLIENT.query( - ` - mutation CreateATeam { - createATeam(input: {teamId: "T1", name: "Team 1"}) { - teamId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateAProject { - createAProject(input: {projectId: "P1", name: "P1", aProjectTeamId: "T1"}) { - projectId - name - } - } - `, - {}, - ); - - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query ListAProjects { - listAProjects { - items { - projectId - name - team { - teamId - name - } - } - } - } - `, - {}, - ); - expect(queryResponse.data.listAProjects).toBeDefined(); - const items = queryResponse.data.listAProjects.items; - expect(items.length).toEqual(1); - expect(items[0].projectId).toEqual('P1'); - expect(items[0].team).toBeDefined(); - expect(items[0].team.teamId).toEqual('T1'); -}); - -test('Unnamed connection 1 way navigation, with primary @key directive 1:M', async () => { - await GRAPHQL_CLIENT.query( - ` - mutation CreateBProject { - createBProject(input: {projectId: "P1", name: "P1"}) { - projectId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateBTeam { - createBTeam(input: {teamId: "T1", name: "Team 1", bProjectTeamsId: "P1"}) { - teamId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateBTeam { - createBTeam(input: {teamId: "T2", name: "Team 2", bProjectTeamsId: "P1"}) { - teamId - name - } - } - `, - {}, - ); - - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query ListBProjects { - listBProjects { - items { - projectId - name - teams { - items { - teamId - name - } - } - } - } - } - `, - {}, - ); - expect(queryResponse.data.listBProjects).toBeDefined(); - const items = queryResponse.data.listBProjects.items; - expect(items.length).toEqual(1); - expect(items[0].projectId).toEqual('P1'); - expect(items[0].teams).toBeDefined(); - expect(items[0].teams.items).toBeDefined(); - expect(items[0].teams.items.length).toEqual(2); - expect(items[0].teams.items[0].teamId).toEqual('T1'); - expect(items[0].teams.items[1].teamId).toEqual('T2'); -}); - -test('Named connection 2 way navigation, with with custom @key fields 1:1', async () => { - await GRAPHQL_CLIENT.query( - ` - mutation CreateCTeam { - createCTeam(input: {teamId: "T1", name: "Team 1", cTeamProjectId: "P1"}) { - teamId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateCProject { - createCProject(input: {projectId: "P1", name: "P1", cProjectTeamId: "T1"}) { - projectId - name - } - } - `, - {}, - ); - - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query ListCProjects { - listCProjects { - items { - projectId - name - team { - teamId - name - project { - projectId - name - } - } - } - } - } - `, - {}, - ); - expect(queryResponse.data.listCProjects).toBeDefined(); - const items = queryResponse.data.listCProjects.items; - expect(items.length).toEqual(1); - expect(items[0].projectId).toEqual('P1'); - expect(items[0].team).toBeDefined(); - expect(items[0].team.teamId).toEqual('T1'); - expect(items[0].team.project).toBeDefined(); - expect(items[0].team.project.projectId).toEqual('P1'); -}); - -test('Named connection 2 way navigation, with with custom @key fields 1:M', async () => { - await GRAPHQL_CLIENT.query( - ` - mutation CreateDProject { - createDProject(input: {projectId: "P1", name: "P1"}) { - projectId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateDTeam { - createDTeam(input: {teamId: "T1", name: "Team 1", dTeamProjectId: "P1"}) { - teamId - name - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation CreateDTeam { - createDTeam(input: {teamId: "T2", name: "Team 2", dTeamProjectId: "P1"}) { - teamId - name - } - } - `, - {}, - ); - - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query ListDProjects { - listDProjects { - items { - projectId - name - teams { - items { - teamId - name - project { - projectId - name - } - } - } - } - } - } - `, - {}, - ); - expect(queryResponse.data.listDProjects).toBeDefined(); - const items = queryResponse.data.listDProjects.items; - expect(items.length).toEqual(1); - expect(items[0].projectId).toEqual('P1'); - expect(items[0].teams).toBeDefined(); - expect(items[0].teams.items).toBeDefined(); - expect(items[0].teams.items.length).toEqual(2); - expect(items[0].teams.items[0].teamId).toEqual('T1'); - expect(items[0].teams.items[0].project).toBeDefined(); - expect(items[0].teams.items[0].project.projectId).toEqual('P1'); - expect(items[0].teams.items[1].teamId).toEqual('T2'); - expect(items[0].teams.items[1].project).toBeDefined(); - expect(items[0].teams.items[1].project.projectId).toEqual('P1'); -}); - -test('Unnamed connection with sortField parameter only #2100', async () => { - await GRAPHQL_CLIENT.query( - ` - mutation M11 { - createModel1(input: {id: "M11", sort: 10, name: "M1-1"}) { - id - name - sort - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation M12 { - createModel1(input: {id: "M12", sort: 10, name: "M1-2"}) { - id - name - sort - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation M21 { - createModel2(input: {id: "M21", modelOneSort: 10, model2ConnectionId: "M11"}) { - id - modelOneSort - } - } - `, - {}, - ); - - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query Query { - getModel2(id: "M21") { - id - connection { - id - sort - name - } - } - } - `, - {}, - ); - expect(queryResponse.data.getModel2).toBeDefined(); - const item = queryResponse.data.getModel2; - expect(item.id).toEqual('M21'); - expect(item.connection).toBeDefined(); - expect(item.connection.id).toEqual('M11'); - expect(item.connection.sort).toEqual(10); -}); - -test('Connection with null sort key returns null when getting a single item', async () => { - await GRAPHQL_CLIENT.query( - ` - mutation M11 { - createModel1(input: {id: "Null-M11", sort: 10, name: "M1-1"}) { - id - name - sort - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation M21 { - createModel2(input: {id: "Null-M21", model2ConnectionId: "Null-M11"}) { - id - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation M31 { - createModel3(input: {id: "Null-M31", connectionPK: "Null-M11"}) { - id - connectionPK - } - } - `, - {}, - ); - - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query Query { - getModel2(id: "Null-M21") { - id - connection { - id - } - } - } - `, - {}, - ); - expect(queryResponse.data.getModel2).toBeDefined(); - const item = queryResponse.data.getModel2; - expect(item.id).toEqual('Null-M21'); - expect(item.connection).toEqual(null); - - const queryResponse2 = await GRAPHQL_CLIENT.query( - ` - query Query { - getModel3(id: "Null-M31") { - id - connection { - id - } - } - } - `, - {}, - ); - expect(queryResponse2.data.getModel3).toBeDefined(); - const item2 = queryResponse2.data.getModel3; - expect(item2.id).toEqual('Null-M31'); - expect(item2.connection).toEqual(null); -}); - -test('Connection with null partition key returns null when getting a list of items', async () => { - await GRAPHQL_CLIENT.query( - ` - mutation M11 { - createModel1(input: {id: "Null-List-M11", sort: 909, name: "Null-List-M1-1"}) { - id - name - sort - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation M31 { - createModel3(input: {id: "Null-List-M31", connectionSort: 909, connectionSK: "Null-List-M1-1"}) { - id - connectionSK - } - } - `, - {}, - ); - - await GRAPHQL_CLIENT.query( - ` - mutation M32 { - createModel3(input: {id: "Null-List-M32", connectionPK: "Null-List-M11"}) { - id - connectionPK - } - } - `, - {}, - ); - - const queryResponse = await GRAPHQL_CLIENT.query( - ` - query Query { - getModel3(id: "Null-List-M32") { - id - connections { - items { - id - } - } - } - } - `, - {}, - ); - expect(queryResponse.data.getModel3).toBeDefined(); - const item = queryResponse.data.getModel3; - expect(item.id).toEqual('Null-List-M32'); - expect(item.connections.items.length).toEqual(0); - - const queryResponse2 = await GRAPHQL_CLIENT.query( - ` - query Query { - getModel3(id: "Null-List-M31") { - id - connections { - items { - id - name - } - } - } - } - `, - {}, - ); - expect(queryResponse2.data.getModel3).toBeDefined(); - const item2 = queryResponse2.data.getModel3; - expect(item2.id).toEqual('Null-List-M31'); - expect(item2.connections.items.length).toEqual(1); - expect(item2.connections.items[0].id).toEqual('Null-List-M11'); -}); - -test('Connection with null key attributes returns empty array', async () => { - // https://github.com/aws-amplify/amplify-cli/pull/5153#pullrequestreview-506028382 - const mutationResponse = await GRAPHQL_CLIENT.query( - ` - mutation createModel3WithMissingPKConnectionField { - createModel3(input: {id: "Null-Connection-PK-M34", connectionSort: 909, connectionPK: "unused-pk"}) { - connectionsWithCompositeKey { - items { - id - name - sort - } - } - } - } - `, - {}, - ); - - expect(mutationResponse.data.createModel3).toBeDefined(); - const item = mutationResponse.data.createModel3; - expect(item.connectionsWithCompositeKey.items.length).toEqual(0); - expect(mutationResponse.errors).not.toBeDefined(); - - const mutationResponse2 = await GRAPHQL_CLIENT.query( - ` - mutation createModel4 { - createModel4(input: {id: "1", sort: 1, name: "model4Name"}) { - id - } - } - `, - {}, - ); - - const mutationResponse3 = await GRAPHQL_CLIENT.query( - ` - mutation createModel3WithMissingSortConnectionField { - createModel3(input: {id: "Null-Connection-PK-M34-3", connectionSort: 1, connectionName: "model4Name"}) { - connectionsWithCompositeKey { - items { - id - name - sort - } - } - } - } - `, - {}, - ); - - expect(mutationResponse3.data.createModel3).toBeDefined(); - const item3 = mutationResponse3.data.createModel3; - expect(item3.connectionsWithCompositeKey.items.length).toEqual(0); - expect(mutationResponse3.errors).not.toBeDefined(); - - const mutationResponse4 = await GRAPHQL_CLIENT.query( - ` - mutation createModel3WithAllConnectionFields { - createModel3(input: {id: "Null-Connection-PK-M34-4", connectionSort: 1, connectionName: "model4Name", connectionPK: "1"}) { - connectionsWithCompositeKey { - items { - id - name - sort - } - } - } - } - `, - {}, - ); - - expect(mutationResponse4.data.createModel3).toBeDefined(); - const item4 = mutationResponse4.data.createModel3; - expect(item4.connectionsWithCompositeKey.items.length).toEqual(1); - expect(mutationResponse4.errors).not.toBeDefined(); -}); diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/MultiAuthModelAuthTransformer.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/MultiAuthModelAuthTransformer.e2e.test.ts deleted file mode 100644 index 176a64f94b..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/MultiAuthModelAuthTransformer.e2e.test.ts +++ /dev/null @@ -1,1341 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import { Auth } from 'aws-amplify'; -import AWSAppSyncClient, { AUTH_TYPE } from 'aws-appsync'; -import gql from 'graphql-tag'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { KeyTransformer } from 'graphql-key-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as CognitoClient } from 'aws-sdk/clients/cognitoidentityserviceprovider'; -import { default as S3 } from 'aws-sdk/clients/s3'; -import { default as moment } from 'moment'; -import Role from 'cloudform-types/types/iam/role'; -import UserPoolClient from 'cloudform-types/types/cognito/userPoolClient'; -import IdentityPool from 'cloudform-types/types/cognito/identityPool'; -import IdentityPoolRoleAttachment from 'cloudform-types/types/cognito/identityPoolRoleAttachment'; -import AWS = require('aws-sdk'); -import { createUserPool, createUserPoolClient, configureAmplify, signupUser, authenticateUser } from '../cognitoUtils'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { S3Client } from '../S3Client'; -import { CloudFormationClient } from '../CloudFormationClient'; -import 'isomorphic-fetch'; - -// to deal with bug in cognito-identity-js -(global as any).fetch = require('node-fetch'); - -import { resolveTestRegion } from '../testSetup'; - -// To overcome of the way of how AmplifyJS picks up currentUserCredentials -const anyAWS = AWS as any; - -if (anyAWS && anyAWS.config && anyAWS.config.credentials) { - delete anyAWS.config.credentials; -} - -const REGION = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(REGION); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `MultiAuthModelAuthTransformerTest-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `appsync-multi-auth-transformer-test-bucket-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/multi_auth_model_auth_transform_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; -const AUTH_ROLE_NAME = `${STACK_NAME}-authRole`; -const UNAUTH_ROLE_NAME = `${STACK_NAME}-unauthRole`; -const IDENTITY_POOL_NAME = `MultiAuthModelAuthTransformerTest_${BUILD_TIMESTAMP}_identity_pool`; -const USER_POOL_CLIENTWEB_NAME = `multiauth_${BUILD_TIMESTAMP}_clientweb`; -const USER_POOL_CLIENT_NAME = `multiauth_${BUILD_TIMESTAMP}_client`; - -let GRAPHQL_ENDPOINT = undefined; - -let APIKEY_GRAPHQL_CLIENT: AWSAppSyncClient = undefined; -let USER_POOL_AUTH_CLIENT: AWSAppSyncClient = undefined; -let IAM_UNAUTHCLIENT: AWSAppSyncClient = undefined; - -let USER_POOL_ID = undefined; - -const USERNAME1 = 'user1@test.com'; - -const TMP_PASSWORD = 'Password123!'; -const REAL_PASSWORD = 'Password1234!'; - -const cognitoClient = new CognitoClient({ apiVersion: '2016-04-19', region: REGION }); -const customS3Client = new S3Client(REGION); -const awsS3Client = new S3({ region: REGION }); - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -function deleteDirectory(directory: string) { - const files = fs.readdirSync(directory); - for (const file of files) { - const contentPath = path.join(directory, file); - if (fs.lstatSync(contentPath).isDirectory()) { - deleteDirectory(contentPath); - fs.rmdirSync(contentPath); - } else { - fs.unlinkSync(contentPath); - } - } -} - -beforeAll(async () => { - // Create a stack for the post model with auth enabled. - const validSchema = ` - # Allow anyone to access. This is translated into API_KEY. - type PostPublic @model @auth(rules: [{ allow: public }]) { - id: ID! - title: String - } - - # Allow anyone to access. This is translated to IAM with unauth role. - type PostPublicIAM @model @auth(rules: [{ allow: public, provider: iam }]) { - id: ID! - title: String - } - - # Allow anyone with a valid Amazon Cognito UserPools JWT to access. - type PostPrivate @model @auth(rules: [{ allow: private }]) { - id: ID! - title: String - } - - # Allow anyone with a sigv4 signed request with relevant policy to access. - type PostPrivateIAM @model @auth(rules: [{ allow: private, provider: iam }]) { - id: ID! - title: String - } - - # I have a model that is protected by userPools by default. - # I want to call createPost from my lambda. - type PostOwnerIAM @model - @auth ( - rules: [ - # The cognito user pool owner can CRUD. - { allow: owner }, - # A lambda function using IAM can call Mutation.createPost. - { allow: private, provider: iam, operations: [create] } - ] - ) - { - id: ID! - title: String - owner: String - } - - type PostSecretFieldIAM @model - @auth ( - rules: [ - # The cognito user pool and can CRUD. - { allow: private } - ] - ) - { - id: ID! - title: String - owner: String - secret: String - @auth ( - rules: [ - # Only a lambda function using IAM can create/update this field - { allow: private, provider: iam, operations: [create, update] } - ] - ) - } - - type PostConnection @model @auth(rules:[{allow: public}]){ - id: ID! - title: String! - comments: [CommentConnection] @connection(name: "PostComments") - } - - type CommentConnection @model { - id: ID! - content: String! - post: PostConnection @connection(name: "PostComments") - } - - type PostIAMWithKeys @model - @auth ( - rules: [ - # API Key can CRUD - { allow: public } - # IAM can read - { allow: public, provider: iam, operations: [read] } - ] - ) - @key (name: "byDate", fields: ["type", "date"], queryField: "getPostIAMWithKeysByDate") - { - id: ID! - title: String - type: String - date: AWSDateTime - } - - # This type is for the managed policy slicing, only deployment test in this e2e - type TodoWithExtraLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongName @model(subscriptions:null) @auth(rules:[{allow: private, provider: iam}]) - { - id: ID! - namenamenamenamenamenamenamenamenamenamenamenamenamenamename001: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename002: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename003: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename004: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename005: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename006: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename007: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename008: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename009: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename010: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename011: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename012: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename013: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename014: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename015: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename016: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename017: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename018: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename019: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename020: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename021: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename022: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename023: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename024: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename025: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename026: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename027: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename028: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename029: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename030: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename031: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename032: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename033: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename034: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename035: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename036: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename037: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename038: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename039: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename040: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename041: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename042: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename043: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename044: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename045: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename046: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename047: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename048: String! @auth(rules:[{allow: private, provider: iam}]) - namenamenamenamenamenamenamenamenamenamenamenamenamenamename049: String! @auth(rules:[{allow: private, provider: iam}]) - description: String - } - `; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelConnectionTransformer(), - new KeyTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'API_KEY', - apiKeyConfig: { - description: 'E2E Test API Key', - apiKeyExpirationDays: 300, - }, - }, - { - authenticationType: 'AWS_IAM', - }, - ], - }, - }), - ], - }); - - try { - await awsS3Client.createBucket({ Bucket: BUCKET_NAME }).promise(); - } catch (e) { - console.error(`Failed to create bucket: ${e}`); - } - const userPoolResponse = await createUserPool(cognitoClient, `UserPool${STACK_NAME}`); - USER_POOL_ID = userPoolResponse.UserPool.Id; - const userPoolClientResponse = await createUserPoolClient(cognitoClient, USER_POOL_ID, `UserPool${STACK_NAME}`); - const userPoolClientId = userPoolClientResponse.UserPoolClient.ClientId; - - try { - // Clean the bucket - const out = transformer.transform(validSchema); - - const authRole = new Role({ - RoleName: AUTH_ROLE_NAME, - AssumeRolePolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Sid: '', - Effect: 'Allow', - Principal: { - Federated: 'cognito-identity.amazonaws.com', - }, - Action: 'sts:AssumeRoleWithWebIdentity', - Condition: { - StringEquals: { - 'cognito-identity.amazonaws.com:aud': { Ref: 'IdentityPool' }, - }, - 'ForAnyValue:StringLike': { - 'cognito-identity.amazonaws.com:amr': 'authenticated', - }, - }, - }, - ], - }, - }); - - const unauthRole = new Role({ - RoleName: UNAUTH_ROLE_NAME, - AssumeRolePolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Sid: '', - Effect: 'Allow', - Principal: { - Federated: 'cognito-identity.amazonaws.com', - }, - Action: 'sts:AssumeRoleWithWebIdentity', - Condition: { - StringEquals: { - 'cognito-identity.amazonaws.com:aud': { Ref: 'IdentityPool' }, - }, - 'ForAnyValue:StringLike': { - 'cognito-identity.amazonaws.com:amr': 'unauthenticated', - }, - }, - }, - ], - }, - Policies: [ - new Role.Policy({ - PolicyName: 'appsync-unauthrole-policy', - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Action: ['appsync:GraphQL'], - Resource: [ - { - 'Fn::Join': [ - '', - [ - 'arn:aws:appsync:', - { Ref: 'AWS::Region' }, - ':', - { Ref: 'AWS::AccountId' }, - ':apis/', - { - 'Fn::GetAtt': ['GraphQLAPI', 'ApiId'], - }, - '/*', - ], - ], - }, - ], - }, - ], - }, - }), - ], - }); - - const identityPool = new IdentityPool({ - IdentityPoolName: IDENTITY_POOL_NAME, - CognitoIdentityProviders: [ - { - ClientId: { - Ref: 'UserPoolClient', - }, - ProviderName: { - 'Fn::Sub': [ - 'cognito-idp.${region}.amazonaws.com/${client}', - { - region: { - Ref: 'AWS::Region', - }, - client: USER_POOL_ID, - }, - ], - }, - } as unknown, - { - ClientId: { - Ref: 'UserPoolClientWeb', - }, - ProviderName: { - 'Fn::Sub': [ - 'cognito-idp.${region}.amazonaws.com/${client}', - { - region: { - Ref: 'AWS::Region', - }, - client: USER_POOL_ID, - }, - ], - }, - } as unknown, - ], - AllowUnauthenticatedIdentities: true, - }); - - const identityPoolRoleMap = new IdentityPoolRoleAttachment({ - IdentityPoolId: { Ref: 'IdentityPool' } as unknown as string, - Roles: { - unauthenticated: { 'Fn::GetAtt': ['UnauthRole', 'Arn'] }, - authenticated: { 'Fn::GetAtt': ['AuthRole', 'Arn'] }, - }, - }); - - const userPoolClientWeb = new UserPoolClient({ - ClientName: USER_POOL_CLIENTWEB_NAME, - RefreshTokenValidity: 30, - UserPoolId: USER_POOL_ID, - }); - - const userPoolClient = new UserPoolClient({ - ClientName: USER_POOL_CLIENT_NAME, - GenerateSecret: true, - RefreshTokenValidity: 30, - UserPoolId: USER_POOL_ID, - }); - - out.rootStack.Resources.IdentityPool = identityPool; - out.rootStack.Resources.IdentityPoolRoleMap = identityPoolRoleMap; - out.rootStack.Resources.UserPoolClientWeb = userPoolClientWeb; - out.rootStack.Resources.UserPoolClient = userPoolClient; - out.rootStack.Outputs.IdentityPoolId = { Value: { Ref: 'IdentityPool' } }; - out.rootStack.Outputs.IdentityPoolName = { Value: { 'Fn::GetAtt': ['IdentityPool', 'Name'] } }; - - out.rootStack.Resources.AuthRole = authRole; - out.rootStack.Outputs.AuthRoleArn = { Value: { 'Fn::GetAtt': ['AuthRole', 'Arn'] } }; - out.rootStack.Resources.UnauthRole = unauthRole; - out.rootStack.Outputs.UnauthRoleArn = { Value: { 'Fn::GetAtt': ['UnauthRole', 'Arn'] } }; - - // Since we're doing the policy here we've to remove the transformer generated artifacts from - // the generated stack. - const maxPolicyCount = 10; - for (let i = 0; i < maxPolicyCount; i++) { - const paddedIndex = `${i + 1}`.padStart(2, '0'); - const authResourceName = `${ResourceConstants.RESOURCES.AuthRolePolicy}${paddedIndex}`; - const unauthResourceName = `${ResourceConstants.RESOURCES.UnauthRolePolicy}${paddedIndex}`; - - if (out.rootStack.Resources[authResourceName]) { - delete out.rootStack.Resources[authResourceName]; - } - - if (out.rootStack.Resources[unauthResourceName]) { - delete out.rootStack.Resources[unauthResourceName]; - } - } - - delete out.rootStack.Parameters.authRoleName; - delete out.rootStack.Parameters.unauthRoleName; - - for (const key of Object.keys(out.rootStack.Resources)) { - if ( - out.rootStack.Resources[key].Properties && - out.rootStack.Resources[key].Properties.Parameters && - out.rootStack.Resources[key].Properties.Parameters.unauthRoleName - ) { - delete out.rootStack.Resources[key].Properties.Parameters.unauthRoleName; - } - - if ( - out.rootStack.Resources[key].Properties && - out.rootStack.Resources[key].Properties.Parameters && - out.rootStack.Resources[key].Properties.Parameters.authRoleName - ) { - delete out.rootStack.Resources[key].Properties.Parameters.authRoleName; - } - } - - for (const stackKey of Object.keys(out.stacks)) { - const stack = out.stacks[stackKey]; - - for (const key of Object.keys(stack.Resources)) { - if (stack.Parameters && stack.Parameters.unauthRoleName) { - delete stack.Parameters.unauthRoleName; - } - if (stack.Parameters && stack.Parameters.authRoleName) { - delete stack.Parameters.authRoleName; - } - if ( - stack.Resources[key].Properties && - stack.Resources[key].Properties.Parameters && - stack.Resources[key].Properties.Parameters.unauthRoleName - ) { - delete stack.Resources[key].Properties.Parameters.unauthRoleName; - } - if ( - stack.Resources[key].Properties && - stack.Resources[key].Properties.Parameters && - stack.Resources[key].Properties.Parameters.authRoleName - ) { - delete stack.Resources[key].Properties.Parameters.authRoleName; - } - } - } - - const params = { - CreateAPIKey: '1', - AuthCognitoUserPoolId: USER_POOL_ID, - }; - - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - params, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - GRAPHQL_ENDPOINT = getApiEndpoint(finishedStack.Outputs); - - const apiKey = getApiKey(finishedStack.Outputs); - expect(apiKey).toBeTruthy(); - - const getIdentityPoolId = outputValueSelector('IdentityPoolId'); - const identityPoolId = getIdentityPoolId(finishedStack.Outputs); - expect(identityPoolId).toBeTruthy(); - - // Verify we have all the details - expect(GRAPHQL_ENDPOINT).toBeTruthy(); - expect(USER_POOL_ID).toBeTruthy(); - expect(userPoolClientId).toBeTruthy(); - - // Configure Amplify, create users, and sign in. - configureAmplify(USER_POOL_ID, userPoolClientId, identityPoolId); - - const unauthCredentials = await Auth.currentCredentials(); - - IAM_UNAUTHCLIENT = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: REGION, - auth: { - type: AUTH_TYPE.AWS_IAM, - credentials: { - accessKeyId: unauthCredentials.accessKeyId, - secretAccessKey: unauthCredentials.secretAccessKey, - sessionToken: unauthCredentials.sessionToken, - }, - }, - offlineConfig: { - keyPrefix: 'iam', - }, - disableOffline: true, - }); - - await signupUser(USER_POOL_ID, USERNAME1, TMP_PASSWORD); - const authRes = await authenticateUser(USERNAME1, TMP_PASSWORD, REAL_PASSWORD); - const idToken = authRes.getIdToken().getJwtToken(); - - USER_POOL_AUTH_CLIENT = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: REGION, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: () => idToken, - }, - offlineConfig: { - keyPrefix: 'userPools', - }, - disableOffline: true, - }); - - APIKEY_GRAPHQL_CLIENT = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: REGION, - auth: { - type: AUTH_TYPE.API_KEY, - apiKey: apiKey, - }, - offlineConfig: { - keyPrefix: 'apikey', - }, - disableOffline: true, - }); - - // Wait for any propagation to avoid random - // "The security token included in the request is invalid" errors - await new Promise((res) => setTimeout(() => res(), 5000)); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf, { cognitoClient, userPoolId: USER_POOL_ID }); -}); - -/** - * Test queries below - */ -test(`'public' authStrategy`, async () => { - try { - const createMutation = gql` - mutation { - createPostPublic(input: { title: "Hello, World!" }) { - id - title - } - } - `; - - const getQuery = gql` - query ($id: ID!) { - getPostPublic(id: $id) { - id - title - } - } - `; - - const response = await APIKEY_GRAPHQL_CLIENT.mutate({ - mutation: createMutation, - fetchPolicy: 'no-cache', - }); - expect(response.data.createPostPublic.id).toBeDefined(); - expect(response.data.createPostPublic.title).toEqual('Hello, World!'); - - const postId = response.data.createPostPublic.id; - - // Authenticate User Pools user must fail - try { - await USER_POOL_AUTH_CLIENT.query({ - query: getQuery, - fetchPolicy: 'no-cache', - variables: { - id: postId, - }, - }); - - expect(true).toBe(false); - } catch (e) { - expect(e.message).toMatch('GraphQL error: Not Authorized to access getPostPublic on type Query'); - } - - // IAM with unauth role must fail - try { - await IAM_UNAUTHCLIENT.query({ - query: getQuery, - fetchPolicy: 'no-cache', - variables: { - id: postId, - }, - }); - - expect(true).toBe(false); - } catch (e) { - expect(e.message).toMatch('GraphQL error: Not Authorized to access getPostPublic on type Query'); - } - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -test(`'public' provider: 'iam' authStrategy`, async () => { - try { - const createMutation = gql` - mutation { - createPostPublicIAM(input: { title: "Hello, World!" }) { - id - title - } - } - `; - - const getQuery = gql` - query ($id: ID!) { - getPostPublicIAM(id: $id) { - id - title - } - } - `; - - const response = await IAM_UNAUTHCLIENT.mutate({ - mutation: createMutation, - fetchPolicy: 'no-cache', - }); - expect(response.data.createPostPublicIAM.id).toBeDefined(); - expect(response.data.createPostPublicIAM.title).toEqual('Hello, World!'); - - const postId = response.data.createPostPublicIAM.id; - - // Authenticate User Pools user must fail - try { - await USER_POOL_AUTH_CLIENT.query({ - query: getQuery, - fetchPolicy: 'no-cache', - variables: { - id: postId, - }, - }); - - expect(true).toBe(false); - } catch (e) { - expect(e.message).toMatch('GraphQL error: Not Authorized to access getPostPublicIAM on type Query'); - } - - // API Key must fail - try { - await APIKEY_GRAPHQL_CLIENT.query({ - query: getQuery, - fetchPolicy: 'no-cache', - variables: { - id: postId, - }, - }); - - expect(true).toBe(false); - } catch (e) { - expect(e.message).toMatch('GraphQL error: Not Authorized to access getPostPublicIAM on type Query'); - } - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -test(`'private' authStrategy`, async () => { - try { - const createMutation = gql` - mutation { - createPostPrivate(input: { title: "Hello, World!" }) { - id - title - } - } - `; - - const getQuery = gql` - query ($id: ID!) { - getPostPrivate(id: $id) { - id - title - } - } - `; - - const response = await USER_POOL_AUTH_CLIENT.mutate({ - mutation: createMutation, - fetchPolicy: 'no-cache', - }); - expect(response.data.createPostPrivate.id).toBeDefined(); - expect(response.data.createPostPrivate.title).toEqual('Hello, World!'); - - const postId = response.data.createPostPrivate.id; - - // Authenticate API Key fail - try { - await APIKEY_GRAPHQL_CLIENT.query({ - query: getQuery, - fetchPolicy: 'no-cache', - variables: { - id: postId, - }, - }); - - expect(true).toBe(false); - } catch (e) { - expect(e.message).toMatch('GraphQL error: Not Authorized to access getPostPrivate on type Query'); - } - - // IAM with unauth role must fail - try { - await IAM_UNAUTHCLIENT.query({ - query: getQuery, - fetchPolicy: 'no-cache', - variables: { - id: postId, - }, - }); - - expect(true).toBe(false); - } catch (e) { - expect(e.message).toMatch('GraphQL error: Not Authorized to access getPostPrivate on type Query'); - } - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -test(`'private' provider: 'iam' authStrategy`, async () => { - // This test reuses the unauth role, but any IAM credentials would work - // in real world scenarios, we've to see if provider override works. - try { - const createMutation = gql` - mutation { - createPostPrivateIAM(input: { title: "Hello, World!" }) { - id - title - } - } - `; - - const getQuery = gql` - query ($id: ID!) { - getPostPrivateIAM(id: $id) { - id - title - } - } - `; - - const response = await IAM_UNAUTHCLIENT.mutate({ - mutation: createMutation, - fetchPolicy: 'no-cache', - }); - expect(response.data.createPostPrivateIAM.id).toBeDefined(); - expect(response.data.createPostPrivateIAM.title).toEqual('Hello, World!'); - - const postId = response.data.createPostPrivateIAM.id; - - // Authenticate User Pools user must fail - try { - await USER_POOL_AUTH_CLIENT.query({ - query: getQuery, - fetchPolicy: 'no-cache', - variables: { - id: postId, - }, - }); - - expect(true).toBe(false); - } catch (e) { - expect(e.message).toMatch('GraphQL error: Not Authorized to access getPostPrivateIAM on type Query'); - } - - // API Key must fail - try { - await APIKEY_GRAPHQL_CLIENT.query({ - query: getQuery, - fetchPolicy: 'no-cache', - variables: { - id: postId, - }, - }); - - expect(true).toBe(false); - } catch (e) { - expect(e.message).toMatch('GraphQL error: Not Authorized to access getPostPrivateIAM on type Query'); - } - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -test(`'private' provider: 'iam' authStrategy`, async () => { - // This test reuses the unauth role, but any IAM credentials would work - // in real world scenarios, we've to see if provider override works. - - // - Create UserPool - Verify owner - // - Create IAM - Verify owner (blank) - // - Get UserPool owner - Verify success - // - Get UserPool non-owner - Verify deny - // - Get IAM - Verify deny - // - Get API Key - Verify deny - - try { - const createMutation = gql` - mutation { - createPostOwnerIAM(input: { title: "Hello, World!" }) { - id - title - owner - } - } - `; - - const getQuery = gql` - query ($id: ID!) { - getPostOwnerIAM(id: $id) { - id - title - owner - } - } - `; - - const response = await USER_POOL_AUTH_CLIENT.mutate({ - mutation: createMutation, - fetchPolicy: 'no-cache', - }); - expect(response.data.createPostOwnerIAM.id).toBeDefined(); - expect(response.data.createPostOwnerIAM.title).toEqual('Hello, World!'); - expect(response.data.createPostOwnerIAM.owner).toEqual(USERNAME1); - - const postIdOwner = response.data.createPostOwnerIAM.id; - - const responseIAM = await IAM_UNAUTHCLIENT.mutate({ - mutation: createMutation, - fetchPolicy: 'no-cache', - }); - expect(responseIAM.data.createPostOwnerIAM.id).toBeDefined(); - expect(responseIAM.data.createPostOwnerIAM.title).toEqual('Hello, World!'); - expect(responseIAM.data.createPostOwnerIAM.owner).toBeNull(); - - const postIdIAM = responseIAM.data.createPostOwnerIAM.id; - - const responseGetUserPool = await USER_POOL_AUTH_CLIENT.query({ - query: getQuery, - fetchPolicy: 'no-cache', - variables: { - id: postIdOwner, - }, - }); - - expect(responseGetUserPool.data.getPostOwnerIAM.id).toBeDefined(); - expect(responseGetUserPool.data.getPostOwnerIAM.title).toEqual('Hello, World!'); - expect(responseGetUserPool.data.getPostOwnerIAM.owner).toEqual(USERNAME1); - - try { - await USER_POOL_AUTH_CLIENT.query({ - query: getQuery, - fetchPolicy: 'no-cache', - variables: { - id: postIdIAM, - }, - }); - - expect(true).toBe(false); - } catch (e) { - expect(e.message).toMatch('GraphQL error: Not Authorized to access getPostOwnerIAM on type Query'); - } - - // IAM user must fail - try { - await IAM_UNAUTHCLIENT.query({ - query: getQuery, - fetchPolicy: 'no-cache', - variables: { - id: postIdOwner, - }, - }); - - expect(true).toBe(false); - } catch (e) { - expect(e.message).toMatch('GraphQL error: Not Authorized to access getPostOwnerIAM on type Query'); - } - - // API Key must fail - try { - await APIKEY_GRAPHQL_CLIENT.query({ - query: getQuery, - variables: { - id: postIdOwner, - }, - }); - - expect(true).toBe(false); - } catch (e) { - expect(e.message).toMatch('GraphQL error: Not Authorized to access getPostOwnerIAM on type Query'); - } - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -describe(`Test IAM protected field operations`, () => { - // This test reuses the unauth role, but any IAM credentials would work - // in real world scenarios, we've to see if provider override works. - - const createMutation = gql` - mutation { - createPostSecretFieldIAM(input: { title: "Hello, World!" }) { - id - title - } - } - `; - - const createMutationWithSecret = gql` - mutation { - createPostSecretFieldIAM(input: { title: "Hello, World!", secret: "42" }) { - id - title - secret - } - } - `; - - const getQuery = gql` - query ($id: ID!) { - getPostSecretFieldIAM(id: $id) { - id - title - } - } - `; - - const getQueryWithSecret = gql` - query ($id: ID!) { - getPostSecretFieldIAM(id: $id) { - id - title - secret - } - } - `; - - let postIdNoSecret = ''; - let postIdSecret = ''; - - beforeAll(async () => { - try { - // - Create UserPool - no secret - Success - const response = await USER_POOL_AUTH_CLIENT.mutate({ - mutation: createMutation, - fetchPolicy: 'no-cache', - }); - - postIdNoSecret = response.data.createPostSecretFieldIAM.id; - - // - Create IAM - with secret - Success - const responseIAMSecret = await IAM_UNAUTHCLIENT.mutate({ - mutation: createMutationWithSecret, - fetchPolicy: 'no-cache', - }); - - postIdSecret = responseIAMSecret.data.createPostSecretFieldIAM.id; - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } - }); - - it('Get UserPool - Succeed', async () => { - const responseGetUserPool = await USER_POOL_AUTH_CLIENT.query({ - query: getQuery, - fetchPolicy: 'no-cache', - variables: { - id: postIdNoSecret, - }, - }); - expect(responseGetUserPool.data.getPostSecretFieldIAM.id).toBeDefined(); - expect(responseGetUserPool.data.getPostSecretFieldIAM.title).toEqual('Hello, World!'); - }); - - it('Get UserPool with secret - Fail', async () => { - expect.assertions(1); - await expect( - USER_POOL_AUTH_CLIENT.query({ - query: getQueryWithSecret, - fetchPolicy: 'no-cache', - variables: { - id: postIdSecret, - }, - }), - ).rejects.toThrow('GraphQL error: Not Authorized to access secret on type PostSecretFieldIAM'); - }); - - it('Get IAM with secret - Fail (only create and update)', async () => { - expect.assertions(1); - await expect( - IAM_UNAUTHCLIENT.query({ - query: getQueryWithSecret, - fetchPolicy: 'no-cache', - variables: { - id: postIdSecret, - }, - }), - ).rejects.toThrow('GraphQL error: Not Authorized to access getPostSecretFieldIAM on type Query'); - }); -}); - -describe(`Connection tests with @auth on type`, () => { - const createPostMutation = gql` - mutation { - createPostConnection(input: { title: "Hello, World!" }) { - id - title - } - } - `; - - const createCommentMutation = gql` - mutation ($postId: ID!) { - createCommentConnection(input: { content: "Comment", commentConnectionPostId: $postId }) { - id - content - } - } - `; - - const getPostQuery = gql` - query ($postId: ID!) { - getPostConnection(id: $postId) { - id - title - } - } - `; - - const getPostQueryWithComments = gql` - query ($postId: ID!) { - getPostConnection(id: $postId) { - id - title - comments { - items { - id - content - } - } - } - } - `; - - const getCommentQuery = gql` - query ($commentId: ID!) { - getCommentConnection(id: $commentId) { - id - content - } - } - `; - - const getCommentWithPostQuery = gql` - query ($commentId: ID!) { - getCommentConnection(id: $commentId) { - id - content - post { - id - title - } - } - } - `; - - let postId = ''; - let commentId = ''; - - beforeAll(async () => { - try { - // Add a comment with ApiKey - Succeed - const response = await APIKEY_GRAPHQL_CLIENT.mutate({ - mutation: createPostMutation, - fetchPolicy: 'no-cache', - }); - - postId = response.data.createPostConnection.id; - - // Add a comment with UserPool - Succeed - const commentResponse = await USER_POOL_AUTH_CLIENT.mutate({ - mutation: createCommentMutation, - fetchPolicy: 'no-cache', - variables: { - postId, - }, - }); - - commentId = commentResponse.data.createCommentConnection.id; - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } - }); - - it('Create a Post with UserPool - Fail', async () => { - expect.assertions(1); - await expect( - USER_POOL_AUTH_CLIENT.mutate({ - mutation: createPostMutation, - fetchPolicy: 'no-cache', - }), - ).rejects.toThrow('GraphQL error: Not Authorized to access createPostConnection on type Mutation'); - }); - - it('Add a comment with ApiKey - Fail', async () => { - expect.assertions(1); - await expect( - APIKEY_GRAPHQL_CLIENT.mutate({ - mutation: createCommentMutation, - fetchPolicy: 'no-cache', - variables: { - postId, - }, - }), - ).rejects.toThrow('Not Authorized to access createCommentConnection on type Mutation'); - }); - - it('Get Post with ApiKey - Succeed', async () => { - const responseGetPost = await APIKEY_GRAPHQL_CLIENT.query({ - query: getPostQuery, - fetchPolicy: 'no-cache', - variables: { - postId, - }, - }); - expect(responseGetPost.data.getPostConnection.id).toEqual(postId); - expect(responseGetPost.data.getPostConnection.title).toEqual('Hello, World!'); - }); - - it('Get Post+Comments with ApiKey - Fail', async () => { - expect.assertions(1); - await expect( - APIKEY_GRAPHQL_CLIENT.query({ - query: getPostQueryWithComments, - fetchPolicy: 'no-cache', - variables: { - postId, - }, - }), - ).rejects.toThrow('Not Authorized to access items on type ModelCommentConnectionConnection'); - }); - - it('Get Post with UserPool - Fail', async () => { - expect.assertions(1); - await expect( - USER_POOL_AUTH_CLIENT.query({ - query: getPostQuery, - fetchPolicy: 'no-cache', - variables: { - postId, - }, - }), - ).rejects.toThrow('Not Authorized to access getPostConnection on type Query'); - }); - - it('Get Comment with UserPool - Succeed', async () => { - const responseGetComment = await USER_POOL_AUTH_CLIENT.query({ - query: getCommentQuery, - fetchPolicy: 'no-cache', - variables: { - commentId, - }, - }); - expect(responseGetComment.data.getCommentConnection.id).toEqual(commentId); - expect(responseGetComment.data.getCommentConnection.content).toEqual('Comment'); - }); - - it('Get Comment with ApiKey - Fail', async () => { - expect.assertions(1); - await expect( - APIKEY_GRAPHQL_CLIENT.query({ - query: getCommentQuery, - fetchPolicy: 'no-cache', - variables: { - commentId, - }, - }), - ).rejects.toThrow('Not Authorized to access getCommentConnection on type Query'); - }); - - it('Get Comment with Post with UserPool - Succeed, but null for Post field', async () => { - const responseGetComment = await USER_POOL_AUTH_CLIENT.query({ - query: getCommentWithPostQuery, - errorPolicy: 'all', - fetchPolicy: 'no-cache', - variables: { - commentId, - }, - }); - expect(responseGetComment.data.getCommentConnection.id).toEqual(commentId); - expect(responseGetComment.data.getCommentConnection.content).toEqual('Comment'); - expect(responseGetComment.data.getCommentConnection.post).toBeNull(); - }); -}); - -describe(`IAM Tests`, () => { - const createMutation = gql` - mutation { - createPostIAMWithKeys(input: { title: "Hello, World!", type: "Post", date: "2019-01-01T00:00:00Z" }) { - id - title - type - date - } - } - `; - - const getPostIAMWithKeysByDate = gql` - query { - getPostIAMWithKeysByDate(type: "Post") { - items { - id - title - type - date - } - } - } - `; - - let postId = ''; - - beforeAll(async () => { - try { - // - Create API Key - Success - const response = await APIKEY_GRAPHQL_CLIENT.mutate({ - mutation: createMutation, - fetchPolicy: 'no-cache', - }); - - postId = response.data.createPostIAMWithKeys.id; - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } - }); - - it('Execute @key query - Succeed', async () => { - const response = await IAM_UNAUTHCLIENT.query({ - query: getPostIAMWithKeysByDate, - fetchPolicy: 'no-cache', - }); - expect(response.data.getPostIAMWithKeysByDate.items).toBeDefined(); - expect(response.data.getPostIAMWithKeysByDate.items.length).toEqual(1); - const post = response.data.getPostIAMWithKeysByDate.items[0]; - expect(post.id).toEqual(postId); - expect(post.title).toEqual('Hello, World!'); - expect(post.type).toEqual('Post'); - expect(post.date).toEqual('2019-01-01T00:00:00Z'); - }); -}); diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/NestedStacksTest.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/NestedStacksTest.e2e.test.ts deleted file mode 100644 index 3e7bdfaf3c..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/NestedStacksTest.e2e.test.ts +++ /dev/null @@ -1,110 +0,0 @@ -import fs = require('fs'); -import path = require('path'); -import { - ObjectTypeDefinitionNode, - parse, - FieldDefinitionNode, - DocumentNode, - DefinitionNode, - Kind, - InputObjectTypeDefinitionNode, -} from 'graphql'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; - -jest.setTimeout(2000000); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -test('custom root types with additional fields.', () => { - const validSchema = ` - type Query { - additionalQueryField: String - } - type Mutation { - additionalMutationField: String - } - type Subscription { - additionalSubscriptionField: String - } - type Post @model { - id: ID! - title: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [new DynamoDBModelTransformer()], - }); - // GetAttGraphQLAPIId - const out = transformer.transform(validSchema); - // fs.writeFileSync('./out.json', JSON.stringify(out, null, 4)); - const mainStack = out.rootStack; - const postStack = out.stacks.Post; - expect(mainStack).toBeDefined(); - expect(postStack).toBeDefined(); - const schema = out.schema; - expect(schema).toBeDefined(); - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - const queryType = getObjectType(parsed, 'Query'); - expectFields(queryType, ['getPost', 'listPosts', 'additionalQueryField']); - const mutationType = getObjectType(parsed, 'Mutation'); - expectFields(mutationType, ['createPost', 'updatePost', 'deletePost', 'additionalMutationField']); - const subscriptionType = getObjectType(parsed, 'Subscription'); - expectFields(subscriptionType, ['onCreatePost', 'onUpdatePost', 'onDeletePost', 'additionalSubscriptionField']); -}); - -function expectFields(type: ObjectTypeDefinitionNode, fields: string[]) { - for (const fieldName of fields) { - const foundField = type.fields.find((f: FieldDefinitionNode) => f.name.value === fieldName); - expect(foundField).toBeDefined(); - } -} - -function doNotExpectFields(type: ObjectTypeDefinitionNode, fields: string[]) { - for (const fieldName of fields) { - expect(type.fields.find((f: FieldDefinitionNode) => f.name.value === fieldName)).toBeUndefined(); - } -} - -function getObjectType(doc: DocumentNode, type: string): ObjectTypeDefinitionNode | undefined { - return doc.definitions.find((def: DefinitionNode) => def.kind === Kind.OBJECT_TYPE_DEFINITION && def.name.value === type) as - | ObjectTypeDefinitionNode - | undefined; -} - -function getInputType(doc: DocumentNode, type: string): InputObjectTypeDefinitionNode | undefined { - return doc.definitions.find((def: DefinitionNode) => def.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION && def.name.value === type) as - | InputObjectTypeDefinitionNode - | undefined; -} - -function verifyInputCount(doc: DocumentNode, type: string, count: number): boolean { - return doc.definitions.filter((def) => def.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION && def.name.value === type).length == count; -} - -function cleanUpFiles(directory: string) { - let files = fs.readdirSync(directory); - for (const file of files) { - const dir = path.join(directory, file); - if (!fs.lstatSync(dir).isDirectory()) { - fs.unlinkSync(dir); - } else { - cleanUpFiles(dir); - } - } - fs.rmdirSync(directory); -} - -function readFile(filePath: string) { - return fs.readFileSync(filePath, 'utf8'); -} diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/NewConnectionTransformer.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/NewConnectionTransformer.e2e.test.ts deleted file mode 100644 index 57d32aae00..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/NewConnectionTransformer.e2e.test.ts +++ /dev/null @@ -1,621 +0,0 @@ -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform, DeploymentResources } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { KeyTransformer } from 'graphql-key-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as S3 } from 'aws-sdk/clients/s3'; -import { default as moment } from 'moment'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { GraphQLClient } from '../GraphQLClient'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { S3Client } from '../S3Client'; -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `NewConnectionTransformerTest-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `appsync-new-connection-transformer-test-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/new_connection_transform_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; - -let GRAPHQL_CLIENT: GraphQLClient = undefined; - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -beforeAll(async () => { - const validSchema = ` -type Child - @model - @key(fields: ["id", "name"]) -{ - id: ID! - name: String! - - parents: [Parent] @connection(keyName: "byChild", fields: ["id"]) -} - -type Parent - @model - @key(name: "byChild", fields: ["childID", "childName"]) -{ - id: ID! - childID: ID! - childName: String! - - child: Child @connection(fields: ["childID", "childName"]) -} - -type User - @model - @key(fields: ["id", "name", "surname"]) -{ - id: ID! - name: String! - surname: String! - - friendships: [Friendship] @connection(keyName: "byUser", fields: ["id"]) -} - -type Friendship - @model - @key(name: "byUser", fields: ["userID", "friendID"]) -{ - id: ID! - userID: ID! - friendID: ID! - - friend: [User] @connection(fields: ["friendID"]) -} - -type UserModel - @model - @key(fields: ["id", "rollNumber"]) - @key(name: "composite", fields: ["id", "name", "surname"]) -{ - id: ID! - rollNumber: Int! - name: String! - surname: String! - - authorPosts: [PostAuthor] @connection(keyName: "byAuthor", fields: ["id"]) -} - - -type PostModel @model { - id: ID! - authorID: ID! - authorName: String! - authorSurname: String! - postContents: [String] - - authors: [UserModel] @connection(keyName: "composite", fields: ["authorID", "authorName", "authorSurname"]) - singleAuthor: User @connection(fields: ["authorID", "authorName", "authorSurname"]) -} - -type Post @model { - id: ID! - authorID: ID! - postContents: [String] - authors: [User] @connection(fields: ["authorID"], limit: 50) -} - -type PostAuthor - @model - @key(name: "byAuthor", fields: ["authorID", "postID"]) -{ - id: ID! - authorID: ID! - postID: ID! - - post: Post @connection(fields: ["postID"]) -} -`; - let out: DeploymentResources = undefined; - try { - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new KeyTransformer(), - new ModelConnectionTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - out = transformer.transform(validSchema); - } catch (e) { - console.error(`Failed to transform schema: ${e}`); - expect(true).toEqual(false); - } - try { - await awsS3Client - .createBucket({ - Bucket: BUCKET_NAME, - }) - .promise(); - } catch (e) { - console.error(`Failed to create S3 bucket: ${e}`); - expect(true).toEqual(false); - } - try { - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { CreateAPIKey: '1' }, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - // Arbitrary wait to make sure everything is ready. - await cf.wait(5, () => Promise.resolve()); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - const endpoint = getApiEndpoint(finishedStack.Outputs); - const apiKey = getApiKey(finishedStack.Outputs); - expect(apiKey).toBeDefined(); - expect(endpoint).toBeDefined(); - GRAPHQL_CLIENT = new GraphQLClient(endpoint, { 'x-api-key': apiKey }); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf); -}); - -/** - * Test queries below - */ - -test('Parent.child getItem', async () => { - const createChild = await GRAPHQL_CLIENT.query( - `mutation { - createChild(input: { id: "1", name: "child1" }) { - id - name - } - }`, - {}, - ); - expect(createChild.data.createChild.id).toBeDefined(); - expect(createChild.data.createChild.name).toEqual('child1'); - const createParent = await GRAPHQL_CLIENT.query( - `mutation { - createParent(input: { childID: "1", childName: "${createChild.data.createChild.name}" }) { - id - childID - childName - } - }`, - {}, - ); - expect(createParent.data.createParent.id).toBeDefined(); - expect(createParent.data.createParent.childID).toEqual(createChild.data.createChild.id); - expect(createParent.data.createParent.childName).toEqual(createChild.data.createChild.name); - const queryParent = await GRAPHQL_CLIENT.query( - `query { - getParent(id: "${createParent.data.createParent.id}") { - id - child { - id - name - } - } - }`, - {}, - ); - expect(queryParent.data.getParent).toBeDefined(); - const child = queryParent.data.getParent.child; - expect(child.id).toEqual(createParent.data.createParent.childID); - expect(child.name).toEqual(createParent.data.createParent.childName); -}); - -test('Child.parents query', async () => { - const createChild = await GRAPHQL_CLIENT.query( - `mutation { - createChild(input: { id: "2", name: "child2" }) { - id - name - } - }`, - {}, - ); - expect(createChild.data.createChild.id).toBeDefined(); - expect(createChild.data.createChild.name).toEqual('child2'); - - const createParent1 = await GRAPHQL_CLIENT.query( - `mutation { - createParent(input: { childID: "${createChild.data.createChild.id}", childName: "${createChild.data.createChild.name}" }) { - id - childID - childName - } - }`, - {}, - ); - expect(createParent1.data.createParent.id).toBeDefined(); - expect(createParent1.data.createParent.childID).toEqual(createChild.data.createChild.id); - expect(createParent1.data.createParent.childName).toEqual(createChild.data.createChild.name); - - const queryChild = await GRAPHQL_CLIENT.query( - `query { - getChild(id: "${createChild.data.createChild.id}", name: "${createChild.data.createChild.name}") { - id - parents { - items { - id - childID - childName - } - } - } - }`, - {}, - ); - expect(queryChild.data.getChild).toBeDefined(); - const items = queryChild.data.getChild.parents.items; - expect(items.length).toEqual(1); - expect(items[0].id).toEqual(createParent1.data.createParent.id); - expect(items[0].childID).toEqual(createParent1.data.createParent.childID); - expect(items[0].childName).toEqual(createParent1.data.createParent.childName); -}); - -test('PostModel.singleAuthor GetItem with composite sortkey', async () => { - const createUser = await GRAPHQL_CLIENT.query( - `mutation { - createUser(input: { id: "123", name: "Bob", surname: "Rob" }) { - id - name - surname - } - }`, - {}, - ); - - expect(createUser.data.createUser.id).toBeDefined(); - expect(createUser.data.createUser.name).toEqual('Bob'); - expect(createUser.data.createUser.surname).toEqual('Rob'); - const createPostModel = await GRAPHQL_CLIENT.query( - `mutation { - createPostModel(input: { authorID: "${createUser.data.createUser.id}", - authorName: "${createUser.data.createUser.name}", - authorSurname: "${createUser.data.createUser.surname}", - postContents: "potato" }) { - id - authorID - authorName - authorSurname - postContents - } - }`, - {}, - ); - expect(createPostModel.data.createPostModel.id).toBeDefined(); - expect(createPostModel.data.createPostModel.authorID).toEqual(createUser.data.createUser.id); - expect(createPostModel.data.createPostModel.authorName).toEqual(createUser.data.createUser.name); - expect(createPostModel.data.createPostModel.authorSurname).toEqual(createUser.data.createUser.surname); - const queryPostModel = await GRAPHQL_CLIENT.query( - `query { - getPostModel(id: "${createPostModel.data.createPostModel.id}") { - id - singleAuthor { - id - name - surname - } - } - }`, - {}, - ); - expect(queryPostModel.data.getPostModel).toBeDefined(); - const author = queryPostModel.data.getPostModel.singleAuthor; - expect(author.id).toEqual(createUser.data.createUser.id); - expect(author.name).toEqual(createUser.data.createUser.name); - expect(author.surname).toEqual(createUser.data.createUser.surname); -}); - -test('PostModel.authors query with composite sortkey', async () => { - const createUser = await GRAPHQL_CLIENT.query( - `mutation { - createUserModel(input: { id: "123", rollNumber: 1, name: "Bob", surname: "Rob" }) { - id - rollNumber - name - surname - } - }`, - {}, - ); - expect(createUser.data.createUserModel.id).toBeDefined(); - expect(createUser.data.createUserModel.name).toEqual('Bob'); - expect(createUser.data.createUserModel.rollNumber).toEqual(1); - expect(createUser.data.createUserModel.surname).toEqual('Rob'); - const createUser2 = await GRAPHQL_CLIENT.query( - `mutation { - createUserModel(input: { id: "123", rollNumber: 2, name: "Bob", surname: "Rob" }) { - id - rollNumber - name - surname - } - }`, - {}, - ); - expect(createUser2.data.createUserModel.id).toBeDefined(); - expect(createUser2.data.createUserModel.name).toEqual('Bob'); - expect(createUser2.data.createUserModel.rollNumber).toEqual(2); - expect(createUser2.data.createUserModel.surname).toEqual('Rob'); - const createPostModel = await GRAPHQL_CLIENT.query( - `mutation { - createPostModel(input: { authorID: "${createUser.data.createUserModel.id}", - authorName: "${createUser.data.createUserModel.name}", - authorSurname: "${createUser.data.createUserModel.surname}", - postContents: "potato" }) { - id - authorID - authorName - authorSurname - postContents - } - }`, - {}, - ); - expect(createPostModel.data.createPostModel.id).toBeDefined(); - expect(createPostModel.data.createPostModel.authorID).toEqual(createUser.data.createUserModel.id); - expect(createPostModel.data.createPostModel.authorName).toEqual(createUser.data.createUserModel.name); - expect(createPostModel.data.createPostModel.authorSurname).toEqual(createUser.data.createUserModel.surname); - const queryPostModel = await GRAPHQL_CLIENT.query( - `query { - getPostModel(id: "${createPostModel.data.createPostModel.id}") { - id - authors { - items { - id - rollNumber - name - surname - } - } - } - }`, - {}, - ); - expect(queryPostModel.data.getPostModel).toBeDefined(); - const items = queryPostModel.data.getPostModel.authors.items; - expect(items.length).toEqual(2); - expect(items[0].id).toEqual(createUser.data.createUserModel.id); - try { - expect(items[0].rollNumber).toEqual(createUser.data.createUserModel.rollNumber); - expect(items[1].rollNumber).toEqual(createUser2.data.createUserModel.rollNumber); - } catch (error) { - expect(items[1].rollNumber).toEqual(createUser.data.createUserModel.rollNumber); - expect(items[0].rollNumber).toEqual(createUser2.data.createUserModel.rollNumber); - } - expect(items[0].name).toEqual(createUser.data.createUserModel.name); - expect(items[0].surname).toEqual(createUser.data.createUserModel.surname); - expect(items[1].id).toEqual(createUser2.data.createUserModel.id); - expect(items[1].surname).toEqual(createUser2.data.createUserModel.surname); - expect(items[1].name).toEqual(createUser2.data.createUserModel.name); -}); - -test(`the default limit.`, async () => { - for (let i = 0; i < 51; i++) { - await GRAPHQL_CLIENT.query( - `mutation { - createUser(input: { id: "11", name: "user${i}", surname: "sub${i}" }) { - id - name - surname - } - }`, - {}, - ); - } - - const createResponse = await GRAPHQL_CLIENT.query( - ` - mutation { - createPost(input: {authorID: "11", postContents: "helloWorld"}) { - authorID - id - authors { - items { - name - surname - id - } - } - } - }`, - {}, - ); - expect(createResponse).toBeDefined(); - expect(createResponse.data.createPost.authorID).toEqual('11'); - expect(createResponse.data.createPost.authors.items.length).toEqual(50); -}); - -test('PostModel.authors query with composite sortkey passed as arg.', async () => { - const createUser = await GRAPHQL_CLIENT.query( - `mutation { - createUser(input: { id: "123", name: "Bobby", surname: "Rob" }) { - id - name - surname - } - }`, - {}, - ); - expect(createUser.data.createUser.id).toBeDefined(); - expect(createUser.data.createUser.name).toEqual('Bobby'); - expect(createUser.data.createUser.surname).toEqual('Rob'); - const createPost = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { id: "321", authorID: "${createUser.data.createUser.id}", postContents: "potato"}) { - id - authorID - postContents - } - }`, - {}, - ); - expect(createPost.data.createPost.id).toBeDefined(); - expect(createPost.data.createPost.authorID).toEqual(createUser.data.createUser.id); - const queryPost = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createPost.data.createPost.id}") { - id - authors(nameSurname: {beginsWith: {name: "${createUser.data.createUser.name}", surname: "${createUser.data.createUser.surname}"}}) { - items { - id - name - surname - } - } - } - }`, - {}, - ); - expect(queryPost.data.getPost).toBeDefined(); - const items = queryPost.data.getPost.authors.items; - expect(items.length).toEqual(1); - expect(items[0].id).toEqual(createUser.data.createUser.id); - expect(items[0].name).toEqual(createUser.data.createUser.name); - expect(items[0].surname).toEqual(createUser.data.createUser.surname); -}); - -test('User.authorPosts.posts query followed by getItem (intermediary model)', async () => { - const createPostAuthor = await GRAPHQL_CLIENT.query( - `mutation { - createPostAuthor(input: { authorID: "123", postID: "321" }) { - id - authorID - postID - } - }`, - {}, - ); - expect(createPostAuthor.data.createPostAuthor.id).toBeDefined(); - expect(createPostAuthor.data.createPostAuthor.authorID).toEqual('123'); - expect(createPostAuthor.data.createPostAuthor.postID).toEqual('321'); - const queryUser = await GRAPHQL_CLIENT.query( - `query { - getUserModel(id: "123", rollNumber: 1) { - id - authorPosts { - items { - post { - id - postContents - } - } - } - } - }`, - {}, - ); - expect(queryUser.data.getUserModel).toBeDefined(); - const items = queryUser.data.getUserModel.authorPosts.items; - expect(items.length).toEqual(1); - expect(items[0].post.id).toEqual('321'); - expect(items[0].post.postContents).toEqual(['potato']); -}); - -test('User.friendship.friend query (reflexive has many).', async () => { - const createUser = await GRAPHQL_CLIENT.query( - `mutation { - createUser(input: { id: "12", name: "Bobby", surname: "Rob" }) { - id - name - surname - } - }`, - {}, - ); - expect(createUser.data.createUser.id).toBeDefined(); - expect(createUser.data.createUser.name).toEqual('Bobby'); - expect(createUser.data.createUser.surname).toEqual('Rob'); - const createUser1 = await GRAPHQL_CLIENT.query( - `mutation { - createUser(input: { id: "13", name: "Bob", surname: "Rob" }) { - id - name - surname - } - }`, - {}, - ); - expect(createUser1.data.createUser.id).toBeDefined(); - expect(createUser1.data.createUser.name).toEqual('Bob'); - expect(createUser1.data.createUser.surname).toEqual('Rob'); - const createFriendship = await GRAPHQL_CLIENT.query( - `mutation { - createFriendship(input: { id: "1", userID: 13, friendID: 12 }) { - id - userID - friendID - } - }`, - {}, - ); - expect(createFriendship.data.createFriendship.id).toBeDefined(); - expect(createFriendship.data.createFriendship.userID).toEqual('13'); - expect(createFriendship.data.createFriendship.friendID).toEqual('12'); - const queryUser = await GRAPHQL_CLIENT.query( - `query { - getUser(id: "13", name: "Bob", surname: "Rob") { - id - friendships { - items { - friend { - items { - id - name - } - } - } - } - } - }`, - {}, - ); - expect(queryUser.data.getUser).toBeDefined(); - const items = queryUser.data.getUser.friendships.items; - expect(items.length).toEqual(1); - expect(items[0].friend.items[0].id).toEqual('12'); - expect(items[0].friend.items[0].name).toEqual('Bobby'); -}); diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/NewConnectionWithAuth.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/NewConnectionWithAuth.e2e.test.ts deleted file mode 100644 index 1cf5747863..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/NewConnectionWithAuth.e2e.test.ts +++ /dev/null @@ -1,530 +0,0 @@ -import * as fs from 'fs'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { KeyTransformer } from 'graphql-key-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as S3, CreateBucketRequest } from 'aws-sdk/clients/s3'; -import { default as CognitoClient } from 'aws-sdk/clients/cognitoidentityserviceprovider'; -import { default as moment } from 'moment'; -import { GraphQLClient } from '../GraphQLClient'; -import { S3Client } from '../S3Client'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { - createUserPool, - createUserPoolClient, - createGroup, - addUserToGroup, - configureAmplify, - signupUser, - authenticateUser, -} from '../cognitoUtils'; -import 'isomorphic-fetch'; - -// to deal with bug in cognito-identity-js -(global as any).fetch = require('node-fetch'); - -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `NewConnectionsWithAuthTests-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `new-connections-with-auth-test-bucket-${BUILD_TIMESTAMP}`; -const LOCAL_BUILD_ROOT = '/tmp/new_connections_with_auth_test/'; -const DEPLOYMENT_ROOT_KEY = 'deployments'; - -let GRAPHQL_ENDPOINT = undefined; - -/** - * Client 1 is logged in and is a member of the Admin group. - */ -let GRAPHQL_CLIENT_1 = undefined; - -/** - * Client 2 is logged in and is a member of the Devs group. - */ -let GRAPHQL_CLIENT_2 = undefined; - -/** - * Client 3 is logged in and has no group memberships. - */ -let GRAPHQL_CLIENT_3 = undefined; - -let USER_POOL_ID = undefined; - -const USERNAME1 = 'user1@test.com'; -const USERNAME2 = 'user2@test.com'; -const USERNAME3 = 'user3@test.com'; -const TMP_PASSWORD = 'Password123!'; -const REAL_PASSWORD = 'Password1234!'; - -const ADMIN_GROUP_NAME = 'Admin'; -const DEVS_GROUP_NAME = 'Devs'; -const PARTICIPANT_GROUP_NAME = 'Participant'; -const WATCHER_GROUP_NAME = 'Watcher'; - -const cognitoClient = new CognitoClient({ apiVersion: '2016-04-19', region: region }); -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -async function createBucket(name: string) { - return new Promise((res, rej) => { - const params: CreateBucketRequest = { - Bucket: name, - }; - awsS3Client.createBucket(params, (err, data) => (err ? rej(err) : res(data))); - }); -} - -async function deleteBucket(name: string) { - return new Promise((res, rej) => { - const params: CreateBucketRequest = { - Bucket: name, - }; - awsS3Client.deleteBucket(params, (err, data) => (err ? rej(err) : res(data))); - }); -} - -beforeAll(async () => { - // Create a stack for the post model with auth enabled. - if (!fs.existsSync(LOCAL_BUILD_ROOT)) { - fs.mkdirSync(LOCAL_BUILD_ROOT); - } - await createBucket(BUCKET_NAME); - const validSchema = ` - type Post - @model - @auth(rules: [{ allow: owner }]) - @key(name: "byOwner", fields: ["owner", "id"]) - { - id: ID! - title: String! - author: User @connection(fields: ["owner"]) - owner: ID! - } - type User @model @auth(rules: [{ allow: owner }]) { - id: ID! - posts: [Post] @connection(keyName: "byOwner", fields: ["id"]) - } - type FieldProtected @model { - id: ID! - owner: String - ownerOnly: String @auth(rules: [{ allow: owner }]) - } - type OpenTopLevel @model { - id: ID! - name: String - owner: String - protected: [ConnectionProtected] @connection(keyName: "byTopLevel", fields: ["id"]) - } - type ConnectionProtected - @model(queries: null) - @auth(rules: [{ allow: owner }]) - @key(name: "byTopLevel", fields: ["topLevelID", "id"]) - { - id: ID! - name: String - owner: String - topLevelID: ID! - topLevel: OpenTopLevel @connection(fields: ["topLevelID"]) - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new KeyTransformer(), - new ModelConnectionTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const userPoolResponse = await createUserPool(cognitoClient, `UserPool${STACK_NAME}`); - USER_POOL_ID = userPoolResponse.UserPool.Id; - const userPoolClientResponse = await createUserPoolClient(cognitoClient, USER_POOL_ID, `UserPool${STACK_NAME}`); - const userPoolClientId = userPoolClientResponse.UserPoolClient.ClientId; - try { - // Clean the bucket - const out = transformer.transform(validSchema); - - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { AuthCognitoUserPoolId: USER_POOL_ID }, - LOCAL_BUILD_ROOT, - BUCKET_NAME, - DEPLOYMENT_ROOT_KEY, - BUILD_TIMESTAMP, - ); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - GRAPHQL_ENDPOINT = getApiEndpoint(finishedStack.Outputs); - - // Verify we have all the details - expect(GRAPHQL_ENDPOINT).toBeTruthy(); - expect(USER_POOL_ID).toBeTruthy(); - expect(userPoolClientId).toBeTruthy(); - - // Configure Amplify, create users, and sign in. - configureAmplify(USER_POOL_ID, userPoolClientId); - - await signupUser(USER_POOL_ID, USERNAME1, TMP_PASSWORD); - await signupUser(USER_POOL_ID, USERNAME2, TMP_PASSWORD); - await signupUser(USER_POOL_ID, USERNAME3, TMP_PASSWORD); - - await createGroup(USER_POOL_ID, ADMIN_GROUP_NAME); - await createGroup(USER_POOL_ID, PARTICIPANT_GROUP_NAME); - await createGroup(USER_POOL_ID, WATCHER_GROUP_NAME); - await createGroup(USER_POOL_ID, DEVS_GROUP_NAME); - await addUserToGroup(ADMIN_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(PARTICIPANT_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(WATCHER_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(DEVS_GROUP_NAME, USERNAME2, USER_POOL_ID); - const authResAfterGroup: any = await authenticateUser(USERNAME1, TMP_PASSWORD, REAL_PASSWORD); - - const idToken = authResAfterGroup.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_1 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken }); - - const authRes2AfterGroup: any = await authenticateUser(USERNAME2, TMP_PASSWORD, REAL_PASSWORD); - const idToken2 = authRes2AfterGroup.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_2 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken2 }); - - const authRes3: any = await authenticateUser(USERNAME3, TMP_PASSWORD, REAL_PASSWORD); - const idToken3 = authRes3.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_3 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken3 }); - - // Wait for any propagation to avoid random - // "The security token included in the request is invalid" errors - await new Promise((res) => setTimeout(() => res(), 5000)); - } catch (e) { - console.error(e); - throw e; - } -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf, { cognitoClient, userPoolId: USER_POOL_ID }); -}); - -/** - * Tests - */ -test('creating a post and immediately view it via the User.posts connection.', async () => { - const createUser1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createUser(input: { id: "user1@test.com" }) { - id - } - }`, - {}, - ); - expect(createUser1.data.createUser.id).toEqual('user1@test.com'); - - const response = await GRAPHQL_CLIENT_1.query( - `mutation { - createPost(input: { title: "Hello, World!", owner: "user1@test.com" }) { - id - title - owner - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.owner).toBeDefined(); - - const getResponse = await GRAPHQL_CLIENT_1.query( - `query { - getUser(id: "user1@test.com") { - posts { - items { - id - title - owner - author { - id - } - } - } - } - }`, - {}, - ); - expect(getResponse.data.getUser.posts.items[0].id).toBeDefined(); - expect(getResponse.data.getUser.posts.items[0].title).toEqual('Hello, World!'); - expect(getResponse.data.getUser.posts.items[0].owner).toEqual('user1@test.com'); - expect(getResponse.data.getUser.posts.items[0].author.id).toEqual('user1@test.com'); -}); - -test('Testing reading an owner protected field as a non owner', async () => { - const response1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createFieldProtected(input: { id: "1", owner: "${USERNAME1}", ownerOnly: "owner-protected" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response1.data.createFieldProtected.id).toEqual('1'); - expect(response1.data.createFieldProtected.owner).toEqual(USERNAME1); - expect(response1.data.createFieldProtected.ownerOnly).toEqual(null); - - const response2 = await GRAPHQL_CLIENT_2.query( - `query { - getFieldProtected(id: "1") { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response2.data.getFieldProtected.ownerOnly).toBeNull(); - expect(response2.errors).toHaveLength(1); - - const response3 = await GRAPHQL_CLIENT_1.query( - `query { - getFieldProtected(id: "1") { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response3.data.getFieldProtected.id).toEqual('1'); - expect(response3.data.getFieldProtected.owner).toEqual(USERNAME1); - expect(response3.data.getFieldProtected.ownerOnly).toEqual('owner-protected'); -}); - -test('that @connection resolvers respect @model read operations.', async () => { - const response1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createOpenTopLevel(input: { id: "1", owner: "${USERNAME1}", name: "open" }) { - id - owner - name - } - }`, - {}, - ); - expect(response1.data.createOpenTopLevel.id).toEqual('1'); - expect(response1.data.createOpenTopLevel.owner).toEqual(USERNAME1); - expect(response1.data.createOpenTopLevel.name).toEqual('open'); - - const response2 = await GRAPHQL_CLIENT_2.query( - `mutation { - createConnectionProtected(input: { id: "1", owner: "${USERNAME2}", name: "closed", topLevelID: "1" }) { - id - owner - name - topLevelID - } - }`, - {}, - ); - expect(response2.data.createConnectionProtected.id).toEqual('1'); - expect(response2.data.createConnectionProtected.owner).toEqual(USERNAME2); - expect(response2.data.createConnectionProtected.name).toEqual('closed'); - - const response3 = await GRAPHQL_CLIENT_1.query( - `query { - getOpenTopLevel(id: "1") { - id - protected { - items { - id - name - owner - } - } - } - }`, - {}, - ); - expect(response3.data.getOpenTopLevel.id).toEqual('1'); - expect(response3.data.getOpenTopLevel.protected.items).toHaveLength(0); - - const response4 = await GRAPHQL_CLIENT_2.query( - `query { - getOpenTopLevel(id: "1") { - id - protected { - items { - id - name - owner - } - } - } - }`, - {}, - ); - expect(response4.data.getOpenTopLevel.id).toEqual('1'); - expect(response4.data.getOpenTopLevel.protected.items).toHaveLength(1); -}); - -// Per field auth in mutations -test('that owners cannot set the field of a FieldProtected object unless authorized.', async () => { - const response1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createFieldProtected(input: { id: "2", owner: "${USERNAME1}", ownerOnly: "owner-protected" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response1.data.createFieldProtected.id).toEqual('2'); - expect(response1.data.createFieldProtected.owner).toEqual(USERNAME1); - expect(response1.data.createFieldProtected.ownerOnly).toEqual(null); - - const response2 = await GRAPHQL_CLIENT_1.query( - `mutation { - createFieldProtected(input: { id: "3", owner: "${USERNAME2}", ownerOnly: "owner-protected" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response2.data.createFieldProtected).toBeNull(); - expect(response2.errors).toHaveLength(1); - - // The auth rule is on ownerOnly. Omitting the "ownerOnly" field will - // not trigger the @auth check - const response3 = await GRAPHQL_CLIENT_1.query( - `mutation { - createFieldProtected(input: { id: "4", owner: "${USERNAME2}" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response3.data.createFieldProtected.id).toEqual('4'); - expect(response3.data.createFieldProtected.owner).toEqual(USERNAME2); - // The length is one because the 'ownerOnly' field is protected on reads. - // Since the caller is not the owner this will throw after the mutation succeeds - // and return partial results. - expect(response3.errors).toHaveLength(1); -}); - -test('that owners cannot update the field of a FieldProtected object unless authorized.', async () => { - const response1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createFieldProtected(input: { owner: "${USERNAME1}", ownerOnly: "owner-protected" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response1.data.createFieldProtected.id).not.toBeNull(); - expect(response1.data.createFieldProtected.owner).toEqual(USERNAME1); - expect(response1.data.createFieldProtected.ownerOnly).toEqual(null); - - const response2 = await GRAPHQL_CLIENT_2.query( - `mutation { - updateFieldProtected(input: { id: "${response1.data.createFieldProtected.id}", ownerOnly: "owner2-protected" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response2.data.updateFieldProtected).toBeNull(); - expect(response2.errors).toHaveLength(1); - - // The auth rule is on ownerOnly. Omitting the "ownerOnly" field will - // not trigger the @auth check - const response3 = await GRAPHQL_CLIENT_1.query( - `mutation { - updateFieldProtected(input: { id: "${response1.data.createFieldProtected.id}", ownerOnly: "updated" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - const resposne3ID = response3.data.updateFieldProtected.id; - expect(resposne3ID).toEqual(response1.data.createFieldProtected.id); - expect(response3.data.updateFieldProtected.owner).toEqual(USERNAME1); - - const response3query = await GRAPHQL_CLIENT_1.query(`query getMake1 { - getFieldProtected(id: "${resposne3ID}"){ - id - owner - ownerOnly - } - }`); - expect(response3query.data.getFieldProtected.ownerOnly).toEqual('updated'); - - // This request should succeed since we are not updating the protected field. - const response4 = await GRAPHQL_CLIENT_3.query( - `mutation { - updateFieldProtected(input: { id: "${response1.data.createFieldProtected.id}", owner: "${USERNAME3}" }) { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response4.data.updateFieldProtected.id).toEqual(response1.data.createFieldProtected.id); - expect(response4.data.updateFieldProtected.owner).toEqual(USERNAME3); - expect(response4.data.updateFieldProtected.ownerOnly).toBeNull(); - - const response5 = await GRAPHQL_CLIENT_3.query( - `query { - getFieldProtected( id: "${response1.data.createFieldProtected.id}" ) { - id - owner - ownerOnly - } - }`, - {}, - ); - expect(response5.data.getFieldProtected.ownerOnly).toEqual('updated'); -}); diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/NonModelAuthFunction.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/NonModelAuthFunction.e2e.test.ts deleted file mode 100644 index c160df7aee..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/NonModelAuthFunction.e2e.test.ts +++ /dev/null @@ -1,473 +0,0 @@ -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform, gql } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { FunctionTransformer } from 'graphql-function-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as moment } from 'moment'; -import { default as S3 } from 'aws-sdk/clients/s3'; -import AWSAppSyncClient, { AUTH_TYPE } from 'aws-appsync'; -import AWS from 'aws-sdk'; -import { default as CognitoClient } from 'aws-sdk/clients/cognitoidentityserviceprovider'; -import Role from 'cloudform-types/types/iam/role'; -import UserPoolClient from 'cloudform-types/types/cognito/userPoolClient'; -import IdentityPool from 'cloudform-types/types/cognito/identityPool'; -import IdentityPoolRoleAttachment from 'cloudform-types/types/cognito/identityPoolRoleAttachment'; -import { Auth } from 'aws-amplify'; -import { createUserPool, createUserPoolClient, configureAmplify, signupUser, authenticateUser } from '../cognitoUtils'; -import { IAMHelper } from '../IAMHelper'; -import { LambdaHelper } from '../LambdaHelper'; -import { S3Client } from '../S3Client'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { CloudFormationClient } from '../CloudFormationClient'; -import 'isomorphic-fetch'; - -// to deal with bug in cognito-identity-js -(global as any).fetch = require('node-fetch'); - -import { resolveTestRegion } from '../testSetup'; - -const REGION = resolveTestRegion(); - -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -// To overcome of the way of how AmplifyJS picks up currentUserCredentials -const anyAWS = AWS as any; - -if (anyAWS && anyAWS.config && anyAWS.config.credentials) { - delete anyAWS.config.credentials; -} - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(REGION); -const customS3Client = new S3Client(REGION); -const awsS3Client = new S3({ region: REGION }); - -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `NonModelAuthFunctionTransformerTests-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `non-model-auth-function-transformer-test-bucket-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/nonmodel_auth_function_transformer_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; -const ECHO_FUNCTION_NAME = `long-prefix-e2e-test-functions-echo-dev-${BUILD_TIMESTAMP}`; -const LAMBDA_EXECUTION_ROLE_NAME = `amplify_e2e_tests_lambda_basic_${BUILD_TIMESTAMP}`; -const LAMBDA_EXECUTION_POLICY_NAME = `amplify_e2e_tests_lambda_basic_access_${BUILD_TIMESTAMP}`; -let LAMBDA_EXECUTION_POLICY_ARN = ''; -const AUTH_ROLE_NAME = `${STACK_NAME}-authRole`; -const UNAUTH_ROLE_NAME = `${STACK_NAME}-unauthRole`; -const IDENTITY_POOL_NAME = `NonModelAuthFunctionTest_${BUILD_TIMESTAMP}_identity_pool`; -const USER_POOL_CLIENTWEB_NAME = `nofuncauth_${BUILD_TIMESTAMP}_clientweb`; -const USER_POOL_CLIENT_NAME = `nofuncauth_${BUILD_TIMESTAMP}_client`; - -let USER_POOL_AUTH_CLIENT: AWSAppSyncClient = undefined; -let IAM_UNAUTHCLIENT: AWSAppSyncClient = undefined; - -let USER_POOL_ID = undefined; - -const USERNAME1 = 'user1@test.com'; - -const TMP_PASSWORD = 'Password123!'; -const REAL_PASSWORD = 'Password1234!'; - -const cognitoClient = new CognitoClient({ apiVersion: '2016-04-19', region: REGION }); - -const LAMBDA_HELPER = new LambdaHelper(); -const IAM_HELPER = new IAMHelper(); - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -beforeAll(async () => { - const validSchema = ` - type Query { - echo(msg: String!): String! @function(name: "${ECHO_FUNCTION_NAME}") @auth (rules: [{ allow: private, provider: iam }]) - } - `; - try { - await awsS3Client.createBucket({ Bucket: BUCKET_NAME }).promise(); - } catch (e) { - console.warn(`Could not create bucket: ${e}`); - } - const userPoolResponse = await createUserPool(cognitoClient, `UserPool${STACK_NAME}`); - USER_POOL_ID = userPoolResponse.UserPool.Id; - const userPoolClientResponse = await createUserPoolClient(cognitoClient, USER_POOL_ID, `UserPool${STACK_NAME}`); - const userPoolClientId = userPoolClientResponse.UserPoolClient.ClientId; - - try { - const role = await IAM_HELPER.createLambdaExecutionRole(LAMBDA_EXECUTION_ROLE_NAME); - await wait(5000); - const policy = await IAM_HELPER.createLambdaExecutionPolicy(LAMBDA_EXECUTION_POLICY_NAME); - await wait(5000); - LAMBDA_EXECUTION_POLICY_ARN = policy.Policy.Arn; - await IAM_HELPER.attachPolicy(policy.Policy.Arn, role.Role.RoleName); - await wait(10000); - await LAMBDA_HELPER.createFunction(ECHO_FUNCTION_NAME, role.Role.Arn, 'echoResolverFunction'); - } catch (e) { - console.warn(`Could not setup function: ${e}`); - } - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new FunctionTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - ], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - - const authRole = new Role({ - RoleName: AUTH_ROLE_NAME, - AssumeRolePolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Sid: '', - Effect: 'Allow', - Principal: { - Federated: 'cognito-identity.amazonaws.com', - }, - Action: 'sts:AssumeRoleWithWebIdentity', - Condition: { - StringEquals: { - 'cognito-identity.amazonaws.com:aud': { Ref: 'IdentityPool' }, - }, - 'ForAnyValue:StringLike': { - 'cognito-identity.amazonaws.com:amr': 'authenticated', - }, - }, - }, - ], - }, - }); - - const unauthRole = new Role({ - RoleName: UNAUTH_ROLE_NAME, - AssumeRolePolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Sid: '', - Effect: 'Allow', - Principal: { - Federated: 'cognito-identity.amazonaws.com', - }, - Action: 'sts:AssumeRoleWithWebIdentity', - Condition: { - StringEquals: { - 'cognito-identity.amazonaws.com:aud': { Ref: 'IdentityPool' }, - }, - 'ForAnyValue:StringLike': { - 'cognito-identity.amazonaws.com:amr': 'unauthenticated', - }, - }, - }, - ], - }, - Policies: [ - new Role.Policy({ - PolicyName: 'appsync-unauthrole-policy', - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Action: ['appsync:GraphQL'], - Resource: [ - { - 'Fn::Join': [ - '', - [ - 'arn:aws:appsync:', - { Ref: 'AWS::Region' }, - ':', - { Ref: 'AWS::AccountId' }, - ':apis/', - { - 'Fn::GetAtt': ['GraphQLAPI', 'ApiId'], - }, - '/*', - ], - ], - }, - ], - }, - ], - }, - }), - ], - }); - - const identityPool = new IdentityPool({ - IdentityPoolName: IDENTITY_POOL_NAME, - CognitoIdentityProviders: [ - { - ClientId: { - Ref: 'UserPoolClient', - }, - ProviderName: { - 'Fn::Sub': [ - 'cognito-idp.${region}.amazonaws.com/${client}', - { - region: { - Ref: 'AWS::Region', - }, - client: USER_POOL_ID, - }, - ], - }, - } as unknown, - { - ClientId: { - Ref: 'UserPoolClientWeb', - }, - ProviderName: { - 'Fn::Sub': [ - 'cognito-idp.${region}.amazonaws.com/${client}', - { - region: { - Ref: 'AWS::Region', - }, - client: USER_POOL_ID, - }, - ], - }, - } as unknown, - ], - AllowUnauthenticatedIdentities: true, - }); - - const identityPoolRoleMap = new IdentityPoolRoleAttachment({ - IdentityPoolId: { Ref: 'IdentityPool' } as unknown as string, - Roles: { - unauthenticated: { 'Fn::GetAtt': ['UnauthRole', 'Arn'] }, - authenticated: { 'Fn::GetAtt': ['AuthRole', 'Arn'] }, - }, - }); - - const userPoolClientWeb = new UserPoolClient({ - ClientName: USER_POOL_CLIENTWEB_NAME, - RefreshTokenValidity: 30, - UserPoolId: USER_POOL_ID, - }); - - const userPoolClient = new UserPoolClient({ - ClientName: USER_POOL_CLIENT_NAME, - GenerateSecret: true, - RefreshTokenValidity: 30, - UserPoolId: USER_POOL_ID, - }); - - out.rootStack.Resources.IdentityPool = identityPool; - out.rootStack.Resources.IdentityPoolRoleMap = identityPoolRoleMap; - out.rootStack.Resources.UserPoolClientWeb = userPoolClientWeb; - out.rootStack.Resources.UserPoolClient = userPoolClient; - out.rootStack.Outputs.IdentityPoolId = { Value: { Ref: 'IdentityPool' } }; - out.rootStack.Outputs.IdentityPoolName = { Value: { 'Fn::GetAtt': ['IdentityPool', 'Name'] } }; - - out.rootStack.Resources.AuthRole = authRole; - out.rootStack.Outputs.AuthRoleArn = { Value: { 'Fn::GetAtt': ['AuthRole', 'Arn'] } }; - out.rootStack.Resources.UnauthRole = unauthRole; - out.rootStack.Outputs.UnauthRoleArn = { Value: { 'Fn::GetAtt': ['UnauthRole', 'Arn'] } }; - - // Since we're doing the policy here we've to remove the transformer generated artifacts from - // the generated stack. - const maxPolicyCount = 10; - for (let i = 0; i < maxPolicyCount; i++) { - const paddedIndex = `${i + 1}`.padStart(2, '0'); - const authResourceName = `${ResourceConstants.RESOURCES.AuthRolePolicy}${paddedIndex}`; - const unauthResourceName = `${ResourceConstants.RESOURCES.UnauthRolePolicy}${paddedIndex}`; - - if (out.rootStack.Resources[authResourceName]) { - delete out.rootStack.Resources[authResourceName]; - } - - if (out.rootStack.Resources[unauthResourceName]) { - delete out.rootStack.Resources[unauthResourceName]; - } - } - - delete out.rootStack.Parameters.authRoleName; - delete out.rootStack.Parameters.unauthRoleName; - - for (const key of Object.keys(out.rootStack.Resources)) { - if ( - out.rootStack.Resources[key].Properties && - out.rootStack.Resources[key].Properties.Parameters && - out.rootStack.Resources[key].Properties.Parameters.unauthRoleName - ) { - delete out.rootStack.Resources[key].Properties.Parameters.unauthRoleName; - } - - if ( - out.rootStack.Resources[key].Properties && - out.rootStack.Resources[key].Properties.Parameters && - out.rootStack.Resources[key].Properties.Parameters.authRoleName - ) { - delete out.rootStack.Resources[key].Properties.Parameters.authRoleName; - } - } - - for (const stackKey of Object.keys(out.stacks)) { - const stack = out.stacks[stackKey]; - - for (const key of Object.keys(stack.Resources)) { - if (stack.Parameters && stack.Parameters.unauthRoleName) { - delete stack.Parameters.unauthRoleName; - } - if (stack.Parameters && stack.Parameters.authRoleName) { - delete stack.Parameters.authRoleName; - } - if ( - stack.Resources[key].Properties && - stack.Resources[key].Properties.Parameters && - stack.Resources[key].Properties.Parameters.unauthRoleName - ) { - delete stack.Resources[key].Properties.Parameters.unauthRoleName; - } - if ( - stack.Resources[key].Properties && - stack.Resources[key].Properties.Parameters && - stack.Resources[key].Properties.Parameters.authRoleName - ) { - delete stack.Resources[key].Properties.Parameters.authRoleName; - } - } - } - - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { CreateAPIKey: '1', env: 'dev' }, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - // Arbitrary wait to make sure everything is ready. - await cf.wait(5, () => Promise.resolve()); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const endpoint = getApiEndpoint(finishedStack.Outputs); - expect(endpoint).toBeDefined(); - - const getIdentityPoolId = outputValueSelector('IdentityPoolId'); - const identityPoolId = getIdentityPoolId(finishedStack.Outputs); - expect(identityPoolId).toBeTruthy(); - - // Verify we have all the details - expect(USER_POOL_ID).toBeTruthy(); - expect(userPoolClientId).toBeTruthy(); - - // Configure Amplify, create users, and sign in. - configureAmplify(USER_POOL_ID, userPoolClientId, identityPoolId); - - const unauthCredentials = await Auth.currentCredentials(); - - IAM_UNAUTHCLIENT = new AWSAppSyncClient({ - url: endpoint, - region: REGION, - auth: { - type: AUTH_TYPE.AWS_IAM, - credentials: { - accessKeyId: unauthCredentials.accessKeyId, - secretAccessKey: unauthCredentials.secretAccessKey, - sessionToken: unauthCredentials.sessionToken, - }, - }, - offlineConfig: { - keyPrefix: 'iam', - }, - disableOffline: true, - }); - - await signupUser(USER_POOL_ID, USERNAME1, TMP_PASSWORD); - const authRes = await authenticateUser(USERNAME1, TMP_PASSWORD, REAL_PASSWORD); - const idToken = authRes.getIdToken().getJwtToken(); - - USER_POOL_AUTH_CLIENT = new AWSAppSyncClient({ - url: endpoint, - region: REGION, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: () => idToken, - }, - offlineConfig: { - keyPrefix: 'userPools', - }, - disableOffline: true, - }); -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf, { cognitoClient, userPoolId: USER_POOL_ID }); - - try { - await LAMBDA_HELPER.deleteFunction(ECHO_FUNCTION_NAME); - } catch (e) { - console.warn(`Error during function cleanup: ${e}`); - } - try { - await IAM_HELPER.detachPolicy(LAMBDA_EXECUTION_POLICY_ARN, LAMBDA_EXECUTION_ROLE_NAME); - } catch (e) { - console.warn(`Error during policy dissociation: ${e}`); - } - try { - await IAM_HELPER.deleteRole(LAMBDA_EXECUTION_ROLE_NAME); - } catch (e) { - console.warn(`Error during role cleanup: ${e}`); - } - try { - await IAM_HELPER.deletePolicy(LAMBDA_EXECUTION_POLICY_ARN); - } catch (e) { - console.warn(`Error during policy cleanup: ${e}`); - } -}); - -/** - * Test queries below - */ -test('calling echo function as a user via IAM', async () => { - const query = gql` - query { - echo(msg: "Hello") - } - `; - - const response = await IAM_UNAUTHCLIENT.query<{ echo: string }>({ - query, - fetchPolicy: 'no-cache', - }); - - expect(response.data.echo).toEqual('Hello'); -}); - -function wait(ms: number) { - return new Promise((resolve, reject) => { - setTimeout(() => resolve(), ms); - }); -} diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/PredictionsTransformerTests.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/PredictionsTransformerTests.e2e.test.ts deleted file mode 100644 index f044c2e252..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/PredictionsTransformerTests.e2e.test.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { PredictionsTransformer } from 'graphql-predictions-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as moment } from 'moment'; -import { default as S3 } from 'aws-sdk/clients/s3'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { GraphQLClient } from '../GraphQLClient'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { S3Client } from '../S3Client'; -import { resolveTestRegion } from '../testSetup'; - -const AWS_REGION = resolveTestRegion(); - -// tslint:disable: no-magic-numbers -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(AWS_REGION); -const customS3Client = new S3Client(AWS_REGION); -const awsS3Client = new S3({ region: AWS_REGION }); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `PredictionsTransformerTests-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `appsync-predictions-transformer-test-bucket-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/predictions_transformer_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; - -let GRAPHQL_CLIENT: GraphQLClient = undefined; - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -beforeAll(async () => { - const validSchema = ` - type Query { - translateImageText: String @predictions(actions: [ identifyText translateText ]) - translateThis: String @predictions(actions: [ translateText ]) - speakTranslatedText: String @predictions(actions: [ translateText convertTextToSpeech]) - } - `; - try { - await awsS3Client.createBucket({ Bucket: BUCKET_NAME }).promise(); - } catch (e) { - console.warn(`Could not create bucket: ${e}`); - } - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new PredictionsTransformer({ bucketName: BUCKET_NAME }), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { CreateAPIKey: '1' }, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - // Arbitrary wait to make sure everything is ready. - await cf.wait(5, () => Promise.resolve()); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - const endpoint = getApiEndpoint(finishedStack.Outputs); - const apiKey = getApiKey(finishedStack.Outputs); - expect(apiKey).toBeDefined(); - expect(endpoint).toBeDefined(); - GRAPHQL_CLIENT = new GraphQLClient(endpoint, { 'x-api-key': apiKey }); -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf); -}); - -test('translate and convert text to speech', async () => { - // logic to test graphql - const response = await GRAPHQL_CLIENT.query( - `query SpeakTranslatedText($input: SpeakTranslatedTextInput!) { - speakTranslatedText(input: $input) - }`, - { - input: { - translateText: { - sourceLanguage: 'en', - targetLanguage: 'es', - text: 'this is a voice test', - }, - convertTextToSpeech: { - voiceID: 'Conchita', - }, - }, - }, - ); - expect(response).toBeDefined(); - const pollyURL = response.data.speakTranslatedText; - // check that return format is a url - expect(pollyURL).toMatch(/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/); -}); - -test('translate text individually', async () => { - const germanTranslation = - /((\bDies\b)|(\bdas\b)|(\bder\b)) ist ein ((\bStimmtest\b)|(\Sprachtest\b)|(\bStimmetest\b)|(\bStimmentest\b))/i; - const response = await GRAPHQL_CLIENT.query( - `query TranslateThis($input: TranslateThisInput!) { - translateThis(input: $input) - }`, - { - input: { - translateText: { - sourceLanguage: 'en', - targetLanguage: 'de', - text: 'this is a voice test', - }, - }, - }, - ); - expect(response).toBeDefined(); - const translatedText = response.data.translateThis; - expect(translatedText).toMatch(germanTranslation); -}); diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/RelationalTransformers.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/RelationalTransformers.e2e.test.ts deleted file mode 100644 index 45c65ad848..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/RelationalTransformers.e2e.test.ts +++ /dev/null @@ -1,955 +0,0 @@ -import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer'; -import { IndexTransformer, PrimaryKeyTransformer } from '@aws-amplify/graphql-index-transformer'; -import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; -import { - BelongsToTransformer, - HasManyTransformer, - HasOneTransformer, - ManyToManyTransformer, -} from '@aws-amplify/graphql-relational-transformer'; -import { testTransform } from '@aws-amplify/graphql-transformer-test-utils'; -import { AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as S3 } from 'aws-sdk/clients/s3'; -import { default as moment } from 'moment'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { GraphQLClient } from '../GraphQLClient'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { S3Client } from '../S3Client'; -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `RelationalTransformersTest-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `appsync-relational-transformers-test-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/relational_transforms_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; - -let GRAPHQL_CLIENT: GraphQLClient; - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -beforeAll(async () => { - const validSchema = ` -type Child @model { - id: ID! @primaryKey(sortKeyFields: ["name"]) - name: String! - parents: [Parent] @hasMany(indexName: "byChild", fields: ["id"]) -} - -type Parent @model { - id: ID! - childID: ID! @index(name: "byChild", sortKeyFields: ["childName"]) - childName: String! - child: Child @belongsTo(fields: ["childID", "childName"]) -} - -type User @model { - id: ID! @primaryKey(sortKeyFields: ["name", "surname"]) - name: String! - surname: String! - friendships: [Friendship] @hasMany(indexName: "byUser", fields: ["id"]) -} - -type Friendship @model { - id: ID! - userID: ID! @index(name: "byUser", sortKeyFields: ["friendID"]) - friendID: ID! - friend: [User] @hasMany(fields: ["friendID"]) -} - -type UserModel @model { - id: ID! @primaryKey(sortKeyFields: ["rollNumber"]) @index(name: "composite", sortKeyFields: ["name", "surname"]) - rollNumber: Int! - name: String! - surname: String! - authorPosts: [PostAuthor] @hasMany(indexName: "byAuthor", fields: ["id"]) -} - -type PostModel @model { - id: ID! - authorID: ID! - authorName: String! - authorSurname: String! - postContents: [String] - authors: [UserModel] @hasMany(indexName: "composite", fields: ["authorID", "authorName", "authorSurname"]) - singleAuthor: User @hasOne(fields: ["authorID", "authorName", "authorSurname"]) -} - -type Post @model { - id: ID! - authorID: ID! - postContents: [String] - authors: [User] @hasMany(fields: ["authorID"], limit: 50) -} - -type PostAuthor @model { - id: ID! - authorID: ID! @index(name: "byAuthor", sortKeyFields: ["postID"]) - postID: ID! - post: Post @hasOne(fields: ["postID"]) -} - -type Student @model { - id: ID! - name: String! - courses: [Course] @manyToMany(relationName: "Enrollment") -} - -type Course @model { - id: ID! - title: String! - students: [Student] @manyToMany(relationName: "Enrollment") -} - -type Foo @model { - bars: [Bar] @hasMany -} - -type Bar @model(queries: null) { - strings: [String] -} - -type ModelA @model { - id: ID! @primaryKey(sortKeyFields: ["sortId"]) - sortId: ID! - name: String! - models: [ModelB] @manyToMany(relationName: "ModelAModelB") -} - -type ModelB @model { - id: ID! - name: String! - models: [ModelA] @manyToMany(relationName: "ModelAModelB") -} -`; - let out; - try { - const authConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }; - const authTransformer = new AuthTransformer(); - const modelTransformer = new ModelTransformer(); - const indexTransformer = new IndexTransformer(); - const hasOneTransformer = new HasOneTransformer(); - out = testTransform({ - schema: validSchema, - authConfig, - transformers: [ - modelTransformer, - new PrimaryKeyTransformer(), - indexTransformer, - hasOneTransformer, - new HasManyTransformer(), - new BelongsToTransformer(), - new ManyToManyTransformer(modelTransformer, indexTransformer, hasOneTransformer, authTransformer), - authTransformer, - ], - transformParameters: { - shouldDeepMergeDirectiveConfigDefaults: false, - populateOwnerFieldForStaticGroupAuth: false, - useSubUsernameForDefaultIdentityClaim: false, - respectPrimaryKeyAttributesOnConnectionField: false, - sandboxModeEnabled: true, - }, - }); - } catch (e) { - console.error(`Failed to transform schema: ${e}`); - expect(true).toEqual(false); - } - try { - await awsS3Client - .createBucket({ - Bucket: BUCKET_NAME, - }) - .promise(); - } catch (e) { - console.error(`Failed to create S3 bucket: ${e}`); - expect(true).toEqual(false); - } - try { - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - {}, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - // Arbitrary wait to make sure everything is ready. - await cf.wait(5, () => Promise.resolve()); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - const endpoint = getApiEndpoint(finishedStack.Outputs); - const apiKey = getApiKey(finishedStack.Outputs); - expect(apiKey).toBeDefined(); - expect(endpoint).toBeDefined(); - GRAPHQL_CLIENT = new GraphQLClient(endpoint, { 'x-api-key': apiKey }); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf); -}); - -/** - * Test queries below - */ - -test('Parent.child getItem', async () => { - const createChild = await GRAPHQL_CLIENT.query( - `mutation { - createChild(input: { id: "1", name: "child1" }) { - id - name - } - }`, - {}, - ); - expect(createChild.data.createChild.id).toBeDefined(); - expect(createChild.data.createChild.name).toEqual('child1'); - const createParent = await GRAPHQL_CLIENT.query( - `mutation { - createParent(input: { childID: "1", childName: "${createChild.data.createChild.name}" }) { - id - childID - childName - } - }`, - {}, - ); - expect(createParent.data.createParent.id).toBeDefined(); - expect(createParent.data.createParent.childID).toEqual(createChild.data.createChild.id); - expect(createParent.data.createParent.childName).toEqual(createChild.data.createChild.name); - const queryParent = await GRAPHQL_CLIENT.query( - `query { - getParent(id: "${createParent.data.createParent.id}") { - id - child { - id - name - } - } - }`, - {}, - ); - expect(queryParent.data.getParent).toBeDefined(); - const { child } = queryParent.data.getParent; - expect(child.id).toEqual(createParent.data.createParent.childID); - expect(child.name).toEqual(createParent.data.createParent.childName); -}); - -test('Child.parents query', async () => { - const createChild = await GRAPHQL_CLIENT.query( - `mutation { - createChild(input: { id: "2", name: "child2" }) { - id - name - } - }`, - {}, - ); - expect(createChild.data.createChild.id).toBeDefined(); - expect(createChild.data.createChild.name).toEqual('child2'); - - const createParent1 = await GRAPHQL_CLIENT.query( - `mutation { - createParent(input: { childID: "${createChild.data.createChild.id}", childName: "${createChild.data.createChild.name}" }) { - id - childID - childName - } - }`, - {}, - ); - expect(createParent1.data.createParent.id).toBeDefined(); - expect(createParent1.data.createParent.childID).toEqual(createChild.data.createChild.id); - expect(createParent1.data.createParent.childName).toEqual(createChild.data.createChild.name); - - const queryChild = await GRAPHQL_CLIENT.query( - `query { - getChild(id: "${createChild.data.createChild.id}", name: "${createChild.data.createChild.name}") { - id - parents { - items { - id - childID - childName - } - } - } - }`, - {}, - ); - expect(queryChild.data.getChild).toBeDefined(); - const { items } = queryChild.data.getChild.parents; - expect(items.length).toEqual(1); - expect(items[0].id).toEqual(createParent1.data.createParent.id); - expect(items[0].childID).toEqual(createParent1.data.createParent.childID); - expect(items[0].childName).toEqual(createParent1.data.createParent.childName); -}); - -test('PostModel.singleAuthor GetItem with composite sortkey', async () => { - const createUser = await GRAPHQL_CLIENT.query( - `mutation { - createUser(input: { id: "123", name: "Bob", surname: "Rob" }) { - id - name - surname - } - }`, - {}, - ); - - expect(createUser.data.createUser.id).toBeDefined(); - expect(createUser.data.createUser.name).toEqual('Bob'); - expect(createUser.data.createUser.surname).toEqual('Rob'); - const createPostModel = await GRAPHQL_CLIENT.query( - `mutation { - createPostModel(input: { authorID: "${createUser.data.createUser.id}", - authorName: "${createUser.data.createUser.name}", - authorSurname: "${createUser.data.createUser.surname}", - postContents: "potato" }) { - id - authorID - authorName - authorSurname - postContents - } - }`, - {}, - ); - expect(createPostModel.data.createPostModel.id).toBeDefined(); - expect(createPostModel.data.createPostModel.authorID).toEqual(createUser.data.createUser.id); - expect(createPostModel.data.createPostModel.authorName).toEqual(createUser.data.createUser.name); - expect(createPostModel.data.createPostModel.authorSurname).toEqual(createUser.data.createUser.surname); - const queryPostModel = await GRAPHQL_CLIENT.query( - `query { - getPostModel(id: "${createPostModel.data.createPostModel.id}") { - id - singleAuthor { - id - name - surname - } - } - }`, - {}, - ); - expect(queryPostModel.data.getPostModel).toBeDefined(); - const author = queryPostModel.data.getPostModel.singleAuthor; - expect(author.id).toEqual(createUser.data.createUser.id); - expect(author.name).toEqual(createUser.data.createUser.name); - expect(author.surname).toEqual(createUser.data.createUser.surname); -}); - -test('PostModel.authors query with composite sortkey', async () => { - const createUser = await GRAPHQL_CLIENT.query( - `mutation { - createUserModel(input: { id: "123", rollNumber: 1, name: "Bob", surname: "Rob" }) { - id - rollNumber - name - surname - } - }`, - {}, - ); - expect(createUser.data.createUserModel.id).toBeDefined(); - expect(createUser.data.createUserModel.name).toEqual('Bob'); - expect(createUser.data.createUserModel.rollNumber).toEqual(1); - expect(createUser.data.createUserModel.surname).toEqual('Rob'); - const createUser2 = await GRAPHQL_CLIENT.query( - `mutation { - createUserModel(input: { id: "123", rollNumber: 2, name: "Bob", surname: "Rob" }) { - id - rollNumber - name - surname - } - }`, - {}, - ); - expect(createUser2.data.createUserModel.id).toBeDefined(); - expect(createUser2.data.createUserModel.name).toEqual('Bob'); - expect(createUser2.data.createUserModel.rollNumber).toEqual(2); - expect(createUser2.data.createUserModel.surname).toEqual('Rob'); - const createPostModel = await GRAPHQL_CLIENT.query( - `mutation { - createPostModel(input: { authorID: "${createUser.data.createUserModel.id}", - authorName: "${createUser.data.createUserModel.name}", - authorSurname: "${createUser.data.createUserModel.surname}", - postContents: "potato" }) { - id - authorID - authorName - authorSurname - postContents - } - }`, - {}, - ); - expect(createPostModel.data.createPostModel.id).toBeDefined(); - expect(createPostModel.data.createPostModel.authorID).toEqual(createUser.data.createUserModel.id); - expect(createPostModel.data.createPostModel.authorName).toEqual(createUser.data.createUserModel.name); - expect(createPostModel.data.createPostModel.authorSurname).toEqual(createUser.data.createUserModel.surname); - const queryPostModel = await GRAPHQL_CLIENT.query( - `query { - getPostModel(id: "${createPostModel.data.createPostModel.id}") { - id - authors { - items { - id - rollNumber - name - surname - } - } - } - }`, - {}, - ); - expect(queryPostModel.data.getPostModel).toBeDefined(); - const { items } = queryPostModel.data.getPostModel.authors; - expect(items.length).toEqual(2); - expect(items[0].id).toEqual(createUser.data.createUserModel.id); - try { - expect(items[0].rollNumber).toEqual(createUser.data.createUserModel.rollNumber); - expect(items[1].rollNumber).toEqual(createUser2.data.createUserModel.rollNumber); - } catch (error) { - expect(items[1].rollNumber).toEqual(createUser.data.createUserModel.rollNumber); - expect(items[0].rollNumber).toEqual(createUser2.data.createUserModel.rollNumber); - } - expect(items[0].name).toEqual(createUser.data.createUserModel.name); - expect(items[0].surname).toEqual(createUser.data.createUserModel.surname); - expect(items[1].id).toEqual(createUser2.data.createUserModel.id); - expect(items[1].surname).toEqual(createUser2.data.createUserModel.surname); - expect(items[1].name).toEqual(createUser2.data.createUserModel.name); -}); - -test('the default limit.', async () => { - for (let i = 0; i < 51; i++) { - await GRAPHQL_CLIENT.query( - `mutation { - createUser(input: { id: "11", name: "user${i}", surname: "sub${i}" }) { - id - name - surname - } - }`, - {}, - ); - } - - const createResponse = await GRAPHQL_CLIENT.query( - ` - mutation { - createPost(input: {authorID: "11", postContents: "helloWorld"}) { - authorID - id - authors { - items { - name - surname - id - } - } - } - }`, - {}, - ); - expect(createResponse).toBeDefined(); - expect(createResponse.data.createPost.authorID).toEqual('11'); - expect(createResponse.data.createPost.authors.items.length).toEqual(50); -}); - -test('PostModel.authors query with composite sortkey passed as arg.', async () => { - const createUser = await GRAPHQL_CLIENT.query( - `mutation { - createUser(input: { id: "123", name: "Bobby", surname: "Rob" }) { - id - name - surname - } - }`, - {}, - ); - expect(createUser.data.createUser.id).toBeDefined(); - expect(createUser.data.createUser.name).toEqual('Bobby'); - expect(createUser.data.createUser.surname).toEqual('Rob'); - const createPost = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { id: "321", authorID: "${createUser.data.createUser.id}", postContents: "potato"}) { - id - authorID - postContents - } - }`, - {}, - ); - expect(createPost.data.createPost.id).toBeDefined(); - expect(createPost.data.createPost.authorID).toEqual(createUser.data.createUser.id); - const queryPost = await GRAPHQL_CLIENT.query( - `query { - getPost(id: "${createPost.data.createPost.id}") { - id - authors(nameSurname: {beginsWith: {name: "${createUser.data.createUser.name}", surname: "${createUser.data.createUser.surname}"}}) { - items { - id - name - surname - } - } - } - }`, - {}, - ); - expect(queryPost.data.getPost).toBeDefined(); - const { items } = queryPost.data.getPost.authors; - expect(items.length).toEqual(1); - expect(items[0].id).toEqual(createUser.data.createUser.id); - expect(items[0].name).toEqual(createUser.data.createUser.name); - expect(items[0].surname).toEqual(createUser.data.createUser.surname); -}); - -test('User.authorPosts.posts query followed by getItem (intermediary model)', async () => { - const createUser = await GRAPHQL_CLIENT.query( - `mutation { - createUserModel(input: { id: "999", rollNumber: 1, name: "Peter", surname: "Pluck" }) { - id - rollNumber - name - surname - } - }`, - {}, - ); - expect(createUser.data.createUserModel.id).toBeDefined(); - expect(createUser.data.createUserModel.name).toEqual('Peter'); - expect(createUser.data.createUserModel.rollNumber).toEqual(1); - expect(createUser.data.createUserModel.surname).toEqual('Pluck'); - const createPost = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { id: "888", authorID: "999", postContents: "abcxyz"}) { - id - authorID - postContents - } - }`, - {}, - ); - expect(createPost.data.createPost.id).toBeDefined(); - const createPostAuthor = await GRAPHQL_CLIENT.query( - `mutation { - createPostAuthor(input: { authorID: "999", postID: "888" }) { - id - authorID - postID - } - }`, - {}, - ); - expect(createPostAuthor.data.createPostAuthor.id).toBeDefined(); - expect(createPostAuthor.data.createPostAuthor.authorID).toEqual('999'); - expect(createPostAuthor.data.createPostAuthor.postID).toEqual('888'); - const queryUser = await GRAPHQL_CLIENT.query( - `query { - getUserModel(id: "999", rollNumber: 1) { - id - authorPosts { - items { - post { - id - postContents - } - } - } - } - }`, - {}, - ); - expect(queryUser.data.getUserModel).toBeDefined(); - const { items } = queryUser.data.getUserModel.authorPosts; - expect(items.length).toEqual(1); - expect(items[0].post.id).toEqual('888'); - expect(items[0].post.postContents).toEqual(['abcxyz']); -}); - -test('User.friendship.friend query (reflexive has many).', async () => { - const createUser = await GRAPHQL_CLIENT.query( - `mutation { - createUser(input: { id: "12", name: "Bobby", surname: "Rob" }) { - id - name - surname - } - }`, - {}, - ); - expect(createUser.data.createUser.id).toBeDefined(); - expect(createUser.data.createUser.name).toEqual('Bobby'); - expect(createUser.data.createUser.surname).toEqual('Rob'); - const createUser1 = await GRAPHQL_CLIENT.query( - `mutation { - createUser(input: { id: "13", name: "Bob", surname: "Rob" }) { - id - name - surname - } - }`, - {}, - ); - expect(createUser1.data.createUser.id).toBeDefined(); - expect(createUser1.data.createUser.name).toEqual('Bob'); - expect(createUser1.data.createUser.surname).toEqual('Rob'); - const createFriendship = await GRAPHQL_CLIENT.query( - `mutation { - createFriendship(input: { id: "1", userID: 13, friendID: 12 }) { - id - userID - friendID - } - }`, - {}, - ); - expect(createFriendship.data.createFriendship.id).toBeDefined(); - expect(createFriendship.data.createFriendship.userID).toEqual('13'); - expect(createFriendship.data.createFriendship.friendID).toEqual('12'); - const queryUser = await GRAPHQL_CLIENT.query( - `query { - getUser(id: "13", name: "Bob", surname: "Rob") { - id - friendships { - items { - friend { - items { - id - name - } - } - } - } - } - }`, - {}, - ); - expect(queryUser.data.getUser).toBeDefined(); - const { items } = queryUser.data.getUser.friendships; - expect(items.length).toEqual(1); - expect(items[0].friend.items[0].id).toEqual('12'); - expect(items[0].friend.items[0].name).toEqual('Bobby'); -}); - -test('Student and Course many to many relationship', async () => { - const createStudent = await GRAPHQL_CLIENT.query( - `mutation { - createStudent(input: { id: "1", name: "Peter Pluck" }) { - id - name - } - }`, - {}, - ); - expect(createStudent.data.createStudent.id).toEqual('1'); - expect(createStudent.data.createStudent.name).toEqual('Peter Pluck'); - - const createCourse = await GRAPHQL_CLIENT.query( - `mutation { - createCourse(input: { id: "CS101", title: "How to Computer" }) { - id - title - } - }`, - {}, - ); - expect(createCourse.data.createCourse.id).toEqual('CS101'); - expect(createCourse.data.createCourse.title).toEqual('How to Computer'); - - const createEnrollment = await GRAPHQL_CLIENT.query( - `mutation { - createEnrollment(input: { id: "CS101-1", studentID: "1", courseID: "CS101" }) { - id - studentID - courseID - } - }`, - {}, - ); - expect(createEnrollment.data.createEnrollment.id).toEqual('CS101-1'); - expect(createEnrollment.data.createEnrollment.studentID).toEqual('1'); - expect(createEnrollment.data.createEnrollment.courseID).toEqual('CS101'); - - const queryRelation = await GRAPHQL_CLIENT.query( - `query { - listStudents(filter: { id: { eq: "1" } }) { - items { - id - name - courses { - items { - id - studentID - courseID - student { - id - name - } - course { - id - title - students { - items { - id - studentID - courseID - } - } - } - } - } - } - } - }`, - {}, - ); - expect(queryRelation.errors).toBeUndefined(); - expect(queryRelation.data.listStudents).toEqual({ - items: [ - { - id: '1', - name: 'Peter Pluck', - courses: { - items: [ - { - id: 'CS101-1', - studentID: '1', - courseID: 'CS101', - student: { - id: '1', - name: 'Peter Pluck', - }, - course: { - id: 'CS101', - title: 'How to Computer', - students: { - items: [ - { - id: 'CS101-1', - studentID: '1', - courseID: 'CS101', - }, - ], - }, - }, - }, - ], - }, - }, - ], - }); -}); - -test('many to many relationship with sort key', async () => { - await createModelAItem('1', 'A1', 'ModelA 1 - A1'); - await createModelAItem('1', 'A2', 'ModelA 1 - A2'); - await createModelAItem('2', 'A1', 'ModelA 2 - A1'); - - await createModelBItem('1', 'ModelB 1'); - await createModelBItem('2', 'ModelB 2'); - - await createModelAModelBItem('1-A1-1', '1', 'A1', '1'); - await createModelAModelBItem('1-A1-2', '1', 'A1', '2'); - await createModelAModelBItem('2-A1-2', '2', 'A1', '2'); - - let queryRelation = await GRAPHQL_CLIENT.query( - `query { - listModelAS(filter: { id: { eq: "1" }, sortId: { eq: "A1" } }) { - items { - id - sortId - name - models { - items { - modelB { - id - name - } - } - } - } - } - }`, - {}, - ); - expect(queryRelation.errors).toBeUndefined(); - expect(queryRelation.data.listModelAS).toEqual({ - items: [ - { - id: '1', - sortId: 'A1', - name: 'ModelA 1 - A1', - models: { - items: [ - { - modelB: { - id: '2', - name: 'ModelB 2', - }, - }, - { - modelB: { - id: '1', - name: 'ModelB 1', - }, - }, - ], - }, - }, - ], - }); - - queryRelation = await GRAPHQL_CLIENT.query( - `query { - listModelAS(filter: { id: { eq: "2" }, sortId: { eq: "A1" } }) { - items { - id - sortId - name - models { - items { - modelB { - id - name - } - } - } - } - } - }`, - {}, - ); - expect(queryRelation.errors).toBeUndefined(); - expect(queryRelation.data.listModelAS).toEqual({ - items: [ - { - id: '2', - sortId: 'A1', - name: 'ModelA 2 - A1', - models: { - items: [ - { - modelB: { - id: '2', - name: 'ModelB 2', - }, - }, - ], - }, - }, - ], - }); - - queryRelation = await GRAPHQL_CLIENT.query( - `query { - listModelAS(filter: { id: { eq: "1" }, sortId: { eq: "A2" } }) { - items { - id - sortId - name - models { - items { - modelB { - id - name - } - } - } - } - } - }`, - {}, - ); - expect(queryRelation.errors).toBeUndefined(); - expect(queryRelation.data.listModelAS).toEqual({ - items: [ - { - id: '1', - sortId: 'A2', - name: 'ModelA 1 - A2', - models: { - items: [], - }, - }, - ], - }); -}); - -async function createModelAItem(id: string, sortId: string, name: string): Promise { - const createModelA = await GRAPHQL_CLIENT.query( - `mutation { - createModelA(input: { id: "${id}", sortId: "${sortId}", name: "${name}" }) { - id - sortId - name - } - }`, - {}, - ); - expect(createModelA.data.createModelA.id).toEqual(id); - expect(createModelA.data.createModelA.sortId).toEqual(sortId); - expect(createModelA.data.createModelA.name).toEqual(name); -} - -async function createModelBItem(id: string, name: string): Promise { - const createModelB = await GRAPHQL_CLIENT.query( - `mutation { - createModelB(input: { id: "${id}", name: "${name}" }) { - id - name - } - }`, - {}, - ); - expect(createModelB.data.createModelB.id).toEqual(id); - expect(createModelB.data.createModelB.name).toEqual(name); -} - -async function createModelAModelBItem(id: string, modelAId: string, modelASortId: string, modelBId: string) { - const createModelAModelB = await GRAPHQL_CLIENT.query( - `mutation { - createModelAModelB(input: { id: "${id}", modelAID: "${modelAId}", modelAsortId: "${modelASortId}", modelBID: "${modelBId}" }) { - id - modelAID - modelAsortId - modelBID - } - }`, - {}, - ); - expect(createModelAModelB.data.createModelAModelB.id).toEqual(id); - expect(createModelAModelB.data.createModelAModelB.modelAID).toEqual(modelAId); - expect(createModelAModelB.data.createModelAModelB.modelAsortId).toEqual(modelASortId); - expect(createModelAModelB.data.createModelAModelB.modelBID).toEqual(modelBId); -} diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/RelationalWithOwnerFieldAsKeySchemaAuth.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/RelationalWithOwnerFieldAsKeySchemaAuth.e2e.test.ts deleted file mode 100644 index 9cab897079..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/RelationalWithOwnerFieldAsKeySchemaAuth.e2e.test.ts +++ /dev/null @@ -1,251 +0,0 @@ -import { PrimaryKeyTransformer } from '@aws-amplify/graphql-index-transformer'; -import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; -import { HasManyTransformer } from '@aws-amplify/graphql-relational-transformer'; -import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer'; -import { testTransform } from '@aws-amplify/graphql-transformer-test-utils'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { S3, CognitoIdentityServiceProvider as CognitoClient } from 'aws-sdk'; -import { default as moment } from 'moment'; -import AWSAppSyncClient, { AUTH_TYPE } from 'aws-appsync'; -import gql from 'graphql-tag'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { S3Client } from '../S3Client'; -import { authenticateUser, configureAmplify, createUserPool, createUserPoolClient, signupUser } from '../cognitoUtils'; -// to deal with bug in cognito-identity-js -(global as any).fetch = require('node-fetch'); - -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); -const cognitoClient = new CognitoClient({ apiVersion: '2016-04-19', region: region }); -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `RelationalOwnerAuthTransformersTest-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `appsync-relational-owner-auth-transformer-test-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/relational_owner_auth_transformer_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; - -let GRAPHQL_ENDPOINT: string; - -let USER_POOL_AUTH_CLIENT_1: AWSAppSyncClient; -let USER_POOL_AUTH_CLIENT_2: AWSAppSyncClient; - -let USER_POOL_ID: string; - -const USERNAME1 = 'user1@test.com'; -const USERNAME2 = 'user2@test.com'; -const TMP_PASSWORD = 'Password123!'; -const REAL_PASSWORD = 'Password1234!'; - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -beforeAll(async () => { - const validSchema = ` - type User @model - @auth(rules: [ - {allow: owner, ownerField: "userID"}, - {allow: private, operations: [get]} - ]) { - userID: String!@primaryKey - displayName: String - firstname: String @auth(rules: [{allow: owner, ownerField: "userID"}]) - lastname: String @auth(rules: [{allow: owner, ownerField: "userID"}]) - birth: AWSDate @auth(rules: [{allow: owner, ownerField: "userID"}]) - creditCards: [CreditCard!] @hasMany(fields: ["userID"]) - } - - type CreditCard @model - @auth(rules:[{allow: owner, ownerField: "userID"}]) - { - userID: String! @primaryKey(sortKeyFields: ["number","expMonth","expYear"]) - number: String! - expMonth: String! - expYear: String! - name: String - issuer: String - } - `; - let out; - try { - const modelTransformer = new ModelTransformer(); - const hasManyTransformer = new HasManyTransformer(); - const authTransformer = new AuthTransformer(); - const primaryKeyTransformer = new PrimaryKeyTransformer(); - out = testTransform({ - schema: validSchema, - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - transformers: [modelTransformer, primaryKeyTransformer, hasManyTransformer, authTransformer], - }); - } catch (e) { - console.error(`Failed to transform schema: ${e}`); - expect(true).toEqual(false); - } - try { - await awsS3Client - .createBucket({ - Bucket: BUCKET_NAME, - }) - .promise(); - } catch (e) { - console.error(`Failed to create S3 bucket: ${e}`); - expect(true).toEqual(false); - } - const userPoolResponse = await createUserPool(cognitoClient, `UserPool${STACK_NAME}`); - USER_POOL_ID = userPoolResponse.UserPool?.Id!; - const userPoolClientResponse = await createUserPoolClient(cognitoClient, USER_POOL_ID, `UserPool${STACK_NAME}`); - const userPoolClientId = userPoolClientResponse.UserPoolClient?.ClientId!; - try { - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { AuthCognitoUserPoolId: USER_POOL_ID }, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - const apiKey = getApiKey(finishedStack.Outputs!); - GRAPHQL_ENDPOINT = getApiEndpoint(finishedStack.Outputs!)!; - expect(apiKey).not.toBeTruthy(); - - // Verify we have all the details - expect(GRAPHQL_ENDPOINT).toBeTruthy(); - expect(USER_POOL_ID).toBeTruthy(); - expect(userPoolClientId).toBeTruthy(); - - // Configure Amplify, create users, and sign in. - configureAmplify(USER_POOL_ID, userPoolClientId); - await signupUser(USER_POOL_ID, USERNAME1, TMP_PASSWORD); - const authRes1 = await authenticateUser(USERNAME1, TMP_PASSWORD, REAL_PASSWORD); - const idToken1 = authRes1.getIdToken().getJwtToken(); - USER_POOL_AUTH_CLIENT_1 = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: () => idToken1, - }, - disableOffline: true, - }); - await signupUser(USER_POOL_ID, USERNAME2, TMP_PASSWORD); - const authRes2 = await authenticateUser(USERNAME2, TMP_PASSWORD, REAL_PASSWORD); - const idToken2 = authRes2.getIdToken().getJwtToken(); - USER_POOL_AUTH_CLIENT_2 = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: () => idToken2, - }, - disableOffline: true, - }); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf, { cognitoClient, userPoolId: USER_POOL_ID }); -}); - -/** - * Test queries below - */ -test('user2 should not access user1 restricted fields when query including relational fields', async () => { - const createUser1Mutation = gql` - mutation { - createUser(input: { userID:"${USERNAME1}", displayName:"d1", firstname: "f1", lastname: "l1", birth: "2023-04-07" }) { - userID - } - } - `; - const createUser1 = await USER_POOL_AUTH_CLIENT_1.mutate({ - mutation: createUser1Mutation, - fetchPolicy: 'no-cache', - }); - expect(createUser1.data.createUser.userID).toEqual(USERNAME1); - - const createCreditCard1 = await USER_POOL_AUTH_CLIENT_1.mutate({ - mutation: gql` - mutation { - createCreditCard(input: { userID:"${USERNAME1}", number:"10000", expMonth: "07", expYear: "2027", name: "platimum", issuer: "amex" }) { - userID - } - } - `, - fetchPolicy: 'no-cache', - }); - expect(createCreditCard1.data.createCreditCard.userID).toEqual(USERNAME1); - - const getUserQueryWithCreditCard = gql` - query ($userID: String!) { - getUser(userID: $userID) { - creditCards { - items { - number - name - issuer - userID - expYear - expMonth - } - } - firstname - lastname - birth - displayName - userID - } - } - `; - const getResponse = await USER_POOL_AUTH_CLIENT_1.query({ - query: getUserQueryWithCreditCard, - variables: { - userID: USERNAME1, - }, - }); - expect(getResponse.data.getUser.creditCards.items[0].number).toEqual('10000'); - expect(getResponse.data.getUser.creditCards.items[0].name).toEqual('platimum'); - expect(getResponse.data.getUser.creditCards.items[0].issuer).toEqual('amex'); - expect(getResponse.data.getUser.creditCards.items[0].userID).toEqual(USERNAME1); - expect(getResponse.data.getUser.creditCards.items[0].expYear).toEqual('2027'); - expect(getResponse.data.getUser.creditCards.items[0].expMonth).toEqual('07'); - - expect(getResponse.data.getUser.firstname).toEqual('f1'); - expect(getResponse.data.getUser.lastname).toEqual('l1'); - expect(getResponse.data.getUser.birth).toEqual('2023-04-07'); - expect(getResponse.data.getUser.displayName).toEqual('d1'); - expect(getResponse.data.getUser.userID).toEqual(USERNAME1); - // Run query with user2 login and use user1 as parameter - await expect( - USER_POOL_AUTH_CLIENT_2.query({ - query: getUserQueryWithCreditCard, - variables: { - userID: USERNAME1, - }, - }), - ).rejects.toThrow('GraphQL error: Not Authorized to access'); -}); diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableModelTransformer.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableModelTransformer.e2e.test.ts deleted file mode 100644 index 0dee8f14a5..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableModelTransformer.e2e.test.ts +++ /dev/null @@ -1,1053 +0,0 @@ -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform, ConflictHandlerType } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { KeyTransformer } from 'graphql-key-transformer'; -import { SearchableModelTransformer } from 'graphql-elasticsearch-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as moment } from 'moment'; -import { default as S3 } from 'aws-sdk/clients/s3'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { S3Client } from '../S3Client'; -import { GraphQLClient } from '../GraphQLClient'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import addStringSets from '../stringSetMutations'; -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -// tslint:disable: no-magic-numbers -jest.setTimeout(60000 * 60); - -const cf = new CloudFormationClient(region); -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); -let GRAPHQL_CLIENT: GraphQLClient = undefined; -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `TestSearchableModelTransformer-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `testsearchablemodeltransformer-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/model_searchable_transform_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; - -const fragments = [`fragment FullPost on Post { id author title ups downs percentageUp isPublished createdAt }`]; - -const runQuery = async (query: string) => { - try { - const q = [query, ...fragments].join('\n'); - const response = await GRAPHQL_CLIENT.query(q, {}); - return response; - } catch (e) { - console.error(e); - return null; - } -}; - -const createEntries = async () => { - // create posts - await runQuery(getCreatePostsMutation('snvishna', 'test', 157, 10, 97.4, true)); - await runQuery(getCreatePostsMutation('snvishna', 'test title', 60, 30, 21.0, false)); - await runQuery(getCreatePostsMutation('shankar', 'test title', 160, 30, 97.6, false)); - await runQuery(getCreatePostsMutation('snvishna', 'test TITLE', 170, 30, 88.8, true)); - await runQuery(getCreatePostsMutation('snvishna', 'test title', 200, 50, 11.9, false)); - await runQuery(getCreatePostsMutation('snvishna', 'test title', 170, 30, 88.8, true)); - await runQuery(getCreatePostsMutation('snvishna', 'test title', 160, 30, 97.6, false)); - await runQuery(getCreatePostsMutation('snvishna', 'test title', 170, 30, 77.7, true)); - // create users - await GRAPHQL_CLIENT.query(getCreateUsersMutation(), { - input: { name: 'user1', userItems: ['thing1', 'thing2'], createdAt: '2016-07-20' }, - }); - await GRAPHQL_CLIENT.query(getCreateUsersMutation(), { - input: { name: 'user2', userItems: ['thing3', 'thing4'], createdAt: '2017-06-10' }, - }); - await GRAPHQL_CLIENT.query(getCreateUsersMutation(), { - input: { name: 'user3', userItems: ['thing5', 'thing6'], createdAt: '2017-08-22' }, - }); - await GRAPHQL_CLIENT.query(getCreateUsersMutation(), { - input: { name: 'user4', userItems: ['thing7', 'thing8'], createdAt: '2019-07-04' }, - }); - // create books - await GRAPHQL_CLIENT.query(createBookMutation(), { - input: { author: 'Agatha Christie', name: 'Murder on the Orient Express', genre: 'Mystery' }, - }); - await GRAPHQL_CLIENT.query(createBookMutation(), { input: { author: 'Agatha Christie', name: 'Death on the Nile', genre: 'Mystery' } }); - await GRAPHQL_CLIENT.query(createBookMutation(), { input: { author: 'Ayn Rand', name: 'Anthem', genre: 'Science Fiction' } }); - // Waiting for the ES Cluster + Streaming Lambda infra to be setup - await cf.wait(120, () => Promise.resolve()); -}; - -beforeAll(async () => { - const validSchema = ` - type Post @model @searchable { - id: ID! - author: String! - title: String - content: String - url: String - ups: Int - downs: Int - version: Int - relatedPosts: [Post] - postedAt: String - createdAt: AWSDateTime - comments: [String!] - ratings: [Int!] - percentageUp: Float - isPublished: Boolean - jsonField: AWSJSON - } - - type User @model @searchable { - id: ID! - name: String! - createdAt: AWSDate - userItems: [String] - } - - type Book - @model - @key(fields: ["author", "name"]) - @searchable - { - author: String! - name: String! - genre: String! - } - - type Todo - @model - @searchable { - id: ID - name: String! - createdAt: AWSDateTime - description: String - } - - type Comment @model @key(name: "commentByVersion", fields: ["version", "id"]) @searchable{ - id: ID! - version: Int! - content: String! - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new KeyTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }, - }), - new SearchableModelTransformer(), - ], - // only enable datastore features on todo - transformConfig: { - ResolverConfig: { - models: { - Todo: { - ConflictHandler: ConflictHandlerType.AUTOMERGE, - ConflictDetection: 'VERSION', - }, - }, - }, - }, - }); - try { - await awsS3Client.createBucket({ Bucket: BUCKET_NAME }).promise(); - } catch (e) { - console.error(`Failed to create bucket: ${e}`); - } - try { - // change create/update to create string sets - const out = addStringSets(transformer.transform(validSchema)); - // fs.writeFileSync('./out.json', JSON.stringify(out, null, 4)) - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { CreateAPIKey: '1' }, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - // Arbitrary wait to make sure everything is ready. - await cf.wait(120, () => Promise.resolve()); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - const endpoint = getApiEndpoint(finishedStack.Outputs); - const apiKey = getApiKey(finishedStack.Outputs); - expect(apiKey).toBeDefined(); - expect(endpoint).toBeDefined(); - GRAPHQL_CLIENT = new GraphQLClient(endpoint, { 'x-api-key': apiKey }); - - // Create sample mutations to test search queries - await createEntries(); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf); -}); - -test('searchPosts with sort field on a string field', async () => { - const firstQuery = await runQuery( - `query { - searchPosts(sort: { - field: id - direction: desc - }){ - items{ - ...FullPost - } - nextToken - } - }`, - ); - expect(firstQuery).toBeDefined(); - expect(firstQuery.data.searchPosts).toBeDefined(); - const fourthItemOfFirstQuery = firstQuery.data.searchPosts.items[3]; - const secondQuery = await runQuery( - `query { - searchPosts(limit: 3, sort: { - field: id - direction: desc - }){ - items{ - ...FullPost - } - nextToken - } - }`, - ); - expect(secondQuery).toBeDefined(); - expect(secondQuery.data.searchPosts).toBeDefined(); - const nextToken = secondQuery.data.searchPosts.nextToken; - expect(nextToken).toBeDefined(); - const thirdQuery = await runQuery( - `query { - searchPosts(nextToken: "${nextToken}", limit: 3, sort: { - field: id - direction: desc - }){ - items{ - ...FullPost - } - nextToken - } - }`, - ); - expect(thirdQuery).toBeDefined(); - expect(thirdQuery.data.searchPosts).toBeDefined(); - const firstItemOfThirdQuery = thirdQuery.data.searchPosts.items[0]; - expect(firstItemOfThirdQuery).toEqual(fourthItemOfFirstQuery); -}); - -test('searchPosts with offset pagination', async () => { - const firstQuery = await runQuery( - `query { - searchPosts(from: 0, limit: 999, sort: { - field: id - direction: desc - }){ - items{ - ...FullPost - } - nextToken - total - } - }`, - ); - expect(firstQuery).toBeDefined(); - expect(firstQuery.data.searchPosts).toBeDefined(); - const firstLength = firstQuery.data.searchPosts.items.length; - const secondQuery = await runQuery( - `query { - searchPosts(from: 2, limit: 999, sort: { - field: id - direction: desc - }){ - items{ - ...FullPost - } - nextToken - total - } - }`, - ); - expect(secondQuery).toBeDefined(); - expect(secondQuery.data.searchPosts).toBeDefined(); - const secondLength = secondQuery.data.searchPosts.items.length; - expect(secondLength).toEqual(firstLength - 2); - const firstItem = firstQuery.data.searchPosts.items[0]; - const secondItems = secondQuery.data.searchPosts.items; - expect(secondItems.find((i) => i.id === firstItem.id)).not.toBeDefined(); -}); - -test('searchPosts with sort on date type', async () => { - const query = await runQuery( - `query { - searchPosts( - sort: { - field: createdAt - direction: desc - }) { - items { - ...FullPost - } - } - }`, - ); - expect(query).toBeDefined(); - expect(query.data.searchPosts).toBeDefined(); - const recentItem = new Date(query.data.searchPosts.items[0].createdAt); - const oldestItem = new Date(query.data.searchPosts.items[query.data.searchPosts.items.length - 1].createdAt); - expect(recentItem > oldestItem); -}); - -test('searchPosts query without filter', async () => { - const response = await runQuery( - `query { - searchPosts { - items { ...FullPost } - } - }`, - ); - expect(response).toBeDefined(); - expect(response.data.searchPosts.items).toBeDefined(); - const items = response.data.searchPosts.items; - expect(items.length).toBeGreaterThan(0); -}); - -test('searchPosts query with basic filter', async () => { - const response = await runQuery( - `query { - searchPosts(filter: { - author: { eq: "snvishna" } - }) { - items { ...FullPost } - } - }`, - ); - expect(response).toBeDefined(); - expect(response.data.searchPosts.items).toBeDefined(); - const items = response.data.searchPosts.items; - expect(items.length).toEqual(7); -}); - -test('searchPosts query with non-recursive filter', async () => { - const response = await runQuery( - `query { - searchPosts(filter: { - title: { eq: "test title" } - ups: { gte: 100 } - percentageUp: { ne: 77.7 } - downs: { range: [29, 31] } - author: { wildcard: "s*a" } - isPublished: { eq: true } - }) { - items { ...FullPost } - } - }`, - ); - expect(response).toBeDefined(); - expect(response.data.searchPosts.items).toBeDefined(); - const items = response.data.searchPosts.items; - expect(items.length).toEqual(1); - expect(items[0].id).toBeDefined(); - expect(items[0].author).toEqual('snvishna'); - expect(items[0].title).toEqual('test title'); - expect(items[0].ups).toEqual(170); - expect(items[0].downs).toEqual(30); - expect(items[0].percentageUp).toEqual(88.8); - expect(items[0].isPublished).toEqual(true); -}); - -test('searchPosts query with recursive filter 1', async () => { - const response = await runQuery( - `query { - searchPosts(filter: { - downs: { eq: 10 } - or: [ - { - author: { wildcard: "s*a" }, - downs: { eq: 30 } - }, - { - isPublished: { eq: true } - } - ] - }) { - items { ...FullPost } - } - }`, - ); - expect(response).toBeDefined(); - expect(response.data.searchPosts.items).toBeDefined(); - const items = response.data.searchPosts.items; - expect(items.length).toEqual(1); - expect(items[0].id).toBeDefined(); - expect(items[0].author).toEqual('snvishna'); - expect(items[0].title).toEqual('test'); - expect(items[0].ups).toEqual(157); - expect(items[0].downs).toEqual(10); - expect(items[0].percentageUp).toEqual(97.4); - expect(items[0].isPublished).toEqual(true); -}); - -test('searchPosts query with recursive filter 2', async () => { - const response = await runQuery( - `query { - searchPosts(filter: { - downs: { eq: 30 } - or: [ - { - author: { wildcard: "s*a" }, - downs: { eq: 30 } - }, - { - isPublished: { eq: true } - } - ] - }) { - items { ...FullPost } - } - }`, - ); - expect(response).toBeDefined(); - expect(response.data.searchPosts.items).toBeDefined(); - const items = response.data.searchPosts.items; - expect(items.length).toEqual(5); -}); - -test('searchPosts query with recursive filter 3', async () => { - const response = await runQuery( - `query { - searchPosts(filter: { - ups:{ gt:199 } - and:[ - { - or:[ - { - author:{ wildcard:"s*a" } - }, - { - downs:{ ne:30 } - } - ] - }, - { - isPublished:{ eq:false } - } - ] - }) { - items { ...FullPost } - } - }`, - ); - expect(response).toBeDefined(); - expect(response.data.searchPosts.items).toBeDefined(); - const items = response.data.searchPosts.items; - expect(items.length).toEqual(1); - expect(items[0].id).toBeDefined(); - expect(items[0].author).toEqual('snvishna'); - expect(items[0].title).toEqual('test title'); - expect(items[0].ups).toEqual(200); - expect(items[0].downs).toEqual(50); - expect(items[0].percentageUp).toEqual(11.9); - expect(items[0].isPublished).toEqual(false); -}); - -test('searchPosts query with recursive filter 4', async () => { - const response = await runQuery( - `query { - searchPosts(filter: { - ups:{ gt:100 } - and:[ - { - or:[ - { - author:{ wildcard:"s*a" } - }, - { - downs:{ ne:30 } - } - ] - }, - { - isPublished:{ eq:false } - } - ], - not: { - percentageUp: { lt: 20 } - } - }) { - items { ...FullPost } - } - }`, - ); - expect(response).toBeDefined(); - expect(response.data.searchPosts.items).toBeDefined(); - const items = response.data.searchPosts.items; - expect(items.length).toEqual(1); - expect(items[0].id).toBeDefined(); - expect(items[0].author).toEqual('snvishna'); - expect(items[0].title).toEqual('test title'); - expect(items[0].ups).toEqual(160); - expect(items[0].downs).toEqual(30); - expect(items[0].percentageUp).toEqual(97.6); - expect(items[0].isPublished).toEqual(false); -}); - -test('searchPosts query with recursive filter 5', async () => { - const response = await runQuery( - `query { - searchPosts(filter: { - downs:{ ne:30 } - or:[ - { - and:[ - { - author:{ wildcard:"s*a" }, - not: { - isPublished: { eq: true } - } - } - ] - }, - { - percentageUp:{ range: [90.0, 100.0] } - } - ] - and: { - title:{ matchPhrasePrefix: "test t" } - } - }) { - items { ...FullPost } - } - }`, - ); - expect(response).toBeDefined(); - expect(response.data.searchPosts.items).toBeDefined(); - const items = response.data.searchPosts.items; - expect(items.length).toEqual(1); - expect(items[0].id).toBeDefined(); - expect(items[0].author).toEqual('snvishna'); - expect(items[0].title).toEqual('test title'); - expect(items[0].ups).toEqual(200); - expect(items[0].downs).toEqual(50); - expect(items[0].percentageUp).toEqual(11.9); - expect(items[0].isPublished).toEqual(false); -}); - -test('searchPosts query with recursive filter 6', async () => { - const response = await runQuery( - `query { - searchPosts(filter: { - not: { - title:{ wildcard: "*test*" } - } - or:[ - { - and:[ - { - author:{ wildcard:"s*a" }, - not: { - isPublished: { eq: true } - } - } - ] - }, - { - percentageUp:{ range: [90.0, 100.0] } - } - ] - }) { - items { ...FullPost } - } - }`, - ); - expect(response).toBeDefined(); - expect(response.data.searchPosts.items).toBeDefined(); - const items = response.data.searchPosts.items; - expect(items.length).toEqual(0); -}); - -test('deletePosts syncing with Elasticsearch', async () => { - // Create Post - const title = 'to be deleted'; - const postToBeDeletedResponse = await runQuery(getCreatePostsMutation('test author new', title, 1157, 1000, 22.2, true)); - expect(postToBeDeletedResponse).toBeDefined(); - expect(postToBeDeletedResponse.data.createPost).toBeDefined(); - expect(postToBeDeletedResponse.data.createPost.id).toBeDefined(); - - // Wait for the Post to sync to Elasticsearch - await cf.wait(10, () => Promise.resolve()); - - const searchResponse1 = await runQuery( - `query { - searchPosts(filter: { - title: { eq: "${title}" } - }) { - items { ...FullPost } - } - }`, - ); - expect(searchResponse1).toBeDefined(); - expect(searchResponse1.data.searchPosts.items).toBeDefined(); - const items1 = searchResponse1.data.searchPosts.items; - expect(items1.length).toEqual(1); - expect(items1[0].id).toEqual(postToBeDeletedResponse.data.createPost.id); - expect(items1[0].author).toEqual('test author new'); - expect(items1[0].title).toEqual(title); - expect(items1[0].ups).toEqual(1157); - expect(items1[0].downs).toEqual(1000); - expect(items1[0].percentageUp).toEqual(22.2); - expect(items1[0].isPublished).toEqual(true); - - const deleteResponse = await runQuery( - `mutation { - deletePost(input: { - id: "${postToBeDeletedResponse.data.createPost.id}" - }) { - ...FullPost - } - }`, - ); - expect(deleteResponse).toBeDefined(); - expect(deleteResponse.data.deletePost).toBeDefined(); - expect(deleteResponse.data.deletePost.id).toEqual(postToBeDeletedResponse.data.createPost.id); - - // Wait for the Deleted Post to sync to Elasticsearch - await cf.wait(10, () => Promise.resolve()); - - const searchResponse2 = await runQuery( - `query { - searchPosts(filter: { - title: { eq: "${title}" } - }) { - items { ...FullPost } - } - }`, - ); - expect(searchResponse2).toBeDefined(); - expect(searchResponse2.data.searchPosts.items).toBeDefined(); - const items2 = searchResponse2.data.searchPosts.items; - expect(items2.length).toEqual(0); -}); - -test('updatePost syncing with Elasticsearch', async () => { - // Create Post - const author = 'test author update new'; - const title = 'to be updated new'; - const ups = 2157; - const downs = 2000; - const percentageUp = 22.2; - const isPublished = true; - - const postToBeUpdatedResponse = await runQuery(getCreatePostsMutation(author, title, ups, downs, percentageUp, isPublished)); - expect(postToBeUpdatedResponse).toBeDefined(); - expect(postToBeUpdatedResponse.data.createPost).toBeDefined(); - - const id = postToBeUpdatedResponse.data.createPost.id; - expect(id).toBeDefined(); - - // Wait for the Post to sync to Elasticsearch - await cf.wait(10, () => Promise.resolve()); - - const searchResponse1 = await runQuery( - `query { - searchPosts(filter: { - id: { eq: "${id}" } - }) { - items { ...FullPost } - } - }`, - ); - expect(searchResponse1).toBeDefined(); - expect(searchResponse1.data.searchPosts.items).toBeDefined(); - const items1 = searchResponse1.data.searchPosts.items; - expect(items1.length).toEqual(1); - expect(items1[0].id).toEqual(id); - expect(items1[0].author).toEqual(author); - expect(items1[0].title).toEqual(title); - expect(items1[0].ups).toEqual(ups); - expect(items1[0].downs).toEqual(downs); - expect(items1[0].percentageUp).toEqual(percentageUp); - expect(items1[0].isPublished).toEqual(isPublished); - - const newTitle = title.concat('_updated'); - const updateResponse = await runQuery( - `mutation { - updatePost(input: { - id: "${id}" - author: "${author}" - title: "${newTitle}" - ups: ${ups} - downs: ${downs} - percentageUp: ${percentageUp} - isPublished: ${isPublished} - }) { - ...FullPost - } - }`, - ); - expect(updateResponse).toBeDefined(); - expect(updateResponse.data.updatePost).toBeDefined(); - expect(updateResponse.data.updatePost.id).toEqual(id); - expect(updateResponse.data.updatePost.title).toEqual(newTitle); - - // Wait for the Update Post to sync to Elasticsearch - await cf.wait(10, () => Promise.resolve()); - - const searchResponse2 = await runQuery( - `query { - searchPosts(filter: { - id: { eq: "${id}" } - }) { - items { ...FullPost } - } - }`, - ); - expect(searchResponse2).toBeDefined(); - expect(searchResponse2.data.searchPosts.items).toBeDefined(); - const items2 = searchResponse2.data.searchPosts.items; - expect(items2.length).toEqual(1); - expect(items2[0].id).toEqual(id); - expect(items2[0].author).toEqual(author); - expect(items2[0].title).toEqual(newTitle); - expect(items2[0].ups).toEqual(ups); - expect(items2[0].downs).toEqual(downs); - expect(items2[0].percentageUp).toEqual(percentageUp); - expect(items2[0].isPublished).toEqual(isPublished); -}); - -test('query users knowing userItems is a string set in ddb but should be a list in es', async () => { - const searchResponse = await GRAPHQL_CLIENT.query( - `query { - searchUsers { - items { - id - name - userItems - } - nextToken - total - } - }`, - {}, - ); - expect(searchResponse).toBeDefined(); - const items = searchResponse.data.searchUsers.items; - expect(items.length).toEqual(4); -}); - -test('query using string range between names', async () => { - // using string range queries - const expectedUsers = ['user2', 'user3']; - const expectedLength = 2; - const searchResponse = await GRAPHQL_CLIENT.query( - `query { - searchUsers(filter: { - name: { - lt: "user4" - gt: "user1" - } - }) { - items { - id - name - } - } - }`, - {}, - ); - expect(searchResponse).toBeDefined(); - const items = searchResponse.data.searchUsers.items; - expect(items.length).toEqual(expectedLength); - items.forEach((item: any) => { - expect(expectedUsers).toContain(item.name); - }); -}); - -test('query using date range using lte and gte for createdAt', async () => { - const expectedDates = ['2017-06-10', '2017-08-22']; - const expectedLength = 2; - const searchResponse = await GRAPHQL_CLIENT.query( - `query { - searchUsers(filter: { - createdAt: { - lte: "2017-08-22" - gte: "2017-06-10" - } - }) { - items { - id - name - createdAt - userItems - } - } - }`, - {}, - ); - expect(searchResponse).toBeDefined(); - const items = searchResponse.data.searchUsers.items; - expect(items.length).toEqual(expectedLength); - items.forEach((item: any) => { - expect(expectedDates).toContain(item.createdAt); - }); -}); - -test('query using date range for createdAt', async () => { - const expectLength = 3; - const searchResponse = await GRAPHQL_CLIENT.query( - `query { - searchUsers(filter: {createdAt: {range: ["2016", "2019"]}}) { - items { - id - name - createdAt - userItems - } - } - } - `, - {}, - ); - expect(searchResponse).toBeDefined(); - const items = searchResponse.data.searchUsers.items; - expect(items.length).toEqual(expectLength); - expect(items.map((item) => item.createdAt).sort()).toEqual(['2016-07-20', '2017-06-10', '2017-08-22']); -}); - -test('query for books by Agatha Christie with model using @key', async () => { - const expectedBookItemsLength = 2; - const expectedBookNames: string[] = ['Murder on the Orient Express', 'Death on the Nile']; - const searchResponse = await GRAPHQL_CLIENT.query( - ` - query SearchBooks { - searchBooks(filter: { - author: { - eq: "Agatha Christie" - } - }) { - items { - author - name - genre - } - } - } - `, - {}, - ); - expect(searchResponse).toBeDefined(); - const items: any[] = searchResponse.data.searchBooks.items; - expect(items.length).toEqual(expectedBookItemsLength); - items.forEach((item: any) => { - expect(expectedBookNames).toContain(item.name); - }); -}); - -test('searches with datastore enabled types', async () => { - const createTodoResponse = await createTodo({ id: '001', name: 'get milk' }); - expect(createTodoResponse).toBeDefined(); - let todoName = createTodoResponse.data.createTodo.name; - let todoVersion = createTodoResponse.data.createTodo._version; - - // Wait for the Todo to sync to Elasticsearch - await cf.wait(10, () => Promise.resolve()); - - let searchTodoResponse = await searchTodos(); - expect(searchTodoResponse).toBeDefined(); - expect(searchTodoResponse.data.searchTodos.items.length).toEqual(1); - expect(searchTodoResponse.data.searchTodos.items[0].name).toEqual(todoName); - expect(searchTodoResponse.data.searchTodos.items[0]._version).toEqual(todoVersion); - todoName = 'get soy milk'; - - const updateTodoResponse = await updateTodo({ id: '001', name: todoName, _version: todoVersion }); - expect(updateTodoResponse).toBeDefined(); - todoVersion += 1; - expect(updateTodoResponse.data.updateTodo.name).toEqual(todoName); - expect(updateTodoResponse.data.updateTodo._version).toEqual(todoVersion); - - // Wait for the Todo to sync to Elasticsearch - await cf.wait(10, () => Promise.resolve()); - - searchTodoResponse = await searchTodos(); - expect(searchTodoResponse.data.searchTodos.items.length).toEqual(1); - expect(searchTodoResponse.data.searchTodos.items[0].name).toEqual(todoName); - expect(searchTodoResponse.data.searchTodos.items[0]._version).toEqual(todoVersion); -}); - -// Test for issue https://github.com/aws-amplify/amplify-cli/issues/5140 -test('searches with @key with integer field', async () => { - const comment = await GRAPHQL_CLIENT.query( - `mutation createComment($createCommentInput: CreateCommentInput!){ - createComment(input: $createCommentInput) { - id, - content, - version - } - }`, - { - createCommentInput: { - id: 1, - version: 1, - content: 'Content', - }, - }, - ); - expect(comment.data).toBeDefined(); - expect(comment.data.createComment).toEqual({ - id: '1', - content: 'Content', - version: 1, - }); - - // Wait for the Comment to sync to Elasticsearch - await cf.wait(10, () => Promise.resolve()); - let searchCommentResponse = await GRAPHQL_CLIENT.query( - `query searchComment { - searchComments { - items { - id, - version, - content - } - } - }`, - {}, - ); - expect(searchCommentResponse).toBeDefined(); - expect(searchCommentResponse.data).toEqual({ - searchComments: { - items: [ - { - id: '1', - version: 1, - content: 'Content', - }, - ], - }, - }); -}); - -type TodoInput = { - id?: string; - name: string; - createdAt?: string; - description?: string; - _version?: number; -}; - -async function createTodo(input: TodoInput) { - const createTodoMutation = ` - mutation ( - $input: CreateTodoInput! - ) { - createTodo(input: $input) { - id - name - _version - } - }`; - return await GRAPHQL_CLIENT.query(createTodoMutation, { input }); -} - -async function updateTodo(input: TodoInput) { - const updateTodoMutation = ` - mutation ( - $input: UpdateTodoInput! - ){ - updateTodo(input: $input) { - id - name - _version - } - }`; - return await GRAPHQL_CLIENT.query(updateTodoMutation, { input }); -} - -async function searchTodos() { - const searchTodosQuery = ` - query SearchTodos { - searchTodos { - items { - id - name - _version - } - } - }`; - return await GRAPHQL_CLIENT.query(searchTodosQuery, {}); -} - -function getCreatePostsMutation( - author: string, - title: string, - ups: number, - downs: number, - percentageUp: number, - isPublished: boolean, -): string { - return `mutation { - createPost(input: { - author: "${author}" - title: "${title}" - ups: ${ups} - downs: ${downs} - percentageUp: ${percentageUp} - isPublished: ${isPublished} - }) { ...FullPost } - }`; -} - -function createBookMutation() { - return `mutation CreateBook( $input: CreateBookInput!) { - createBook(input: $input) { - author - name - genre - } - } - `; -} - -function getCreateUsersMutation() { - return `mutation CreateUser($input: CreateUserInput!) { - createUser(input: $input) { - id - name - createdAt - userItems - } - }`; -} - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableWithAuthTests.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableWithAuthTests.e2e.test.ts deleted file mode 100644 index 0a497f57f7..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/SearchableWithAuthTests.e2e.test.ts +++ /dev/null @@ -1,608 +0,0 @@ -import * as fs from 'fs'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { SearchableModelTransformer } from 'graphql-elasticsearch-transformer'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as S3, CreateBucketRequest } from 'aws-sdk/clients/s3'; -import { default as CognitoClient } from 'aws-sdk/clients/cognitoidentityserviceprovider'; -import AWSAppSyncClient, { AUTH_TYPE } from 'aws-appsync'; -import { AWS } from '@aws-amplify/core'; -import { Auth } from 'aws-amplify'; -import gql from 'graphql-tag'; -import { default as moment } from 'moment'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { S3Client } from '../S3Client'; -import { - createUserPool, - createUserPoolClient, - addIAMRolesToCFNStack, - createGroup, - addUserToGroup, - configureAmplify, - signupUser, - authenticateUser, -} from '../cognitoUtils'; -import 'isomorphic-fetch'; - -// To overcome of the way of how AmplifyJS picks up currentUserCredentials -const anyAWS = AWS as any; -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -if (anyAWS && anyAWS.config && anyAWS.config.credentials) { - delete anyAWS.config.credentials; -} - -// to deal with bug in cognito-identity-js -(global as any).fetch = require('node-fetch'); - -import { resolveTestRegion } from '../testSetup'; - -const AWS_REGION = resolveTestRegion(); - -jest.setTimeout(9700000); - -const cf = new CloudFormationClient(AWS_REGION); -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `SearchableAuthTests-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `searchable-auth-tests-bucket-${BUILD_TIMESTAMP}`; -const LOCAL_BUILD_ROOT = '/tmp/searchable_auth_tests/'; -const DEPLOYMENT_ROOT_KEY = 'deployments'; -const AUTH_ROLE_NAME = `${STACK_NAME}-authRole`; -const UNAUTH_ROLE_NAME = `${STACK_NAME}-unauthRole`; -const IDENTITY_POOL_NAME = `SearchableAuthModelAuthTransformerTest_${BUILD_TIMESTAMP}_identity_pool`; -const USER_POOL_CLIENTWEB_NAME = `search_auth_${BUILD_TIMESTAMP}_clientweb`; -const USER_POOL_CLIENT_NAME = `search_auth_${BUILD_TIMESTAMP}_client`; - -let GRAPHQL_ENDPOINT = undefined; - -/** - * Client 1 is logged in and is a member of the Admin group. - */ -let GRAPHQL_CLIENT_1: AWSAppSyncClient = undefined; - -/** - * Client 2 is logged in and is a member of the Devs group. - */ -let GRAPHQL_CLIENT_2: AWSAppSyncClient = undefined; - -/** - * Client 3 is logged in and has no group memberships. - */ -let GRAPHQL_CLIENT_3: AWSAppSyncClient = undefined; - -/** - * Auth IAM Client - */ -let GRAPHQL_IAM_AUTH_CLIENT: AWSAppSyncClient = undefined; - -/** - * API Key Client - */ -let GRAPHQL_APIKEY_CLIENT: AWSAppSyncClient = undefined; - -let USER_POOL_ID = undefined; - -const USERNAME1 = 'user1@test.com'; -const USERNAME2 = 'user2@test.com'; -const USERNAME3 = 'user3@test.com'; -const TMP_PASSWORD = 'Password123!'; -const REAL_PASSWORD = 'Password1234!'; -const WRITER_GROUP_NAME = 'writer'; -const ADMIN_GROUP_NAME = 'admin'; - -const cognitoClient = new CognitoClient({ apiVersion: '2016-04-19', region: AWS_REGION }); -const customS3Client = new S3Client(AWS_REGION); -const awsS3Client = new S3({ region: AWS_REGION }); - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -async function createBucket(name: string) { - return new Promise((res, rej) => { - const params: CreateBucketRequest = { - Bucket: name, - }; - awsS3Client.createBucket(params, (err, data) => (err ? rej(err) : res(data))); - }); -} - -beforeAll(async () => { - // Create a stack for the post model with auth enabled. - if (!fs.existsSync(LOCAL_BUILD_ROOT)) { - fs.mkdirSync(LOCAL_BUILD_ROOT); - } - await createBucket(BUCKET_NAME); - const validSchema = ` - # Owners and Users in writer group - # can execute crud operations their owned records. - type Comment @model - @searchable - @auth(rules: [ - { allow: owner } - { allow: groups, groups: ["writer"]} - ]) { - id: ID! - content: String - } - # only users in the admin group are authorized to view entries in DynamicContent - type Todo @model - @searchable - @auth(rules: [ - { allow: groups, groupsField: "groups"} - ]) { - id: ID! - groups: String - content: String - } - # users with apikey perform crud operations on Post except for secret - # only users with auth role (iam) can view the secret - type Post @model - @searchable - @auth(rules: [ - { allow: public, provider: apiKey } - { allow: private, provider: iam } - ]) { - id: ID! - content: String - secret: String @auth(rules: [{ allow: private, provider: iam }]) - }`; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelConnectionTransformer(), - new SearchableModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'API_KEY', - apiKeyConfig: { - description: 'E2E Test API Key', - apiKeyExpirationDays: 300, - }, - }, - { - authenticationType: 'AWS_IAM', - }, - ], - }, - }), - ], - }); - const userPoolResponse = await createUserPool(cognitoClient, `UserPool${STACK_NAME}`); - USER_POOL_ID = userPoolResponse.UserPool.Id; - const userPoolClientResponse = await createUserPoolClient(cognitoClient, USER_POOL_ID, `UserPool${STACK_NAME}`); - const userPoolClientId = userPoolClientResponse.UserPoolClient.ClientId; - try { - // Clean the bucket - let out = transformer.transform(validSchema); - - out = addIAMRolesToCFNStack(out, { - AUTH_ROLE_NAME, - UNAUTH_ROLE_NAME, - IDENTITY_POOL_NAME, - USER_POOL_CLIENTWEB_NAME, - USER_POOL_CLIENT_NAME, - USER_POOL_ID, - }); - - const params = { - CreateAPIKey: '1', - AuthCognitoUserPoolId: USER_POOL_ID, - }; - - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - params, - LOCAL_BUILD_ROOT, - BUCKET_NAME, - DEPLOYMENT_ROOT_KEY, - BUILD_TIMESTAMP, - ); - // Wait for any propagation to avoid random errors - await cf.wait(120, () => Promise.resolve()); - - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - GRAPHQL_ENDPOINT = getApiEndpoint(finishedStack.Outputs); - - const apiKey = getApiKey(finishedStack.Outputs); - expect(apiKey).toBeTruthy(); - - const getIdentityPoolId = outputValueSelector('IdentityPoolId'); - const identityPoolId = getIdentityPoolId(finishedStack.Outputs); - expect(identityPoolId).toBeTruthy(); - - // Verify we have all the details - expect(GRAPHQL_ENDPOINT).toBeTruthy(); - expect(USER_POOL_ID).toBeTruthy(); - expect(userPoolClientId).toBeTruthy(); - - // Configure Amplify, create users, and sign in. - configureAmplify(USER_POOL_ID, userPoolClientId, identityPoolId); - - await signupUser(USER_POOL_ID, USERNAME1, TMP_PASSWORD); - await signupUser(USER_POOL_ID, USERNAME2, TMP_PASSWORD); - await signupUser(USER_POOL_ID, USERNAME3, TMP_PASSWORD); - await createGroup(USER_POOL_ID, WRITER_GROUP_NAME); - await createGroup(USER_POOL_ID, ADMIN_GROUP_NAME); - await addUserToGroup(WRITER_GROUP_NAME, USERNAME2, USER_POOL_ID); - await addUserToGroup(ADMIN_GROUP_NAME, USERNAME2, USER_POOL_ID); - - const authResAfterGroup: any = await authenticateUser(USERNAME1, TMP_PASSWORD, REAL_PASSWORD); - const idToken = authResAfterGroup.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_1 = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: AWS_REGION, - disableOffline: true, - offlineConfig: { - keyPrefix: 'userPools', - }, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: idToken, - }, - }); - - const authRes2AfterGroup: any = await authenticateUser(USERNAME2, TMP_PASSWORD, REAL_PASSWORD); - const idToken2 = authRes2AfterGroup.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_2 = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: AWS_REGION, - disableOffline: true, - offlineConfig: { - keyPrefix: 'userPools', - }, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: idToken2, - }, - }); - - const authRes3: any = await authenticateUser(USERNAME3, TMP_PASSWORD, REAL_PASSWORD); - const idToken3 = authRes3.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_3 = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: AWS_REGION, - disableOffline: true, - offlineConfig: { - keyPrefix: 'userPools', - }, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: idToken3, - }, - }); - - await Auth.signIn(USERNAME1, REAL_PASSWORD); - const authCredentials = await Auth.currentUserCredentials(); - GRAPHQL_IAM_AUTH_CLIENT = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: AWS_REGION, - disableOffline: true, - offlineConfig: { - keyPrefix: 'iam', - }, - auth: { - type: AUTH_TYPE.AWS_IAM, - credentials: Auth.essentialCredentials(authCredentials), - }, - }); - - GRAPHQL_APIKEY_CLIENT = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: AWS_REGION, - disableOffline: true, - offlineConfig: { - keyPrefix: 'apikey', - }, - auth: { - type: AUTH_TYPE.API_KEY, - apiKey: apiKey, - }, - }); - // create records for post, comment, and todo - await createRecords(); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf, { cognitoClient, userPoolId: USER_POOL_ID }); -}); - -/** - * Input types - * */ -type CreateCommentInput = { - id?: string | null; - content?: string | null; -}; - -type CreateTodoInput = { - id?: string | null; - groups?: string | null; - content?: string | null; -}; - -type CreatePostInput = { - id?: string | null; - content?: string | null; - secret?: string | null; -}; - -/** - * Tests - */ - -// cognito owner check -test('Comments as owner', async () => { - const ownerResponse: any = await GRAPHQL_CLIENT_1.query({ - query: gql` - query SearchComments { - searchComments { - items { - id - content - owner - } - nextToken - } - } - `, - }); - expect(ownerResponse.data.searchComments).toBeDefined(); - expect(ownerResponse.data.searchComments.items.length).toEqual(1); - expect(ownerResponse.data.searchComments.items[0].content).toEqual('ownerContent'); -}); - -// cognito static group check -test('Comments as user in writer group', async () => { - const writerResponse: any = await GRAPHQL_CLIENT_2.query({ - query: gql` - query SearchComments { - searchComments { - items { - id - content - owner - } - nextToken - } - } - `, - }); - expect(writerResponse.data.searchComments).toBeDefined(); - expect(writerResponse.data.searchComments.items.length).toEqual(4); - const writerItems = writerResponse.data.searchComments.items; - writerItems.forEach((writerItem: { id: string; content: string | null; owner: string | null }) => { - expect(['ownerContent', 'content1', 'content2', 'content3']).toContain(writerItem.content); - if (writerItem.content === 'ownerContent') { - expect(writerItem.owner).toEqual(USERNAME1); - } else { - expect(writerItem.owner).toEqual(USERNAME2); - } - }); -}); - -// cognito test as unauthorized user -test('Comments as user that is not an owner nor is in writer group', async () => { - const user3Response: any = await GRAPHQL_CLIENT_3.query({ - query: gql` - query SearchComments { - searchComments { - items { - id - content - owner - } - nextToken - } - } - `, - }); - expect(user3Response.data.searchComments).toBeDefined(); - expect(user3Response.data.searchComments.items.length).toEqual(0); - expect(user3Response.data.searchComments.nextToken).toBeNull(); -}); - -// cognito dynamic group check -test('Todo as user in the dynamic group admin', async () => { - const adminResponse: any = await GRAPHQL_CLIENT_2.query({ - query: gql` - query SearchTodos { - searchTodos { - items { - id - groups - content - } - nextToken - } - } - `, - }); - expect(adminResponse.data.searchTodos).toBeDefined(); - expect(adminResponse.data.searchTodos.items.length).toEqual(3); - const adminItems = adminResponse.data.searchTodos.items; - adminItems.forEach((adminItem: { id: string; content: string; groups: string }) => { - expect(['adminContent1', 'adminContent2', 'adminContent3']).toContain(adminItem.content); - expect(adminItem.groups).toEqual('admin'); - }); -}); - -// iam test -test('Post as authorized user', async () => { - const authUser: any = await GRAPHQL_IAM_AUTH_CLIENT.query({ - query: gql` - query SearchPosts { - searchPosts { - items { - id - content - secret - } - nextToken - } - } - `, - }); - expect(authUser.data.searchPosts).toBeDefined(); - expect(authUser.data.searchPosts.items.length).toEqual(4); - const authUserItems = authUser.data.searchPosts.items; - authUserItems.forEach((authUserItem: { id: string; content: string; secret: string }) => { - expect(['publicPost', 'post1', 'post2', 'post3']).toContain(authUserItem.content); - expect(['notViewableToPublic', 'post1secret', 'post2secret', 'post3secret']).toContain(authUserItem.secret); - }); -}); - -// test apikey 2nd scenario -test('searchPosts with apikey and secret removed', async () => { - const apiKeyResponse: any = await GRAPHQL_APIKEY_CLIENT.query({ - query: gql` - query SearchPosts { - searchPosts { - items { - id - content - } - nextToken - } - } - `, - }); - expect(apiKeyResponse.data.searchPosts).toBeDefined(); - const apiKeyResponseItems = apiKeyResponse.data.searchPosts.items; - apiKeyResponseItems.forEach((item: { id: string; content: string | null }) => { - expect(item.id).toBeDefined(); - if (item.content) { - expect(['publicPost', 'post1', 'post2', 'post3']).toContain(item.content); - } - }); -}); - -// test iam/apiKey schema with unauth user -test('post as an cognito user that is not allowed in this schema', async () => { - try { - await GRAPHQL_CLIENT_3.query({ - query: gql` - query SearchPosts { - searchPosts { - items { - id - content - secret - } - nextToken - } - } - `, - }); - } catch (err) { - expect(err.graphQLErrors[0].errorType).toEqual('Unauthorized'); - expect(err.graphQLErrors[0].message).toEqual('Not Authorized to access searchPosts on type Query'); - } -}); - -// mutations -async function createComment(client: AWSAppSyncClient, input: CreateCommentInput) { - const create = gql` - mutation CreateComment($input: CreateCommentInput!) { - createComment(input: $input) { - id - content - owner - } - } - `; - return await client.mutate({ mutation: create, variables: { input } }); -} - -async function createTodo(client: AWSAppSyncClient, input: CreateTodoInput) { - const create = gql` - mutation CreateTodo($input: CreateTodoInput!) { - createTodo(input: $input) { - id - groups - content - } - } - `; - return await client.mutate({ mutation: create, variables: { input } }); -} - -async function createPost(client: AWSAppSyncClient, input: CreatePostInput) { - const create = gql` - mutation CreatePost($input: CreatePostInput!) { - createPost(input: $input) { - id - content - } - } - `; - return await client.mutate({ mutation: create, variables: { input } }); -} - -async function createRecords() { - // create a comment as an owner not in the writer group - const ownerCreate = await createComment(GRAPHQL_CLIENT_1, { - content: 'ownerContent', - }); - // create comments as user 2 that is in the writer group - const createCommentList: CreateCommentInput[] = [{ content: 'content1' }, { content: 'content2' }, { content: 'content3' }]; - createCommentList.forEach(async (commentInput: CreateCommentInput) => { - await createComment(GRAPHQL_CLIENT_2, commentInput); - }); - // create todos as user in the admin group - const createTodoList: CreateTodoInput[] = [ - { groups: 'admin', content: 'adminContent1' }, - { groups: 'admin', content: 'adminContent2' }, - { groups: 'admin', content: 'adminContent3' }, - ]; - createTodoList.forEach(async (todoInput: CreateTodoInput) => { - await createTodo(GRAPHQL_CLIENT_2, todoInput); - }); - // create a post as a user with the apiKey - const apiKeyResponse = await createPost(GRAPHQL_APIKEY_CLIENT, { - content: 'publicPost', - secret: 'notViewableToPublic', - }); - // create posts as user that has auth role - const createPostList: CreatePostInput[] = [ - { content: 'post1', secret: 'post1secret' }, - { content: 'post2', secret: 'post2secret' }, - { content: 'post3', secret: 'post3secret' }, - ]; - createPostList.forEach(async (postInput: CreatePostInput) => { - await createPost(GRAPHQL_IAM_AUTH_CLIENT, postInput); - }); - // Waiting for the ES Cluster + Streaming Lambda infra to be setup - await cf.wait(120, () => Promise.resolve()); -} diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/SubscriptionsWithAuthTest.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/SubscriptionsWithAuthTest.e2e.test.ts deleted file mode 100644 index 19e0a05308..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/SubscriptionsWithAuthTest.e2e.test.ts +++ /dev/null @@ -1,1430 +0,0 @@ -import * as fs from 'fs'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as S3, CreateBucketRequest } from 'aws-sdk/clients/s3'; -import { default as CognitoClient } from 'aws-sdk/clients/cognitoidentityserviceprovider'; -import AWSAppSyncClient, { AUTH_TYPE } from 'aws-appsync'; -import { AWS } from '@aws-amplify/core'; -import { Auth, API } from 'aws-amplify'; -import gql from 'graphql-tag'; -import { GRAPHQL_AUTH_MODE } from '@aws-amplify/api'; -import * as Observable from 'zen-observable'; -import { default as moment } from 'moment'; -import { IAM as cfnIAM, Cognito as cfnCognito } from 'cloudform-types'; -import { S3Client } from '../S3Client'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { - createUserPool, - createUserPoolClient, - createGroup, - addUserToGroup, - configureAmplify, - signupUser, - authenticateUser, -} from '../cognitoUtils'; -import 'isomorphic-fetch'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { withTimeOut } from '../promiseWithTimeout'; - -import { resolveTestRegion } from '../testSetup'; - -// tslint:disable: no-use-before-declare - -// To overcome of the way of how AmplifyJS picks up currentUserCredentials -const anyAWS = AWS as any; -if (anyAWS && anyAWS.config && anyAWS.config.credentials) { - delete anyAWS.config.credentials; -} -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -// to deal with bug in cognito-identity-js -(global as any).fetch = require('node-fetch'); -// to deal with subscriptions in node env -(global as any).WebSocket = require('ws'); - -const AWS_REGION = resolveTestRegion(); - -// delay times -const SUBSCRIPTION_DELAY = 10000; -const PROPAGATION_DELAY = 5000; -const JEST_TIMEOUT = 2000000; -const SUBSCRIPTION_TIMEOUT = 10000; - -jest.setTimeout(JEST_TIMEOUT); - -const cf = new CloudFormationClient(AWS_REGION); -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `SubscriptionAuthTests-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `subscription-auth-tests-bucket-${BUILD_TIMESTAMP}`; -const LOCAL_BUILD_ROOT = '/tmp/subscription_auth_tests/'; -const DEPLOYMENT_ROOT_KEY = 'deployments'; -const AUTH_ROLE_NAME = `${STACK_NAME}-authRole`; -const UNAUTH_ROLE_NAME = `${STACK_NAME}-unauthRole`; -const IDENTITY_POOL_NAME = `SubscriptionAuthModelAuthTransformerTest_${BUILD_TIMESTAMP}_identity_pool`; -const USER_POOL_CLIENTWEB_NAME = `subs_auth_${BUILD_TIMESTAMP}_clientweb`; -const USER_POOL_CLIENT_NAME = `subs_auth_${BUILD_TIMESTAMP}_client`; - -let GRAPHQL_ENDPOINT = undefined; - -/** - * Client 1 is logged in and is a member of the Admin group. - */ -let GRAPHQL_CLIENT_1: AWSAppSyncClient = undefined; - -/** - * Client 2 is logged in and is a member of the Devs group. - */ -let GRAPHQL_CLIENT_2: AWSAppSyncClient = undefined; - -/** - * Client 3 is logged in and has no group memberships. - */ -let GRAPHQL_CLIENT_3: AWSAppSyncClient = undefined; - -/** - * Auth IAM Client - */ -let GRAPHQL_IAM_AUTH_CLIENT: AWSAppSyncClient = undefined; - -/** - * API Key Client - */ -let GRAPHQL_APIKEY_CLIENT: AWSAppSyncClient = undefined; - -let USER_POOL_ID = undefined; - -let API_KEY: string = undefined; - -const USERNAME1 = 'user1@test.com'; -const USERNAME2 = 'user2@test.com'; -const USERNAME3 = 'user3@test.com'; -const TMP_PASSWORD = 'Password123!'; -const REAL_PASSWORD = 'Password1234!'; - -const INSTRUCTOR_GROUP_NAME = 'Instructor'; -const MEMBER_GROUP_NAME = 'Member'; -const ADMIN_GROUP_NAME = 'Admin'; - -const cognitoClient = new CognitoClient({ apiVersion: '2016-04-19', region: AWS_REGION }); -const customS3Client = new S3Client(AWS_REGION); -const awsS3Client = new S3({ region: AWS_REGION }); - -// interface inputs -interface MemberInput { - id: string; - name?: string; - createdAt?: string; - updatedAt?: string; -} - -interface CreateStudentInput { - id?: string; - name?: string; - email?: string; - ssn?: string; -} - -interface UpdateStudentInput { - id: string; - name?: string; - email?: string; - ssn?: string; -} - -interface CreatePostInput { - id?: string; - title: string; - postOwner: string; -} - -interface CreateTodoInput { - id?: string; - name?: string; - description?: string; -} - -interface UpdateTodoInput { - id: string; - name?: string; - description?: string; -} - -interface DeleteTypeInput { - id: string; -} - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -async function createBucket(name: string) { - return new Promise((res, rej) => { - const params: CreateBucketRequest = { - Bucket: name, - }; - awsS3Client.createBucket(params, (err, data) => (err ? rej(err) : res(data))); - }); -} - -async function deleteBucket(name: string) { - return new Promise((res, rej) => { - const params: CreateBucketRequest = { - Bucket: name, - }; - awsS3Client.deleteBucket(params, (err, data) => (err ? rej(err) : res(data))); - }); -} -beforeEach(async () => { - try { - await Auth.signOut(); - } catch (ex) { - // don't need to fail tests on this error - } -}); -beforeAll(async () => { - // Create a stack for the post model with auth enabled. - if (!fs.existsSync(LOCAL_BUILD_ROOT)) { - fs.mkdirSync(LOCAL_BUILD_ROOT); - } - await createBucket(BUCKET_NAME); - const validSchema = ` - # Owners may update their owned records. - # Instructors may create Student records. - # Any authenticated user may view Student names & emails. - # Only Owners can see the ssn - - type Student @model - @auth(rules: [ - {allow: owner} - {allow: groups, groups: ["Instructor"]} - ]) { - id: String, - name: String, - email: AWSEmail, - ssn: String @auth(rules: [{allow: owner}]) - } - - type Member @model - @auth(rules: [ - { allow: groups, groups: ["Admin"] } - { allow: groups, groups: ["Member"], operations: [read] } - ]) { - id: ID - name: String - createdAt: AWSDateTime - updatedAt: AWSDateTime - } - - type Post @model - @auth(rules: [ - { allow: owner, ownerField: "postOwner" } - { allow: private, operations: [read], provider: iam } - ]) - { - id: ID! - title: String - postOwner: String - } - - type Todo @model @auth(rules: [ - { allow: public } - ]){ - id: ID! - name: String @auth(rules: [ - { allow: private, provider: iam } - ]) - description: String - }`; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'API_KEY', - apiKeyConfig: { - description: 'E2E Test API Key', - apiKeyExpirationDays: 300, - }, - }, - { - authenticationType: 'AWS_IAM', - }, - ], - }, - }), - ], - }); - const userPoolResponse = await createUserPool(cognitoClient, `UserPool${STACK_NAME}`); - USER_POOL_ID = userPoolResponse.UserPool.Id; - const userPoolClientResponse = await createUserPoolClient(cognitoClient, USER_POOL_ID, `UserPool${STACK_NAME}`); - const userPoolClientId = userPoolClientResponse.UserPoolClient.ClientId; - try { - // Clean the bucket - const out = transformer.transform(validSchema); - - const authRole = new cfnIAM.Role({ - RoleName: AUTH_ROLE_NAME, - AssumeRolePolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Sid: '', - Effect: 'Allow', - Principal: { - Federated: 'cognito-identity.amazonaws.com', - }, - Action: 'sts:AssumeRoleWithWebIdentity', - Condition: { - StringEquals: { - 'cognito-identity.amazonaws.com:aud': { Ref: 'IdentityPool' }, - }, - 'ForAnyValue:StringLike': { - 'cognito-identity.amazonaws.com:amr': 'authenticated', - }, - }, - }, - ], - }, - }); - - const unauthRole = new cfnIAM.Role({ - RoleName: UNAUTH_ROLE_NAME, - AssumeRolePolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Sid: '', - Effect: 'Allow', - Principal: { - Federated: 'cognito-identity.amazonaws.com', - }, - Action: 'sts:AssumeRoleWithWebIdentity', - Condition: { - StringEquals: { - 'cognito-identity.amazonaws.com:aud': { Ref: 'IdentityPool' }, - }, - 'ForAnyValue:StringLike': { - 'cognito-identity.amazonaws.com:amr': 'unauthenticated', - }, - }, - }, - ], - }, - Policies: [ - new cfnIAM.Role.Policy({ - PolicyName: 'appsync-unauthrole-policy', - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Action: ['appsync:GraphQL'], - Resource: [ - { - 'Fn::Join': [ - '', - [ - 'arn:aws:appsync:', - { Ref: 'AWS::Region' }, - ':', - { Ref: 'AWS::AccountId' }, - ':apis/', - { - 'Fn::GetAtt': ['GraphQLAPI', 'ApiId'], - }, - '/*', - ], - ], - }, - ], - }, - ], - }, - }), - ], - }); - - const identityPool = new cfnCognito.IdentityPool({ - IdentityPoolName: IDENTITY_POOL_NAME, - CognitoIdentityProviders: [ - { - ClientId: { - Ref: 'UserPoolClient', - }, - ProviderName: { - 'Fn::Sub': [ - 'cognito-idp.${region}.amazonaws.com/${client}', - { - region: { - Ref: 'AWS::Region', - }, - client: USER_POOL_ID, - }, - ], - }, - } as unknown, - { - ClientId: { - Ref: 'UserPoolClientWeb', - }, - ProviderName: { - 'Fn::Sub': [ - 'cognito-idp.${region}.amazonaws.com/${client}', - { - region: { - Ref: 'AWS::Region', - }, - client: USER_POOL_ID, - }, - ], - }, - } as unknown, - ], - AllowUnauthenticatedIdentities: true, - }); - - const identityPoolRoleMap = new cfnCognito.IdentityPoolRoleAttachment({ - IdentityPoolId: { Ref: 'IdentityPool' } as unknown as string, - Roles: { - unauthenticated: { 'Fn::GetAtt': ['UnauthRole', 'Arn'] }, - authenticated: { 'Fn::GetAtt': ['AuthRole', 'Arn'] }, - }, - }); - - const userPoolClientWeb = new cfnCognito.UserPoolClient({ - ClientName: USER_POOL_CLIENTWEB_NAME, - RefreshTokenValidity: 30, - UserPoolId: USER_POOL_ID, - }); - - const userPoolClient = new cfnCognito.UserPoolClient({ - ClientName: USER_POOL_CLIENT_NAME, - GenerateSecret: true, - RefreshTokenValidity: 30, - UserPoolId: USER_POOL_ID, - }); - - out.rootStack.Resources.IdentityPool = identityPool; - out.rootStack.Resources.IdentityPoolRoleMap = identityPoolRoleMap; - out.rootStack.Resources.UserPoolClientWeb = userPoolClientWeb; - out.rootStack.Resources.UserPoolClient = userPoolClient; - out.rootStack.Outputs.IdentityPoolId = { Value: { Ref: 'IdentityPool' } }; - out.rootStack.Outputs.IdentityPoolName = { Value: { 'Fn::GetAtt': ['IdentityPool', 'Name'] } }; - - out.rootStack.Resources.AuthRole = authRole; - out.rootStack.Outputs.AuthRoleArn = { Value: { 'Fn::GetAtt': ['AuthRole', 'Arn'] } }; - out.rootStack.Resources.UnauthRole = unauthRole; - out.rootStack.Outputs.UnauthRoleArn = { Value: { 'Fn::GetAtt': ['UnauthRole', 'Arn'] } }; - - // Since we're doing the policy here we've to remove the transformer generated artifacts from - // the generated stack. - const maxPolicyCount = 10; - for (let i = 0; i < maxPolicyCount; i++) { - const paddedIndex = `${i + 1}`.padStart(2, '0'); - const authResourceName = `${ResourceConstants.RESOURCES.AuthRolePolicy}${paddedIndex}`; - const unauthResourceName = `${ResourceConstants.RESOURCES.UnauthRolePolicy}${paddedIndex}`; - - if (out.rootStack.Resources[authResourceName]) { - delete out.rootStack.Resources[authResourceName]; - } - - if (out.rootStack.Resources[unauthResourceName]) { - delete out.rootStack.Resources[unauthResourceName]; - } - } - - delete out.rootStack.Parameters.authRoleName; - delete out.rootStack.Parameters.unauthRoleName; - - for (const key of Object.keys(out.rootStack.Resources)) { - if ( - out.rootStack.Resources[key].Properties && - out.rootStack.Resources[key].Properties.Parameters && - out.rootStack.Resources[key].Properties.Parameters.unauthRoleName - ) { - delete out.rootStack.Resources[key].Properties.Parameters.unauthRoleName; - } - - if ( - out.rootStack.Resources[key].Properties && - out.rootStack.Resources[key].Properties.Parameters && - out.rootStack.Resources[key].Properties.Parameters.authRoleName - ) { - delete out.rootStack.Resources[key].Properties.Parameters.authRoleName; - } - } - - for (const stackKey of Object.keys(out.stacks)) { - const stack = out.stacks[stackKey]; - - for (const key of Object.keys(stack.Resources)) { - if (stack.Parameters && stack.Parameters.unauthRoleName) { - delete stack.Parameters.unauthRoleName; - } - if (stack.Parameters && stack.Parameters.authRoleName) { - delete stack.Parameters.authRoleName; - } - if ( - stack.Resources[key].Properties && - stack.Resources[key].Properties.Parameters && - stack.Resources[key].Properties.Parameters.unauthRoleName - ) { - delete stack.Resources[key].Properties.Parameters.unauthRoleName; - } - if ( - stack.Resources[key].Properties && - stack.Resources[key].Properties.Parameters && - stack.Resources[key].Properties.Parameters.authRoleName - ) { - delete stack.Resources[key].Properties.Parameters.authRoleName; - } - } - } - - const params = { - CreateAPIKey: '1', - AuthCognitoUserPoolId: USER_POOL_ID, - }; - - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - params, - LOCAL_BUILD_ROOT, - BUCKET_NAME, - DEPLOYMENT_ROOT_KEY, - BUILD_TIMESTAMP, - ); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - GRAPHQL_ENDPOINT = getApiEndpoint(finishedStack.Outputs); - - const apiKey = getApiKey(finishedStack.Outputs); - API_KEY = apiKey; - expect(apiKey).toBeTruthy(); - - const getIdentityPoolId = outputValueSelector('IdentityPoolId'); - const identityPoolId = getIdentityPoolId(finishedStack.Outputs); - expect(identityPoolId).toBeTruthy(); - - // Verify we have all the details - expect(GRAPHQL_ENDPOINT).toBeTruthy(); - expect(USER_POOL_ID).toBeTruthy(); - expect(userPoolClientId).toBeTruthy(); - - // Configure Amplify, create users, and sign in. - configureAmplify(USER_POOL_ID, userPoolClientId, identityPoolId); - - await signupUser(USER_POOL_ID, USERNAME1, TMP_PASSWORD); - await signupUser(USER_POOL_ID, USERNAME2, TMP_PASSWORD); - await signupUser(USER_POOL_ID, USERNAME3, TMP_PASSWORD); - await createGroup(USER_POOL_ID, INSTRUCTOR_GROUP_NAME); - await createGroup(USER_POOL_ID, MEMBER_GROUP_NAME); - await createGroup(USER_POOL_ID, ADMIN_GROUP_NAME); - await addUserToGroup(ADMIN_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(MEMBER_GROUP_NAME, USERNAME2, USER_POOL_ID); - await addUserToGroup(INSTRUCTOR_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(INSTRUCTOR_GROUP_NAME, USERNAME2, USER_POOL_ID); - - const authResAfterGroup: any = await authenticateUser(USERNAME1, TMP_PASSWORD, REAL_PASSWORD); - const idToken = authResAfterGroup.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_1 = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: AWS_REGION, - disableOffline: true, - offlineConfig: { - keyPrefix: 'userPools', - }, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: idToken, - }, - }); - - const authRes2AfterGroup: any = await authenticateUser(USERNAME2, TMP_PASSWORD, REAL_PASSWORD); - const idToken2 = authRes2AfterGroup.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_2 = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: AWS_REGION, - disableOffline: true, - offlineConfig: { - keyPrefix: 'userPools', - }, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: idToken2, - }, - }); - - const authRes3: any = await authenticateUser(USERNAME3, TMP_PASSWORD, REAL_PASSWORD); - const idToken3 = authRes3.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_3 = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: AWS_REGION, - disableOffline: true, - offlineConfig: { - keyPrefix: 'userPools', - }, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: idToken3, - }, - }); - - await Auth.signIn(USERNAME1, REAL_PASSWORD); - const authCredentials = await Auth.currentUserCredentials(); - GRAPHQL_IAM_AUTH_CLIENT = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: AWS_REGION, - disableOffline: true, - offlineConfig: { - keyPrefix: 'iam', - }, - auth: { - type: AUTH_TYPE.AWS_IAM, - credentials: Auth.essentialCredentials(authCredentials), - }, - }); - - GRAPHQL_APIKEY_CLIENT = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: AWS_REGION, - disableOffline: true, - offlineConfig: { - keyPrefix: 'apikey', - }, - auth: { - type: AUTH_TYPE.API_KEY, - apiKey, - }, - }); - API.configure({ - aws_appsync_graphqlEndpoint: GRAPHQL_ENDPOINT, - aws_appsync_region: AWS_REGION, - aws_appsync_authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }); - - // Wait for any propagation to avoid random - // "The security token included in the request is invalid" errors - await new Promise((res) => setTimeout(res, PROPAGATION_DELAY)); - } catch (e) { - console.log(e); - - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf, { cognitoClient, userPoolId: USER_POOL_ID }); -}); - -/** - * Tests - */ - -// tests using cognito -test('that only authorized members are allowed to view subscriptions', async () => { - // subscribe to create students as user 2 - reconfigureAmplifyAPI('AMAZON_COGNITO_USER_POOLS'); - await Auth.signIn(USERNAME1, REAL_PASSWORD); - const observer = API.graphql({ - // @ts-ignore - query: gql` - subscription OnCreateStudent { - onCreateStudent { - id - name - email - ssn - owner - } - } - `, - authMode: GRAPHQL_AUTH_MODE.AMAZON_COGNITO_USER_POOLS, - }) as unknown as Observable; - let subscription: ZenObservable.Subscription; - const subscriptionPromise = new Promise((resolve, _) => { - subscription = observer.subscribe((event: any) => { - const student = event.value.data.onCreateStudent; - subscription.unsubscribe(); - expect(student.name).toEqual('student1'); - expect(student.email).toEqual('student1@domain.com'); - expect(student.ssn).toBeNull(); - resolve(undefined); - }); - }); - - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - - await createStudent(GRAPHQL_CLIENT_1, { - name: 'student1', - email: 'student1@domain.com', - ssn: 'AAA-01-SSSS', - }); - - return withTimeOut(subscriptionPromise, SUBSCRIPTION_TIMEOUT, 'OnCreateStudent Subscription timed out', () => { - subscription?.unsubscribe(); - }); -}); - -test('a subscription on update', async () => { - // subscribe to update students as user 2 - reconfigureAmplifyAPI('AMAZON_COGNITO_USER_POOLS'); - await Auth.signIn(USERNAME2, REAL_PASSWORD); - const observer = API.graphql({ - // @ts-ignore - query: gql` - subscription OnUpdateStudent { - onUpdateStudent { - id - name - email - ssn - owner - } - } - `, - authMode: GRAPHQL_AUTH_MODE.AMAZON_COGNITO_USER_POOLS, - }) as unknown as Observable; - let subscription: ZenObservable.Subscription; - const subscriptionPromise = new Promise((resolve, _) => { - subscription = observer.subscribe((event: any) => { - const student = event.value.data.onUpdateStudent; - subscription.unsubscribe(); - expect(student.id).toEqual(student3ID); - expect(student.name).toEqual('student3'); - expect(student.email).toEqual('emailChanged@domain.com'); - expect(student.ssn).toBeNull(); - resolve(undefined); - }); - }); - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - - const student3 = await createStudent(GRAPHQL_CLIENT_1, { - name: 'student3', - email: 'changeThisEmail@domain.com', - ssn: 'CCC-01-SNSN', - }); - expect(student3.data.createStudent).toBeDefined(); - const student3ID = student3.data.createStudent.id; - expect(student3.data.createStudent.name).toEqual('student3'); - expect(student3.data.createStudent.email).toEqual('changeThisEmail@domain.com'); - expect(student3.data.createStudent.ssn).toBeNull(); - - await updateStudent(GRAPHQL_CLIENT_1, { - id: student3ID, - email: 'emailChanged@domain.com', - }); - - return withTimeOut(subscriptionPromise, SUBSCRIPTION_TIMEOUT, 'OnUpdateStudent Subscription timed out', () => { - subscription?.unsubscribe(); - }); -}); - -test('a subscription on delete', async () => { - // subscribe to onDelete as user 2 - reconfigureAmplifyAPI('AMAZON_COGNITO_USER_POOLS'); - await Auth.signIn(USERNAME2, REAL_PASSWORD); - const observer = API.graphql({ - // @ts-ignore - query: gql` - subscription OnDeleteStudent { - onDeleteStudent { - id - name - email - ssn - owner - } - } - `, - authMode: GRAPHQL_AUTH_MODE.AMAZON_COGNITO_USER_POOLS, - }) as unknown as Observable; - let subscription: ZenObservable.Subscription; - const subscriptionPromise = new Promise((resolve, reject) => { - subscription = observer.subscribe({ - next: (event) => { - const student = event.value.data.onDeleteStudent; - subscription.unsubscribe(); - expect(student.id).toEqual(student4ID); - expect(student.name).toEqual('student4'); - expect(student.email).toEqual('plsDelete@domain.com'); - expect(student.ssn).toBeNull(); - resolve(undefined); - }, - error: (err) => { - reject(err); - }, - }); - }); - const student4 = await createStudent(GRAPHQL_CLIENT_1, { - name: 'student4', - email: 'plsDelete@domain.com', - ssn: 'DDD-02-SNSN', - }); - expect(student4).toBeDefined(); - const student4ID = student4.data.createStudent.id; - expect(student4.data.createStudent.email).toEqual('plsDelete@domain.com'); - expect(student4.data.createStudent.ssn).toBeNull(); - - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - - await deleteStudent(GRAPHQL_CLIENT_1, { id: student4ID }); - - return withTimeOut(subscriptionPromise, SUBSCRIPTION_TIMEOUT, 'OnDeleteStudent Subscription timed out', () => { - subscription?.unsubscribe(); - }); -}); - -test('that group is only allowed to listen to subscriptions and listen to onCreate', async () => { - const memberID = '001'; - const memberName = 'username00'; - // test that a user that only read can't mutate - reconfigureAmplifyAPI('AMAZON_COGNITO_USER_POOLS'); - await Auth.signIn(USERNAME2, REAL_PASSWORD); - try { - await createMember(GRAPHQL_CLIENT_2, { id: '001', name: 'notUser' }); - } catch (err) { - expect(err).toBeDefined(); - expect(err.graphQLErrors[0].errorType).toEqual('Unauthorized'); - } - - // though they should see when a new member is created - const observer = API.graphql({ - // @ts-ignore - query: gql` - subscription OnCreateMember { - onCreateMember { - id - name - createdAt - updatedAt - } - } - `, - authMode: GRAPHQL_AUTH_MODE.AMAZON_COGNITO_USER_POOLS, - }) as unknown as Observable; - let subscription: ZenObservable.Subscription; - const subscriptionPromise = new Promise((resolve, _) => { - subscription = observer.subscribe((event: any) => { - const member = event.value.data.onCreateMember; - subscription.unsubscribe(); - expect(member).toBeDefined(); - expect(member.id).toEqual(memberID); - expect(member.name).toEqual(memberName); - resolve(undefined); - }); - }); - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - // user that is authorized creates the update the mutation - const createMemberResponse = await createMember(GRAPHQL_CLIENT_1, { id: memberID, name: memberName }); - expect(createMemberResponse.data.createMember.id).toEqual(memberID); - expect(createMemberResponse.data.createMember.name).toEqual(memberName); - - return withTimeOut(subscriptionPromise, SUBSCRIPTION_TIMEOUT, 'OnCreateMember Subscription timed out', () => { - subscription?.unsubscribe(); - }); -}); - -test('authorized group is allowed to listen to onUpdate', async () => { - const memberID = '001update'; - const oldMemberName = 'oldUsername'; - const newMemberName = 'newUsername'; - reconfigureAmplifyAPI('AMAZON_COGNITO_USER_POOLS'); - await Auth.signIn(USERNAME2, REAL_PASSWORD); - - const observer = API.graphql({ - // @ts-ignore - query: gql` - subscription OnUpdateMember { - onUpdateMember { - id - name - createdAt - updatedAt - } - } - `, - authMode: GRAPHQL_AUTH_MODE.AMAZON_COGNITO_USER_POOLS, - }) as unknown as Observable; - let subscription: ZenObservable.Subscription; - - const subscriptionPromise = new Promise((resolve, reject) => { - subscription = observer.subscribe({ - next: (event) => { - const subResponse = event.value.data.onUpdateMember; - subscription.unsubscribe(); - expect(subResponse).toBeDefined(); - expect(subResponse.id).toEqual(memberID); - expect(subResponse.name).toEqual(newMemberName); - resolve(undefined); - }, - complete: () => {}, - error: (err) => { - reject(err); - }, - }); - }); - const createMemberResponse = await createMember(GRAPHQL_CLIENT_1, { id: memberID, name: oldMemberName }); - expect(createMemberResponse.data.createMember.id).toEqual(memberID); - expect(createMemberResponse.data.createMember.name).toEqual(oldMemberName); - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - // user that is authorized creates the update the mutation - const updateMemberResponse = await updateMember(GRAPHQL_CLIENT_1, { id: memberID, name: newMemberName }); - expect(updateMemberResponse.data.updateMember.id).toEqual(memberID); - expect(updateMemberResponse.data.updateMember.name).toEqual(newMemberName); - - return withTimeOut(subscriptionPromise, SUBSCRIPTION_TIMEOUT, 'OnUpdateMember Subscription timed out', () => { - subscription?.unsubscribe(); - }); -}); - -test('authorized group is allowed to listen to onDelete', async () => { - const memberID = '001delete'; - const memberName = 'newUsername'; - reconfigureAmplifyAPI('AMAZON_COGNITO_USER_POOLS'); - await Auth.signIn(USERNAME2, REAL_PASSWORD); - const observer = API.graphql({ - // @ts-ignore - query: gql` - subscription OnDeleteMember { - onDeleteMember { - id - name - createdAt - updatedAt - } - } - `, - authMode: GRAPHQL_AUTH_MODE.AMAZON_COGNITO_USER_POOLS, - }) as unknown as Observable; - let subscription: ZenObservable.Subscription; - - const subscriptionPromise = new Promise((resolve, reject) => { - subscription = observer.subscribe({ - next: (event) => { - subscription.unsubscribe(); - const subResponse = event.value.data.onDeleteMember; - subscription.unsubscribe(); - expect(subResponse).toBeDefined(); - expect(subResponse.id).toEqual(memberID); - expect(subResponse.name).toEqual(memberName); - resolve(undefined); - }, - error: (err) => { - reject(err); - }, - }); - }); - - const createMemberResponse = await createMember(GRAPHQL_CLIENT_1, { id: memberID, name: memberName }); - expect(createMemberResponse.data.createMember.id).toEqual(memberID); - expect(createMemberResponse.data.createMember.name).toEqual(memberName); - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - // user that is authorized creates the update the mutation - const deleteMemberResponse = await deleteMember(GRAPHQL_CLIENT_1, { id: memberID }); - expect(deleteMemberResponse.data.deleteMember.id).toEqual(memberID); - - return withTimeOut(subscriptionPromise, SUBSCRIPTION_TIMEOUT, 'OnDeleteMember Subscription timed out', () => { - subscription?.unsubscribe(); - }); -}); - -// ownerField Tests -test('subscription onCreatePost with ownerField', async () => { - reconfigureAmplifyAPI('AMAZON_COGNITO_USER_POOLS'); - await Auth.signIn(USERNAME1, REAL_PASSWORD); - const observer = API.graphql({ - // @ts-ignore - query: gql` - subscription OnCreatePost { - onCreatePost(postOwner: "${USERNAME1}") { - id - title - postOwner - } - }`, - authMode: GRAPHQL_AUTH_MODE.AMAZON_COGNITO_USER_POOLS, - }) as unknown as Observable; - let subscription: ZenObservable.Subscription; - const subscriptionPromise = new Promise((resolve, _) => { - subscription = observer.subscribe((event: any) => { - const post = event.value.data.onCreatePost; - subscription.unsubscribe(); - expect(post.title).toEqual('someTitle'); - expect(post.postOwner).toEqual(USERNAME1); - resolve(undefined); - }); - }); - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - - const createPostResponse = await createPost(GRAPHQL_CLIENT_1, { - title: 'someTitle', - postOwner: USERNAME1, - }); - expect(createPostResponse.data.createPost.title).toEqual('someTitle'); - expect(createPostResponse.data.createPost.postOwner).toEqual(USERNAME1); - - return withTimeOut(subscriptionPromise, SUBSCRIPTION_TIMEOUT, 'OnCreatePost Subscription timed out', () => { - subscription?.unsubscribe(); - }); -}); - -test('onCreatePost with incorrect owner argument should throw an error', async () => { - reconfigureAmplifyAPI('AMAZON_COGNITO_USER_POOLS'); - await Auth.signIn(USERNAME1, REAL_PASSWORD); - const failedObserver = API.graphql({ - // @ts-ignore - query: gql` - subscription OnCreatePost { - onCreatePost(postOwner: "${USERNAME2}") { - id - title - postOwner - } - } - `, - authMode: GRAPHQL_AUTH_MODE.AMAZON_COGNITO_USER_POOLS, - }) as unknown as Observable; - let subscription: ZenObservable.Subscription; - const subscriptionPromise = new Promise((resolve, reject) => { - subscription = failedObserver.subscribe( - (event) => { - subscription.unsubscribe(); - reject('Should throw unauthorized error.'); - }, - (err) => { - expect(err.error.errors[0].message).toEqual( - 'Connection failed: {"errors":[{"errorType":"Unauthorized","message":"Not Authorized to access onCreatePost on type Subscription"}]}', - ); - resolve(undefined); - }, - ); - }); - - return withTimeOut(subscriptionPromise, SUBSCRIPTION_TIMEOUT, 'OnCreatePost Subscription timed out', () => { - subscription?.unsubscribe(); - }); -}); - -// iam tests -test('that IAM can listen and read to onCreatePost', async () => { - const postID = 'subscriptionID'; - const postTitle = 'titleMadeByPostOwner'; - - reconfigureAmplifyAPI('AWS_IAM'); - await Auth.signIn(USERNAME1, REAL_PASSWORD); - const observer = API.graphql({ - // @ts-ignore - query: gql` - subscription OnCreatePost { - onCreatePost { - id - title - postOwner - } - } - `, - authMode: GRAPHQL_AUTH_MODE.AWS_IAM, - }) as unknown as Observable; - let subscription: ZenObservable.Subscription; - - const subscriptionPromise = new Promise((resolve, reject) => { - subscription = observer.subscribe( - (event: any) => { - const post = event.value.data.onCreatePost; - subscription.unsubscribe(); - expect(post).toBeDefined(); - expect(post.id).toEqual(postID); - expect(post.title).toEqual(postTitle); - expect(post.postOwner).toEqual(USERNAME1); - resolve(undefined); - }, - (err) => { - reject(err); - }, - ); - }); - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - - const createPostResponse = await createPost(GRAPHQL_CLIENT_1, { id: postID, title: postTitle, postOwner: USERNAME1 }); - expect(createPostResponse.data.createPost.id).toEqual(postID); - expect(createPostResponse.data.createPost.title).toEqual(postTitle); - expect(createPostResponse.data.createPost.postOwner).toEqual(USERNAME1); - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - await subscriptionPromise; -}); - -test('that subcsription with apiKey', async () => { - reconfigureAmplifyAPI('API_KEY', API_KEY); - await Auth.signIn(USERNAME1, REAL_PASSWORD); - const observer = API.graphql({ - // @ts-ignore - query: gql` - subscription OnCreateTodo { - onCreateTodo { - id - description - name - } - } - `, - authMode: GRAPHQL_AUTH_MODE.API_KEY, - }) as unknown as Observable; - let subscription: ZenObservable.Subscription; - - const subscriptionPromise = new Promise((resolve, _) => { - subscription = observer.subscribe((event: any) => { - const post = event.value.data.onCreateTodo; - subscription.unsubscribe(); - expect(post.description).toEqual('someDescription'); - expect(post.name).toBeNull(); - resolve(undefined); - }); - }); - - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - - const createTodoResponse = await createTodo(GRAPHQL_IAM_AUTH_CLIENT, { - description: 'someDescription', - name: 'todo1', - }); - expect(createTodoResponse.data.createTodo.description).toEqual('someDescription'); - expect(createTodoResponse.data.createTodo.name).toEqual(null); - - return withTimeOut(subscriptionPromise, SUBSCRIPTION_TIMEOUT, 'OnCreateTodo Subscription timed out', () => { - subscription?.unsubscribe(); - }); -}); - -test('that subscription with apiKey onUpdate', async () => { - reconfigureAmplifyAPI('API_KEY', API_KEY); - await Auth.signIn(USERNAME1, REAL_PASSWORD); - const observer = API.graphql({ - // @ts-ignore - query: gql` - subscription OnUpdateTodo { - onUpdateTodo { - id - description - name - } - } - `, - authMode: GRAPHQL_AUTH_MODE.API_KEY, - }) as unknown as Observable; - let subscription: ZenObservable.Subscription; - const subscriptionPromise = new Promise((resolve, reject) => { - subscription = observer.subscribe( - (event: any) => { - const todo = event.value.data.onUpdateTodo; - subscription.unsubscribe(); - expect(todo.id).toEqual(todo2ID); - expect(todo.description).toEqual('todo2newDesc'); - expect(todo.name).toBeNull(); - resolve(undefined); - }, - (err) => { - reject(undefined); - }, - ); - }); - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - - const todo2 = await createTodo(GRAPHQL_IAM_AUTH_CLIENT, { - description: 'updateTodoDesc', - name: 'todo2', - }); - expect(todo2.data.createTodo.id).toBeDefined(); - const todo2ID = todo2.data.createTodo.id; - expect(todo2.data.createTodo.description).toEqual('updateTodoDesc'); - expect(todo2.data.createTodo.name).toBeNull(); - - // update the description on todo - const updateResponse = await updateTodo(GRAPHQL_IAM_AUTH_CLIENT, { - id: todo2ID, - description: 'todo2newDesc', - }); - expect(updateResponse.data.updateTodo.id).toEqual(todo2ID); - expect(updateResponse.data.updateTodo.description).toEqual('todo2newDesc'); - - return withTimeOut(subscriptionPromise, SUBSCRIPTION_TIMEOUT, 'createTodo Subscription timed out', () => { - subscription?.unsubscribe(); - }); -}); - -test('that subscription with apiKey onDelete', async () => { - reconfigureAmplifyAPI('API_KEY', API_KEY); - await Auth.signIn(USERNAME1, REAL_PASSWORD); - const observer = API.graphql({ - // @ts-ignore - query: gql` - subscription OnDeleteTodo { - onDeleteTodo { - id - description - name - } - } - `, - authMode: GRAPHQL_AUTH_MODE.API_KEY, - }) as unknown as Observable; - let subscription: ZenObservable.Subscription; - const subscriptionPromise = new Promise((resolve, _) => { - subscription = observer.subscribe((event: any) => { - const todo = event.value.data.onDeleteTodo; - subscription.unsubscribe(); - expect(todo.id).toEqual(todo3ID); - expect(todo.description).toEqual('deleteTodoDesc'); - expect(todo.name).toBeNull(); - resolve(undefined); - }); - }); - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - - const todo3 = await createTodo(GRAPHQL_IAM_AUTH_CLIENT, { - description: 'deleteTodoDesc', - name: 'todo3', - }); - expect(todo3.data.createTodo.id).toBeDefined(); - const todo3ID = todo3.data.createTodo.id; - expect(todo3.data.createTodo.description).toEqual('deleteTodoDesc'); - expect(todo3.data.createTodo.name).toBeNull(); - - // delete todo3 - await deleteTodo(GRAPHQL_IAM_AUTH_CLIENT, { - id: todo3ID, - }); - - return withTimeOut(subscriptionPromise, SUBSCRIPTION_TIMEOUT, ' OnDelete Todo Subscription timed out', () => { - subscription?.unsubscribe(); - }); -}); - -test('subscriptions with variable syntax', async () => { - reconfigureAmplifyAPI('AMAZON_COGNITO_USER_POOLS'); - await Auth.signIn(USERNAME1, REAL_PASSWORD); - const observer = API.graphql({ - // @ts-ignore - query: gql` - subscription OnCreateStudent($owner: String) { - onCreateStudent(owner: $owner) { - id - name - email - ssn - owner - } - } - `, - variables: { - owner: USERNAME1, - }, - authMode: GRAPHQL_AUTH_MODE.AMAZON_COGNITO_USER_POOLS, - }) as unknown as Observable; - let subscription: ZenObservable.Subscription; - const subscriptionPromise = new Promise((resolve, _) => { - subscription = observer.subscribe((event: any) => { - const student = event.value.data.onCreateStudent; - subscription.unsubscribe(); - expect(student.name).toEqual('student_variable_1'); - expect(student.email).toEqual('student1@domain.com'); - expect(student.ssn).toBeNull(); - resolve(undefined); - }); - }); - - await new Promise((res) => setTimeout(res, SUBSCRIPTION_DELAY)); - - await createStudent(GRAPHQL_CLIENT_1, { - name: 'student_variable_1', - email: 'student1@domain.com', - ssn: 'AAA-01-SSSS', - }); - - return withTimeOut(subscriptionPromise, SUBSCRIPTION_TIMEOUT, 'OnCreateStudent Subscription timed out', () => { - subscription?.unsubscribe(); - }); -}); - -function reconfigureAmplifyAPI(appSyncAuthType: string, apiKey?: string) { - if (appSyncAuthType === 'API_KEY') { - API.configure({ - aws_appsync_graphqlEndpoint: GRAPHQL_ENDPOINT, - aws_appsync_region: AWS_REGION, - aws_appsync_authenticationType: appSyncAuthType, - aws_appsync_apiKey: apiKey, - }); - } else { - API.configure({ - aws_appsync_graphqlEndpoint: GRAPHQL_ENDPOINT, - aws_appsync_region: AWS_REGION, - aws_appsync_authenticationType: appSyncAuthType, - }); - } -} - -// mutations -async function createMember(client: AWSAppSyncClient, input: MemberInput) { - const request = gql` - mutation CreateMember($input: CreateMemberInput!) { - createMember(input: $input) { - id - name - createdAt - updatedAt - } - } - `; - return await client.mutate({ mutation: request, variables: { input } }); -} - -async function updateMember(client: AWSAppSyncClient, input: MemberInput) { - const request = gql` - mutation UpdateMember($input: UpdateMemberInput!) { - updateMember(input: $input) { - id - name - createdAt - updatedAt - } - } - `; - return await client.mutate({ mutation: request, variables: { input } }); -} - -async function deleteMember(client: AWSAppSyncClient, input: MemberInput) { - const request = gql` - mutation DeleteMember($input: DeleteMemberInput!) { - deleteMember(input: $input) { - id - name - createdAt - updatedAt - } - } - `; - return await client.mutate({ mutation: request, variables: { input } }); -} - -async function createStudent(client: AWSAppSyncClient, input: CreateStudentInput) { - const request = gql` - mutation CreateStudent($input: CreateStudentInput!) { - createStudent(input: $input) { - id - name - email - ssn - owner - } - } - `; - return await client.mutate({ mutation: request, variables: { input } }); -} - -async function updateStudent(client: AWSAppSyncClient, input: UpdateStudentInput) { - const request = gql` - mutation UpdateStudent($input: UpdateStudentInput!) { - updateStudent(input: $input) { - id - name - email - ssn - owner - } - } - `; - return await client.mutate({ mutation: request, variables: { input } }); -} - -async function deleteStudent(client: AWSAppSyncClient, input: DeleteTypeInput) { - const request = gql` - mutation DeleteStudent($input: DeleteStudentInput!) { - deleteStudent(input: $input) { - id - name - email - ssn - owner - } - } - `; - return await client.mutate({ mutation: request, variables: { input } }); -} - -async function createPost(client: AWSAppSyncClient, input: CreatePostInput) { - const request = gql` - mutation CreatePost($input: CreatePostInput!) { - createPost(input: $input) { - id - title - postOwner - } - } - `; - return await client.mutate({ mutation: request, variables: { input } }); -} - -async function createTodo(client: AWSAppSyncClient, input: CreateTodoInput) { - const request = gql` - mutation CreateTodo($input: CreateTodoInput!) { - createTodo(input: $input) { - id - description - name - } - } - `; - return await client.mutate({ mutation: request, variables: { input } }); -} - -async function updateTodo(client: AWSAppSyncClient, input: UpdateTodoInput) { - const request = gql` - mutation UpdateTodo($input: UpdateTodoInput!) { - updateTodo(input: $input) { - id - description - name - } - } - `; - return await client.mutate({ mutation: request, variables: { input } }); -} - -async function deleteTodo(client: AWSAppSyncClient, input: DeleteTypeInput) { - const request = gql` - mutation DeleteTodo($input: DeleteTodoInput!) { - deleteTodo(input: $input) { - id - description - name - } - } - `; - return await client.mutate({ mutation: request, variables: { input } }); -} diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/TestComplexStackMappingsLocal.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/TestComplexStackMappingsLocal.e2e.test.ts deleted file mode 100644 index e41f9a296f..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/TestComplexStackMappingsLocal.e2e.test.ts +++ /dev/null @@ -1,189 +0,0 @@ -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { SearchableModelTransformer } from 'graphql-elasticsearch-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { HttpTransformer } from 'graphql-http-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { FunctionTransformer } from 'graphql-function-transformer'; -import { expectExactKeys } from '../testUtil'; - -const userType = ` -type User @model @auth(rules: [{ allow: owner }]) { - id: ID! - name: String - posts: [UserPost] @connection(name: "UserPostsUser") - profpic: String @http(url: "https://www.profpic.org/this/is/a/fake/url") -}`; -const userPostType = ` -type UserPost @model { - id: ID! - user: User @connection(name: "UserPostsUser") - post: Post @connection(name: "UserPostsPost") -} -`; -const postType = ` -type Post @model @searchable { - id: ID! - name: String - authors: [UserPost] @connection(name: "UserPostsPost") - score: Int @function(name: "scorefunc") -} -`; -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -/** - * We test this schema with the same set of rules multiple times. This protects against a subtle bug in the stack mapping - * that caused the order to impact the stack that a resource got mapped to. - */ -test('that every resource exists in the correct stack given a complex schema with overlapping names.', () => { - const schema = [userType, userPostType, postType].join('\n'); - transpileAndCheck(schema); -}); - -test('that every resource exists in the correct stack given a complex schema with overlapping names. Rotation 1.', () => { - const schema = [userPostType, postType, userType].join('\n'); - transpileAndCheck(schema); -}); - -test('that every resource exists in the correct stack given a complex schema with overlapping names. Rotation 2.', () => { - const schema = [postType, userType, userPostType].join('\n'); - transpileAndCheck(schema); -}); - -function transpileAndCheck(schema: string) { - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new HttpTransformer(), - new ModelConnectionTransformer(), - new FunctionTransformer(), - new SearchableModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - - const out = transformer.transform(schema); - - // Check root - expectExactKeys( - out.rootStack.Resources, - new Set([ - 'GraphQLAPI', - 'GraphQLAPIKey', - 'GraphQLSchema', - 'User', - 'UserPost', - 'Post', - 'ConnectionStack', - 'SearchableStack', - 'FunctionDirectiveStack', - 'HttpStack', - 'NoneDataSource', - ]), - ); - expectExactKeys(out.rootStack.Outputs, new Set(['GraphQLAPIIdOutput', 'GraphQLAPIEndpointOutput', 'GraphQLAPIKeyOutput'])); - - // Check User - expectExactKeys( - out.stacks.User.Resources, - new Set([ - 'UserTable', - 'UserIAMRole', - 'UserDataSource', - 'GetUserResolver', - 'ListUserResolver', - 'CreateUserResolver', - 'UpdateUserResolver', - 'DeleteUserResolver', - 'SubscriptiononCreateUserResolver', - 'SubscriptiononDeleteUserResolver', - 'SubscriptiononUpdateUserResolver', - ]), - ); - expectExactKeys(out.stacks.User.Outputs, new Set(['GetAttUserTableStreamArn', 'GetAttUserDataSourceName', 'GetAttUserTableName'])); - - // Check UserPost - expectExactKeys( - out.stacks.UserPost.Resources, - new Set([ - 'UserPostTable', - 'UserPostIAMRole', - 'UserPostDataSource', - 'GetUserPostResolver', - 'ListUserPostResolver', - 'CreateUserPostResolver', - 'UpdateUserPostResolver', - 'DeleteUserPostResolver', - ]), - ); - expectExactKeys( - out.stacks.UserPost.Outputs, - new Set(['GetAttUserPostTableStreamArn', 'GetAttUserPostDataSourceName', 'GetAttUserPostTableName']), - ); - - // Check Post - expectExactKeys( - out.stacks.Post.Resources, - new Set([ - 'PostTable', - 'PostIAMRole', - 'PostDataSource', - 'GetPostResolver', - 'ListPostResolver', - 'CreatePostResolver', - 'UpdatePostResolver', - 'DeletePostResolver', - ]), - ); - expectExactKeys(out.stacks.Post.Outputs, new Set(['GetAttPostTableStreamArn', 'GetAttPostDataSourceName', 'GetAttPostTableName'])); - - // Check SearchableStack - expectExactKeys( - out.stacks.SearchableStack.Resources, - new Set([ - 'ElasticSearchAccessIAMRole', - 'ElasticSearchDataSource', - 'ElasticSearchDomain', - 'ElasticSearchStreamingLambdaIAMRole', - 'ElasticSearchStreamingLambdaFunction', - 'SearchablePostLambdaMapping', - 'SearchPostResolver', - ]), - ); - expectExactKeys(out.stacks.SearchableStack.Outputs, new Set(['ElasticsearchDomainArn', 'ElasticsearchDomainEndpoint'])); - - // Check connections - expectExactKeys( - out.stacks.ConnectionStack.Resources, - new Set(['UserpostsResolver', 'UserPostuserResolver', 'UserPostpostResolver', 'PostauthorsResolver']), - ); - expectExactKeys(out.stacks.ConnectionStack.Outputs, new Set([])); - - // Check function stack - expectExactKeys( - out.stacks.FunctionDirectiveStack.Resources, - new Set(['ScorefuncLambdaDataSourceRole', 'ScorefuncLambdaDataSource', 'InvokeScorefuncLambdaDataSource', 'PostscoreResolver']), - ); - expectExactKeys(out.stacks.ConnectionStack.Outputs, new Set([])); - - // Check http stack - expectExactKeys(out.stacks.HttpStack.Resources, new Set(['httpswwwprofpicorgDataSource', 'UserprofpicResolver'])); - expectExactKeys(out.stacks.HttpStack.Outputs, new Set([])); -} diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/VersionedModelTransformer.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/VersionedModelTransformer.e2e.test.ts deleted file mode 100644 index fb1265d8d3..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/VersionedModelTransformer.e2e.test.ts +++ /dev/null @@ -1,265 +0,0 @@ -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { VersionedModelTransformer } from 'graphql-versioned-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as moment } from 'moment'; -import { default as S3 } from 'aws-sdk/clients/s3'; -import { GraphQLClient } from '../GraphQLClient'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { S3Client } from '../S3Client'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `VersionedTest-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `versioned-test-bucket-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/model_transform_versioned_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; - -let GRAPHQL_CLIENT = undefined; - -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -beforeAll(async () => { - const validSchema = ` - type Post @model @versioned { - id: ID! - title: String! - version: Int! - createdAt: AWSDateTime - updatedAt: AWSDateTime - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new VersionedModelTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - try { - await awsS3Client.createBucket({ Bucket: BUCKET_NAME }).promise(); - } catch (e) { - console.error(`Failed to create bucket: ${e}`); - } - - try { - const out = transformer.transform(validSchema); - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { CreateAPIKey: '1' }, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - expect(finishedStack).toBeDefined(); - - // Arbitrary wait to make sure everything is ready. - // await cf.wait(10, () => Promise.resolve()) - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - const endpoint = getApiEndpoint(finishedStack.Outputs); - const apiKey = getApiKey(finishedStack.Outputs); - expect(apiKey).toBeDefined(); - expect(endpoint).toBeDefined(); - GRAPHQL_CLIENT = new GraphQLClient(endpoint, { 'x-api-key': apiKey }); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf); -}); - -/** - * Test queries below - */ -test('createPost mutation', async () => { - const response = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Hello, World!" }) { - id - title - createdAt - updatedAt - version - } - }`, - {}, - ); - expect(response.data.createPost.id).toBeDefined(); - expect(response.data.createPost.title).toEqual('Hello, World!'); - expect(response.data.createPost.createdAt).toBeDefined(); - expect(response.data.createPost.updatedAt).toBeDefined(); - expect(response.data.createPost.version).toEqual(1); -}); - -test('updatePost mutation', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Update" }) { - id - title - createdAt - updatedAt - version - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Update'); - expect(createResponse.data.createPost.version).toEqual(1); - const updateResponse = await GRAPHQL_CLIENT.query( - `mutation { - updatePost(input: { - id: "${createResponse.data.createPost.id}", - title: "Bye, World!", - expectedVersion: ${createResponse.data.createPost.version} - }) { - id - title - version - } - }`, - {}, - ); - expect(updateResponse.data.updatePost.title).toEqual('Bye, World!'); - expect(updateResponse.data.updatePost.version).toEqual(2); -}); - -test('failed updatePost mutation with wrong version', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Update" }) { - id - title - createdAt - updatedAt - version - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Update'); - expect(createResponse.data.createPost.version).toEqual(1); - const updateResponse = await GRAPHQL_CLIENT.query( - `mutation { - updatePost(input: { - id: "${createResponse.data.createPost.id}", - title: "Bye, World!", - expectedVersion: 3 - }) { - id - title - version - } - }`, - {}, - ); - expect(updateResponse.errors.length).toEqual(1); - expect((updateResponse.errors[0] as any).data).toBeNull(); - expect((updateResponse.errors[0] as any).errorType).toEqual('DynamoDB:ConditionalCheckFailedException'); -}); - -test('deletePost mutation', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Delete" }) { - id - title - version - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Delete'); - expect(createResponse.data.createPost.version).toBeDefined(); - const deleteResponse = await GRAPHQL_CLIENT.query( - `mutation { - deletePost(input: { id: "${createResponse.data.createPost.id}", expectedVersion: ${createResponse.data.createPost.version} }) { - id - title - version - } - }`, - {}, - ); - expect(deleteResponse.data.deletePost.title).toEqual('Test Delete'); - expect(deleteResponse.data.deletePost.version).toEqual(createResponse.data.createPost.version); -}); - -test('deletePost mutation with wrong version', async () => { - const createResponse = await GRAPHQL_CLIENT.query( - `mutation { - createPost(input: { title: "Test Delete" }) { - id - title - version - createdAt - updatedAt - } - }`, - {}, - ); - expect(createResponse.data.createPost.id).toBeDefined(); - expect(createResponse.data.createPost.title).toEqual('Test Delete'); - expect(createResponse.data.createPost.version).toBeDefined(); - const deleteResponse = await GRAPHQL_CLIENT.query( - `mutation { - deletePost(input: { id: "${createResponse.data.createPost.id}", expectedVersion: 3 }) { - id - title - version - } - }`, - {}, - ); - expect(deleteResponse.errors.length).toEqual(1); - expect((deleteResponse.errors[0] as any).data).toBeNull(); - expect((deleteResponse.errors[0] as any).errorType).toEqual('DynamoDB:ConditionalCheckFailedException'); -}); diff --git a/yarn.lock b/yarn.lock index 2048dccdef..97072f6d0b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15,43 +15,6 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@ardatan/aggregate-error@0.0.6": - version "0.0.6" - resolved "https://registry.yarnpkg.com/@ardatan/aggregate-error/-/aggregate-error-0.0.6.tgz#fe6924771ea40fc98dc7a7045c2e872dc8527609" - integrity sha512-vyrkEHG1jrukmzTPtyWB4NLPauUw5bQeg4uhn8f+1SSynmrOcyvlb1GKQjjgoBzElLdfXCRYX8UnBlhklOHYRQ== - dependencies: - tslib "~2.0.1" - -"@ardatan/relay-compiler@12.0.0": - version "12.0.0" - resolved "https://registry.yarnpkg.com/@ardatan/relay-compiler/-/relay-compiler-12.0.0.tgz#2e4cca43088e807adc63450e8cab037020e91106" - integrity sha512-9anThAaj1dQr6IGmzBMcfzOQKTa5artjuPmw8NYK/fiGEMjADbSguBY2FMDykt+QhilR3wc9VA/3yVju7JHg7Q== - dependencies: - "@babel/core" "^7.14.0" - "@babel/generator" "^7.14.0" - "@babel/parser" "^7.14.0" - "@babel/runtime" "^7.0.0" - "@babel/traverse" "^7.14.0" - "@babel/types" "^7.0.0" - babel-preset-fbjs "^3.4.0" - chalk "^4.0.0" - fb-watchman "^2.0.0" - fbjs "^3.0.0" - glob "^7.1.1" - immutable "~3.7.6" - invariant "^2.2.4" - nullthrows "^1.1.1" - relay-runtime "12.0.0" - signedsource "^1.0.0" - yargs "^15.3.1" - -"@ardatan/sync-fetch@^0.0.1": - version "0.0.1" - resolved "https://registry.yarnpkg.com/@ardatan/sync-fetch/-/sync-fetch-0.0.1.tgz#3385d3feedceb60a896518a1db857ec1e945348f" - integrity sha512-xhlTqH0m31mnsG0tIP4ETgfSB6gXDaYYsUWTrlUV93fFQPI9dd8hE0Ot6MHLCtqgB32hwJAC3YZMWlXZw7AleA== - dependencies: - node-fetch "^2.6.1" - "@aws-amplify/amplify-app@^5.0.35": version "5.0.35" resolved "https://registry.npmjs.org/@aws-amplify/amplify-app/-/amplify-app-5.0.35.tgz#c3c6f33b1e2ac594f1b49635e7a6aef9425d4980" @@ -73,78 +36,6 @@ xcode "^2.1.0" yargs "^15.1.0" -"@aws-amplify/amplify-appsync-simulator@^2.16.4": - version "2.16.4" - resolved "https://registry.npmjs.org/@aws-amplify/amplify-appsync-simulator/-/amplify-appsync-simulator-2.16.4.tgz#372be8358e847c43fc27f15e12c5aed07df1cd58" - integrity sha512-CFPIlCiNfOxJRoo35yS16kAgH9hdR8/HJp2sE3EyuNuyRAZKcN9vytACKDwQ7MyTkja1HZnfXCu4i46oRi/70g== - dependencies: - "@aws-amplify/amplify-cli-core" "4.3.9" - "@aws-amplify/amplify-prompts" "2.8.6" - "@graphql-tools/schema" "^8.3.1" - "@graphql-tools/utils" "^8.5.1" - amplify-velocity-template "1.4.14" - aws-sdk "^2.1464.0" - chalk "^4.1.1" - cors "^2.8.5" - dataloader "^2.0.0" - express "^4.17.3" - get-port "^5.1.1" - graphql "^15.5.0" - graphql-iso-date "^3.6.1" - graphql-subscriptions "^1.1.0" - ip "^1.1.9" - js-string-escape "^1.0.1" - jwt-decode "^2.2.0" - libphonenumber-js "1.9.47" - lodash "^4.17.21" - moment "^2.24.0" - moment-jdateformatparser "^1.2.1" - moment-timezone "0.5.35" - promise-toolbox "^0.20.0" - slash "^3.0.0" - ulid "^2.3.0" - uuid "^8.3.2" - ws "^8.5.0" - -"@aws-amplify/amplify-category-custom@3.1.23": - version "3.1.23" - resolved "https://registry.npmjs.org/@aws-amplify/amplify-category-custom/-/amplify-category-custom-3.1.23.tgz#2f651897288c7c8770838d4a46cca71763410931" - integrity sha512-VHb+1/tHRFB2z7KhRyUKWySftIzWTEKw+ub3ULdUJ0vLYgRnG6gCj2LOh0mRf4+Ka/suocUlxXnOalJwBhYexQ== - dependencies: - "@aws-amplify/amplify-cli-core" "4.3.9" - "@aws-amplify/amplify-prompts" "2.8.6" - aws-cdk-lib "~2.129.0" - execa "^5.1.1" - fs-extra "^8.1.0" - glob "^7.2.0" - ora "^4.0.3" - uuid "^8.3.2" - -"@aws-amplify/amplify-category-function@^5.7.9": - version "5.7.9" - resolved "https://registry.npmjs.org/@aws-amplify/amplify-category-function/-/amplify-category-function-5.7.9.tgz#b9aa00f109e6d127d3402a5e557a78de986f9606" - integrity sha512-YDIe7BWCTzoTAWZ30g+6pIvxOofUhVU4955p6LiFGf0R7Z57O0kT1D3ZaLctDVSW3aaUgycnY5PJ8qVfRPfgaw== - dependencies: - "@aws-amplify/amplify-cli-core" "4.3.9" - "@aws-amplify/amplify-environment-parameters" "1.9.14" - "@aws-amplify/amplify-function-plugin-interface" "1.12.1" - "@aws-amplify/amplify-prompts" "2.8.6" - archiver "^5.3.0" - aws-sdk "^2.1464.0" - chalk "^4.1.1" - cloudform-types "^4.2.0" - enquirer "^2.3.6" - folder-hash "^4.0.2" - fs-extra "^8.1.0" - globby "^11.0.3" - graphql-transformer-core "^8.2.11" - inquirer "^7.3.3" - inquirer-datepicker "^2.0.0" - jstreemap "^1.28.2" - lodash "^4.17.21" - promise-sequential "^1.1.1" - uuid "^8.3.2" - "@aws-amplify/amplify-cli-core@4.3.9", "@aws-amplify/amplify-cli-core@^4.3.9": version "4.3.9" resolved "https://registry.npmjs.org/@aws-amplify/amplify-cli-core/-/amplify-cli-core-4.3.9.tgz#48feec280b22695dce144407beb7372713b1bb1a" @@ -195,15 +86,6 @@ resolved "https://registry.npmjs.org/@aws-amplify/amplify-cli-shared-interfaces/-/amplify-cli-shared-interfaces-1.2.5.tgz#59657a41c5674009293bef924f9140c853dfaf16" integrity sha512-dmg5x5Llk3FBLXh8hXdxhb2fVyoNZi7gb8y7mSraI2UwhmyfgWzmF924yrGbbVQXvRfWY1070OR1SKSqahtEpQ== -"@aws-amplify/amplify-environment-parameters@1.9.14": - version "1.9.14" - resolved "https://registry.npmjs.org/@aws-amplify/amplify-environment-parameters/-/amplify-environment-parameters-1.9.14.tgz#e32fb27927be88dd8eae1a9e74c049ce2036a070" - integrity sha512-mGQW0Fpys7/Srn8CMlsE873iTy8q51hRnG/O4AzCoCXiCju/Ab2b4w5LMzlR+QJKyaZTVKGp2/lptRJ3uoEYgA== - dependencies: - "@aws-amplify/amplify-cli-core" "4.3.9" - ajv "^6.12.6" - lodash "^4.17.21" - "@aws-amplify/amplify-frontend-android@3.5.8": version "3.5.8" resolved "https://registry.npmjs.org/@aws-amplify/amplify-frontend-android/-/amplify-frontend-android-3.5.8.tgz#8fb393f2bd59dcfa13cf0484f25757cd5af59b83" @@ -262,58 +144,6 @@ chalk "^4.1.1" enquirer "^2.3.6" -"@aws-amplify/amplify-provider-awscloudformation@^8.10.11": - version "8.10.11" - resolved "https://registry.npmjs.org/@aws-amplify/amplify-provider-awscloudformation/-/amplify-provider-awscloudformation-8.10.11.tgz#617b92b39eac0537e3c2d700163fd3b4a7bdb393" - integrity sha512-m6O0h9smyTtXOZcRUZE9cSLTimsUWJ/2s+CMky/Knrvf9w1mW2JVbeZYha8aeV+kz25Q0AEGgKt8vstLr6a8AQ== - dependencies: - "@aws-amplify/amplify-category-custom" "3.1.23" - "@aws-amplify/amplify-cli-core" "4.3.9" - "@aws-amplify/amplify-cli-logger" "1.3.8" - "@aws-amplify/amplify-environment-parameters" "1.9.14" - "@aws-amplify/amplify-prompts" "2.8.6" - "@aws-amplify/amplify-util-import" "2.8.3" - "@aws-amplify/cli-extensibility-helper" "3.0.33" - "@aws-amplify/graphql-transformer-core" "^2.9.0" - "@aws-amplify/graphql-transformer-interfaces" "^3.9.0" - amplify-codegen "^4.9.3" - archiver "^5.3.0" - aws-cdk-lib "~2.129.0" - aws-sdk "^2.1464.0" - bottleneck "2.19.5" - chalk "^4.1.1" - cloudform-types "^4.2.0" - columnify "^1.5.4" - constructs "^10.0.5" - cors "^2.8.5" - deep-diff "^1.0.2" - folder-hash "^4.0.2" - fs-extra "^8.1.0" - glob "^7.2.0" - graphql "^15.5.0" - graphql-transformer-core "^8.2.11" - ignore "^5.2.0" - ini "^1.3.5" - inquirer "^7.3.3" - is-wsl "^2.2.0" - jose "^4.15.5" - lodash "^4.17.21" - lodash.throttle "^4.1.1" - netmask "^2.0.2" - node-fetch "^2.6.7" - ora "^4.0.3" - promise-sequential "^1.1.1" - proxy-agent "^6.3.0" - rimraf "^3.0.0" - xstate "^4.14.0" - -"@aws-amplify/amplify-util-import@2.8.3": - version "2.8.3" - resolved "https://registry.npmjs.org/@aws-amplify/amplify-util-import/-/amplify-util-import-2.8.3.tgz#4f0e00ebdf263e4bfdb8d08756260d4e453d76ca" - integrity sha512-kLoqsTSmGJT8sO8ejbebQk63Ea52/S0LHRzarrLzjQ2LvSZiVJx2lG6Q9Z+/YlsM0Mq6QGCplKTq9AMO3LDYpg== - dependencies: - aws-sdk "^2.1464.0" - "@aws-amplify/analytics@5.2.31": version "5.2.31" resolved "https://registry.yarnpkg.com/@aws-amplify/analytics/-/analytics-5.2.31.tgz#8a8a786110c880a8d5de15353f884ccf1552c600" @@ -359,22 +189,6 @@ "@aws-amplify/api-graphql" "2.3.28" "@aws-amplify/api-rest" "2.0.64" -"@aws-amplify/appsync-modelgen-plugin@2.12.2": - version "2.12.2" - resolved "https://registry.npmjs.org/@aws-amplify/appsync-modelgen-plugin/-/appsync-modelgen-plugin-2.12.2.tgz#1c6f684726e602d4c3442e58274eddda01761ae8" - integrity sha512-934QqusQaZpj11NM8xf84C4sgCnW1TINL1IgBpQzk9Zq4MVPuGZK1SO/fsSiriqBtGoMcpHSmMVZ94t+bXwDBg== - dependencies: - "@graphql-codegen/plugin-helpers" "^1.18.8" - "@graphql-codegen/visitor-plugin-common" "^1.22.0" - "@graphql-tools/utils" "^6.0.18" - chalk "^3.0.0" - change-case "^4.1.1" - graphql-transformer-common "^4.25.1" - lower-case-first "^2.0.1" - pluralize "^8.0.0" - strip-indent "^3.0.0" - ts-dedent "^1.1.0" - "@aws-amplify/auth-construct-alpha@^0.5.6": version "0.5.6" resolved "https://registry.npmjs.org/@aws-amplify/auth-construct-alpha/-/auth-construct-alpha-0.5.6.tgz#880fa06668ae74ebd3c93f4b85b58eab7b8d266d" @@ -428,15 +242,6 @@ dependencies: "@aws-amplify/core" "4.7.15" -"@aws-amplify/cli-extensibility-helper@3.0.33": - version "3.0.33" - resolved "https://registry.npmjs.org/@aws-amplify/cli-extensibility-helper/-/cli-extensibility-helper-3.0.33.tgz#7e1f15e09b04fb0abb73b8aeb7d19911f7b5bae7" - integrity sha512-vLut/3LBNEBZo5/s3ql+ZAW4glPTJfsPFeDvUCh089kW11tCaM43P0fKuDLPpxuVL2j8/WyldHpgsnOjZS0/9A== - dependencies: - "@aws-amplify/amplify-category-custom" "3.1.23" - "@aws-amplify/amplify-cli-core" "4.3.9" - aws-cdk-lib "~2.129.0" - "@aws-amplify/core@4.7.15": version "4.7.15" resolved "https://registry.yarnpkg.com/@aws-amplify/core/-/core-4.7.15.tgz#b19c65c0ea8b2b52f53e15343a374bf2751c261d" @@ -487,49 +292,17 @@ "@turf/boolean-clockwise" "6.5.0" camelcase-keys "6.2.2" -"@aws-amplify/graphql-docs-generator@4.2.1": - version "4.2.1" - resolved "https://registry.npmjs.org/@aws-amplify/graphql-docs-generator/-/graphql-docs-generator-4.2.1.tgz#1069b43f3a796ece7d6ac30f66f75a5103cf3d96" - integrity sha512-ReBlY5//mWOmO0FL2ndswB9ku+vpg/JTY9Wwemjm/ibyoLHU1ojtGkPBkKH0CzbpOkIuEkIBLIg9EZ2yca/6oA== +"@aws-amplify/graphql-transformer-migrator@2.2.27": + version "2.2.27" + resolved "https://registry.npmjs.org/@aws-amplify/graphql-transformer-migrator/-/graphql-transformer-migrator-2.2.27.tgz#7ddc98a1036b1364fdbe3c5360b63ee429bf1fec" + integrity sha512-4rzeSMcx0f5MWNEKP2x17uIQl9IZlAEZyGrMYC9t41FerKNv09Arp38jcZD2XhzINlu7MNkOVWb4veTCoqMptg== dependencies: - graphql "^15.5.0" - handlebars "4.7.7" - yargs "^15.1.0" - -"@aws-amplify/graphql-generator@0.4.3": - version "0.4.3" - resolved "https://registry.npmjs.org/@aws-amplify/graphql-generator/-/graphql-generator-0.4.3.tgz#1d14a3c1d7a5178369cd4dd351d093003403cd6c" - integrity sha512-21cbUm7n1f0Ox4UeXNkmcikWgE4ws9vdZqySGTGpERoC5OHPfSsu5KFQ/+V4XePUcEI5ofE+6R7xVH1BEaeUCA== - dependencies: - "@aws-amplify/appsync-modelgen-plugin" "2.12.2" - "@aws-amplify/graphql-directives" "^1.0.1" - "@aws-amplify/graphql-docs-generator" "4.2.1" - "@aws-amplify/graphql-types-generator" "3.6.0" - "@graphql-codegen/core" "^2.6.6" - "@graphql-tools/apollo-engine-loader" "^8.0.0" - graphql "^15.5.0" - prettier "^1.19.1" - -"@aws-amplify/graphql-types-generator@3.6.0": - version "3.6.0" - resolved "https://registry.npmjs.org/@aws-amplify/graphql-types-generator/-/graphql-types-generator-3.6.0.tgz#a104eee0492744e96dff662d1e0cd694f4ccc8d6" - integrity sha512-yjPXJ2dYZwtGvwwcEQ5RDNlwTsd/hUfD2Dgguo999Gu3mQjz7nV4l7CXD/Oxo/QzwtU/4rmTX69yadBpR+he3A== - dependencies: - "@babel/generator" "7.0.0-beta.4" - "@babel/types" "7.0.0-beta.4" - babel-generator "^6.26.1" - babel-types "^6.26.0" - change-case "^4.1.1" - common-tags "^1.8.0" - core-js "^3.6.4" + "@aws-amplify/graphql-transformer-core" "2.9.3" fs-extra "^8.1.0" - globby "^11.1.0" + glob "^10.3.0" graphql "^15.5.0" - inflected "^2.0.4" - prettier "^1.19.1" - rimraf "^3.0.0" - source-map-support "^0.5.16" - yargs "^15.1.0" + graphql-transformer-common "4.31.1" + lodash "^4.17.21" "@aws-amplify/interactions@4.1.12": version "4.1.12" @@ -641,11 +414,6 @@ resolved "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v6/-/asset-node-proxy-agent-v6-2.0.3.tgz#9b5d213b5ce5ad4461f6a4720195ff8de72e6523" integrity sha512-twhuEG+JPOYCYPx/xy5uH2+VUsIEhPTzDY0F1KuB+ocjWWB/KEDiOVL19nHvbPCB6fhWnkykXEMJ4HHcKvjtvg== -"@aws-cdk/aws-apigatewayv2-alpha@~2.114.1-alpha.0": - version "2.114.1-alpha.0" - resolved "https://registry.npmjs.org/@aws-cdk/aws-apigatewayv2-alpha/-/aws-apigatewayv2-alpha-2.114.1-alpha.0.tgz#831f9c448f6e5d4244d312f85ac73a2a434201d7" - integrity sha512-+urpw7rGrtdGvnHQlDXVfpI3TmQJpjuT9jTOeuuG5dNDczLJrUokBvQdj6H6KsngdmBC07WfWU+yL2MBp71ozA== - "@aws-cdk/aws-cognito-identitypool-alpha@2.129.0-alpha.0": version "2.129.0-alpha.0" resolved "https://registry.npmjs.org/@aws-cdk/aws-cognito-identitypool-alpha/-/aws-cognito-identitypool-alpha-2.129.0-alpha.0.tgz#fce287c962f3ad93100dea5f4df3c5452d027fa8" @@ -4602,12 +4370,12 @@ "@babel/highlight" "^7.22.13" chalk "^2.4.2" -"@babel/compat-data@^7.20.5", "@babel/compat-data@^7.22.9": +"@babel/compat-data@^7.22.9": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.20.tgz#8df6e96661209623f1975d66c35ffca66f3306d0" integrity sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw== -"@babel/core@^7.1.0", "@babel/core@^7.10.5", "@babel/core@^7.12.3", "@babel/core@^7.14.0", "@babel/core@^7.7.5": +"@babel/core@^7.1.0", "@babel/core@^7.10.5", "@babel/core@^7.12.3", "@babel/core@^7.7.5": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.0.tgz#f8259ae0e52a123eb40f552551e647b506a94d83" integrity sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ== @@ -4649,17 +4417,6 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@7.0.0-beta.4": - version "7.0.0-beta.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.4.tgz#99606c425fc6614e6386f9330efb48370f200fc3" - integrity sha512-aLpZzf79oGT1bxnsadapfUWErDTcxVKrhvR5F8G27JFgH37+/ATrODMJ0/1D2CgQ/WStDX5B5znnWRv0NzW2JQ== - dependencies: - "@babel/types" "7.0.0-beta.4" - jsesc "^2.5.1" - lodash "^4.2.0" - source-map "^0.5.0" - trim-right "^1.0.1" - "@babel/generator@7.18.2": version "7.18.2" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.2.tgz#33873d6f89b21efe2da63fe554460f3df1c5880d" @@ -4669,7 +4426,7 @@ "@jridgewell/gen-mapping" "^0.3.0" jsesc "^2.5.1" -"@babel/generator@^7.14.0", "@babel/generator@^7.23.0": +"@babel/generator@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420" integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g== @@ -4696,7 +4453,7 @@ dependencies: "@babel/types" "^7.22.5" -"@babel/helper-compilation-targets@^7.20.7", "@babel/helper-compilation-targets@^7.22.15", "@babel/helper-compilation-targets@^7.22.5": +"@babel/helper-compilation-targets@^7.22.15": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52" integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw== @@ -4707,7 +4464,7 @@ lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-create-class-features-plugin@^7.10.5", "@babel/helper-create-class-features-plugin@^7.18.6": +"@babel/helper-create-class-features-plugin@^7.10.5": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz#97a61b385e57fe458496fad19f8e63b63c867de4" integrity sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg== @@ -4774,12 +4531,12 @@ dependencies: "@babel/types" "^7.22.5" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0": +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== -"@babel/helper-replace-supers@^7.22.5", "@babel/helper-replace-supers@^7.22.9": +"@babel/helper-replace-supers@^7.22.9": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz#e37d367123ca98fe455a9887734ed2e16eb7a793" integrity sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw== @@ -4856,7 +4613,7 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.4.tgz#6774231779dd700e0af29f6ad8d479582d7ce5ef" integrity sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow== -"@babel/parser@^7.1.0", "@babel/parser@^7.14.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.23.0", "@babel/parser@^7.7.0": +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.23.0", "@babel/parser@^7.7.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== @@ -4866,14 +4623,6 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.3.tgz#0ce0be31a4ca4f1884b5786057cadcb6c3be58f9" integrity sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw== -"@babel/plugin-proposal-class-properties@^7.0.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" - integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-proposal-numeric-separator@^7.10.4": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75" @@ -4882,17 +4631,6 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.0.0": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz#aa662940ef425779c75534a5c41e9d936edc390a" - integrity sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg== - dependencies: - "@babel/compat-data" "^7.20.5" - "@babel/helper-compilation-targets" "^7.20.7" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.20.7" - "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" @@ -4907,20 +4645,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.0.0", "@babel/plugin-syntax-class-properties@^7.8.3": +"@babel/plugin-syntax-class-properties@^7.8.3": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-syntax-flow@^7.0.0", "@babel/plugin-syntax-flow@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.22.5.tgz#163b820b9e7696ce134df3ee716d9c0c98035859" - integrity sha512-9RdCl0i+q0QExayk2nOS7853w08yLucnnPML6EN9S8fgMPVtdLDCdx/cOQ/i44Lb9UeQX9A35yaqBBOMMZxPxQ== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" @@ -4935,13 +4666,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz#a6b68e84fb76e759fc3b93e901876ffabbe1d918" - integrity sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" @@ -4963,7 +4687,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": +"@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== @@ -4998,95 +4722,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-arrow-functions@^7.0.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz#e5ba566d0c58a5b2ba2a8b795450641950b71958" - integrity sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - -"@babel/plugin-transform-block-scoped-functions@^7.0.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz#27978075bfaeb9fa586d3cb63a3d30c1de580024" - integrity sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - -"@babel/plugin-transform-block-scoping@^7.0.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.0.tgz#8744d02c6c264d82e1a4bc5d2d501fd8aff6f022" - integrity sha512-cOsrbmIOXmf+5YbL99/S49Y3j46k/T16b9ml8bm9lP6N9US5iQ2yBK7gpui1pg0V/WMcXdkfKbTb7HXq9u+v4g== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - -"@babel/plugin-transform-classes@^7.0.0": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.15.tgz#aaf4753aee262a232bbc95451b4bdf9599c65a0b" - integrity sha512-VbbC3PGjBdE0wAWDdHM9G8Gm977pnYI0XpqMd6LrKISj8/DJXEsWqgRuTYaNE9Bv0JGhTZUzHDlMk18IpOuoqw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-compilation-targets" "^7.22.15" - "@babel/helper-environment-visitor" "^7.22.5" - "@babel/helper-function-name" "^7.22.5" - "@babel/helper-optimise-call-expression" "^7.22.5" - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/helper-replace-supers" "^7.22.9" - "@babel/helper-split-export-declaration" "^7.22.6" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.0.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz#cd1e994bf9f316bd1c2dafcd02063ec261bb3869" - integrity sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/template" "^7.22.5" - -"@babel/plugin-transform-destructuring@^7.0.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.0.tgz#6447aa686be48b32eaf65a73e0e2c0bd010a266c" - integrity sha512-vaMdgNXFkYrB+8lbgniSYWHsgqK5gjaMNcc84bMIOMRLH0L9AqYq3hwMdvnyqj1OPqea8UtjPEuS/DCenah1wg== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - -"@babel/plugin-transform-flow-strip-types@^7.0.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.22.5.tgz#0bb17110c7bf5b35a60754b2f00c58302381dee2" - integrity sha512-tujNbZdxdG0/54g/oua8ISToaXTFBf8EnSb5PgQSciIXWOWKX3S4+JR7ZE9ol8FZwf9kxitzkGQ+QWeov/mCiA== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/plugin-syntax-flow" "^7.22.5" - -"@babel/plugin-transform-for-of@^7.0.0": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.15.tgz#f64b4ccc3a4f131a996388fae7680b472b306b29" - integrity sha512-me6VGeHsx30+xh9fbDLLPi0J1HzmeIIyenoOQHuw2D4m2SAU3NrspX5XxJLBpqn5yrLzrlw2Iy3RA//Bx27iOA== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - -"@babel/plugin-transform-function-name@^7.0.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz#935189af68b01898e0d6d99658db6b164205c143" - integrity sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg== - dependencies: - "@babel/helper-compilation-targets" "^7.22.5" - "@babel/helper-function-name" "^7.22.5" - "@babel/helper-plugin-utils" "^7.22.5" - -"@babel/plugin-transform-literals@^7.0.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz#e9341f4b5a167952576e23db8d435849b1dd7920" - integrity sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - -"@babel/plugin-transform-member-expression-literals@^7.0.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz#4fcc9050eded981a468347dd374539ed3e058def" - integrity sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/plugin-transform-modules-commonjs@7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz#66667c3eeda1ebf7896d41f1f16b17105a2fbca0" @@ -5097,77 +4732,6 @@ "@babel/helper-simple-access" "^7.10.4" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-commonjs@^7.0.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.0.tgz#b3dba4757133b2762c00f4f94590cf6d52602481" - integrity sha512-32Xzss14/UVc7k9g775yMIvkVK8xwKE0DPdP5JTapr3+Z9w4tzeOuLNY6BXDQR6BdnzIlXnCGAzsk/ICHBLVWQ== - dependencies: - "@babel/helper-module-transforms" "^7.23.0" - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/helper-simple-access" "^7.22.5" - -"@babel/plugin-transform-object-super@^7.0.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz#794a8d2fcb5d0835af722173c1a9d704f44e218c" - integrity sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/helper-replace-supers" "^7.22.5" - -"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.20.7": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz#719ca82a01d177af358df64a514d64c2e3edb114" - integrity sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - -"@babel/plugin-transform-property-literals@^7.0.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz#b5ddabd73a4f7f26cd0e20f5db48290b88732766" - integrity sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - -"@babel/plugin-transform-react-display-name@^7.0.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.22.5.tgz#3c4326f9fce31c7968d6cb9debcaf32d9e279a2b" - integrity sha512-PVk3WPYudRF5z4GKMEYUrLjPl38fJSKNaEOkFuoprioowGuWN6w2RKznuFNSlJx7pzzXXStPUnNSOEO0jL5EVw== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - -"@babel/plugin-transform-react-jsx@^7.0.0": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.15.tgz#7e6266d88705d7c49f11c98db8b9464531289cd6" - integrity sha512-oKckg2eZFa8771O/5vi7XeTvmM6+O9cxZu+kanTU7tD4sin5nO/G8jGJhq8Hvt2Z0kUoEDRayuZLaUlYl8QuGA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-module-imports" "^7.22.15" - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/plugin-syntax-jsx" "^7.22.5" - "@babel/types" "^7.22.15" - -"@babel/plugin-transform-shorthand-properties@^7.0.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz#6e277654be82b5559fc4b9f58088507c24f0c624" - integrity sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - -"@babel/plugin-transform-spread@^7.0.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz#6487fd29f229c95e284ba6c98d65eafb893fea6b" - integrity sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" - -"@babel/plugin-transform-template-literals@^7.0.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz#8f38cf291e5f7a8e60e9f733193f0bcc10909bff" - integrity sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/plugin-transform-typescript@7.10.5": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.10.5.tgz#edf353944e979f40d8ff9fe4e9975d0a465037c5" @@ -5177,14 +4741,14 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-typescript" "^7.10.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.9.6": +"@babel/runtime@^7.20.7", "@babel/runtime@^7.9.6": version "7.23.1" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.1.tgz#72741dc4d413338a91dcb044a86f3c0bc402646d" integrity sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g== dependencies: regenerator-runtime "^0.14.0" -"@babel/template@^7.22.15", "@babel/template@^7.22.5", "@babel/template@^7.3.3": +"@babel/template@^7.22.15", "@babel/template@^7.3.3": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== @@ -5193,7 +4757,7 @@ "@babel/parser" "^7.22.15" "@babel/types" "^7.22.15" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.14.0", "@babel/traverse@^7.23.0", "@babel/traverse@^7.23.2", "@babel/traverse@^7.7.0": +"@babel/traverse@^7.1.0", "@babel/traverse@^7.23.0", "@babel/traverse@^7.23.2", "@babel/traverse@^7.7.0": version "7.23.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.3.tgz#26ee5f252e725aa7aca3474aa5b324eaf7908b5b" integrity sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ== @@ -5209,15 +4773,6 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@7.0.0-beta.4": - version "7.0.0-beta.4" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.4.tgz#988cc7683c448d7710e7d80bd88558183a102349" - integrity sha512-yLvBW5TTAgJwURAUAdZa1vrFTkwXXvk0Kw48LYvgxpyT/IaV8W4OIhxdVztAt5ruDQ/OFUwHpzWqk6TN3EfmWA== - dependencies: - esutils "^2.0.2" - lodash "^4.2.0" - to-fast-properties "^2.0.0" - "@babel/types@7.19.0": version "7.19.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.19.0.tgz#75f21d73d73dc0351f3368d28db73465f4814600" @@ -5536,221 +5091,6 @@ resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== -"@graphql-codegen/core@2.6.6": - version "2.6.6" - resolved "https://registry.yarnpkg.com/@graphql-codegen/core/-/core-2.6.6.tgz#e6ea99682230c5bbcf28cb247672da7f17e78578" - integrity sha512-gU2FUxoLGw2GfcPWfBVXuiN3aDODbZ6Z9I+IGxa2u1Rzxlacw4TMmcwr4/IjC6mkiYJEKTvdVspHaby+brhuAg== - dependencies: - "@graphql-codegen/plugin-helpers" "^2.7.2" - "@graphql-tools/schema" "^9.0.0" - "@graphql-tools/utils" "^9.1.1" - tslib "~2.4.0" - -"@graphql-codegen/core@^2.6.6": - version "2.6.8" - resolved "https://registry.yarnpkg.com/@graphql-codegen/core/-/core-2.6.8.tgz#00c4011e3619ddbc6af5e41b2f254d6f6759556e" - integrity sha512-JKllNIipPrheRgl+/Hm/xuWMw9++xNQ12XJR/OHHgFopOg4zmN3TdlRSyYcv/K90hCFkkIwhlHFUQTfKrm8rxQ== - dependencies: - "@graphql-codegen/plugin-helpers" "^3.1.1" - "@graphql-tools/schema" "^9.0.0" - "@graphql-tools/utils" "^9.1.1" - tslib "~2.4.0" - -"@graphql-codegen/plugin-helpers@^1.18.8": - version "1.18.8" - resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-1.18.8.tgz#39aac745b9e22e28c781cc07cf74836896a3a905" - integrity sha512-mb4I9j9lMGqvGggYuZ0CV+Hme08nar68xkpPbAVotg/ZBmlhZIok/HqW2BcMQi7Rj+Il5HQMeQ1wQ1M7sv/TlQ== - dependencies: - "@graphql-tools/utils" "^7.9.1" - common-tags "1.8.0" - import-from "4.0.0" - lodash "~4.17.0" - tslib "~2.3.0" - -"@graphql-codegen/plugin-helpers@^2.7.2": - version "2.7.2" - resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-2.7.2.tgz#6544f739d725441c826a8af6a49519f588ff9bed" - integrity sha512-kln2AZ12uii6U59OQXdjLk5nOlh1pHis1R98cDZGFnfaiAbX9V3fxcZ1MMJkB7qFUymTALzyjZoXXdyVmPMfRg== - dependencies: - "@graphql-tools/utils" "^8.8.0" - change-case-all "1.0.14" - common-tags "1.8.2" - import-from "4.0.0" - lodash "~4.17.0" - tslib "~2.4.0" - -"@graphql-codegen/plugin-helpers@^3.1.1": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-3.1.2.tgz#69a2e91178f478ea6849846ade0a59a844d34389" - integrity sha512-emOQiHyIliVOIjKVKdsI5MXj312zmRDwmHpyUTZMjfpvxq/UVAHUJIVdVf+lnjjrI+LXBTgMlTWTgHQfmICxjg== - dependencies: - "@graphql-tools/utils" "^9.0.0" - change-case-all "1.0.15" - common-tags "1.8.2" - import-from "4.0.0" - lodash "~4.17.0" - tslib "~2.4.0" - -"@graphql-codegen/visitor-plugin-common@^1.22.0": - version "1.22.0" - resolved "https://registry.yarnpkg.com/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-1.22.0.tgz#75fc8b580143bccbec411eb92d5fef715ed22e42" - integrity sha512-2afJGb6d8iuZl9KizYsexPwraEKO1lAvt5eVHNM5Xew4vwz/AUHeqDR2uOeQgVV+27EzjjzSDd47IEdH0dLC2w== - dependencies: - "@graphql-codegen/plugin-helpers" "^1.18.8" - "@graphql-tools/optimize" "^1.0.1" - "@graphql-tools/relay-operation-optimizer" "^6.3.0" - array.prototype.flatmap "^1.2.4" - auto-bind "~4.0.0" - change-case-all "1.0.14" - dependency-graph "^0.11.0" - graphql-tag "^2.11.0" - parse-filepath "^1.0.2" - tslib "~2.3.0" - -"@graphql-tools/apollo-engine-loader@^8.0.0": - version "8.0.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-8.0.0.tgz#ac1f351cbe41508411784f25757f5557b0f27489" - integrity sha512-axQTbN5+Yxs1rJ6cWQBOfw3AEeC+fvIuZSfJLPLLvFJLj4pUm9fhxey/g6oQZAAQJqKPfw+tLDUQvnfvRK8Kmg== - dependencies: - "@ardatan/sync-fetch" "^0.0.1" - "@graphql-tools/utils" "^10.0.0" - "@whatwg-node/fetch" "^0.9.0" - tslib "^2.4.0" - -"@graphql-tools/merge@8.3.1": - version "8.3.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.3.1.tgz#06121942ad28982a14635dbc87b5d488a041d722" - integrity sha512-BMm99mqdNZbEYeTPK3it9r9S6rsZsQKtlqJsSBknAclXq2pGEfOxjcIZi+kBSkHZKPKCRrYDd5vY0+rUmIHVLg== - dependencies: - "@graphql-tools/utils" "8.9.0" - tslib "^2.4.0" - -"@graphql-tools/merge@^6.0.18": - version "6.2.17" - resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-6.2.17.tgz#4dedf87d8435a5e1091d7cc8d4f371ed1e029f1f" - integrity sha512-G5YrOew39fZf16VIrc49q3c8dBqQDD0ax5LYPiNja00xsXDi0T9zsEWVt06ApjtSdSF6HDddlu5S12QjeN8Tow== - dependencies: - "@graphql-tools/schema" "^8.0.2" - "@graphql-tools/utils" "8.0.2" - tslib "~2.3.0" - -"@graphql-tools/merge@^8.4.1": - version "8.4.2" - resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.4.2.tgz#95778bbe26b635e8d2f60ce9856b388f11fe8288" - integrity sha512-XbrHAaj8yDuINph+sAfuq3QCZ/tKblrTLOpirK0+CAgNlZUCHs0Fa+xtMUURgwCVThLle1AF7svJCxFizygLsw== - dependencies: - "@graphql-tools/utils" "^9.2.1" - tslib "^2.4.0" - -"@graphql-tools/optimize@^1.0.1": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/optimize/-/optimize-1.4.0.tgz#20d6a9efa185ef8fc4af4fd409963e0907c6e112" - integrity sha512-dJs/2XvZp+wgHH8T5J2TqptT9/6uVzIYvA6uFACha+ufvdMBedkfR4b4GbT8jAKLRARiqRTxy3dctnwkTM2tdw== - dependencies: - tslib "^2.4.0" - -"@graphql-tools/relay-operation-optimizer@^6.3.0": - version "6.5.18" - resolved "https://registry.yarnpkg.com/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-6.5.18.tgz#a1b74a8e0a5d0c795b8a4d19629b654cf66aa5ab" - integrity sha512-mc5VPyTeV+LwiM+DNvoDQfPqwQYhPV/cl5jOBjTgSniyaq8/86aODfMkrE2OduhQ5E00hqrkuL2Fdrgk0w1QJg== - dependencies: - "@ardatan/relay-compiler" "12.0.0" - "@graphql-tools/utils" "^9.2.1" - tslib "^2.4.0" - -"@graphql-tools/schema@^8.0.2", "@graphql-tools/schema@^8.3.1": - version "8.5.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-8.5.1.tgz#c2f2ff1448380919a330312399c9471db2580b58" - integrity sha512-0Esilsh0P/qYcB5DKQpiKeQs/jevzIadNTaT0jeWklPMwNbT7yMX4EqZany7mbeRRlSRwMzNzL5olyFdffHBZg== - dependencies: - "@graphql-tools/merge" "8.3.1" - "@graphql-tools/utils" "8.9.0" - tslib "^2.4.0" - value-or-promise "1.0.11" - -"@graphql-tools/schema@^9.0.0": - version "9.0.19" - resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-9.0.19.tgz#c4ad373b5e1b8a0cf365163435b7d236ebdd06e7" - integrity sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w== - dependencies: - "@graphql-tools/merge" "^8.4.1" - "@graphql-tools/utils" "^9.2.1" - tslib "^2.4.0" - value-or-promise "^1.0.12" - -"@graphql-tools/utils@8.0.2": - version "8.0.2" - resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.0.2.tgz#795a8383cdfdc89855707d62491c576f439f3c51" - integrity sha512-gzkavMOgbhnwkHJYg32Adv6f+LxjbQmmbdD5Hty0+CWxvaiuJq+nU6tzb/7VSU4cwhbNLx/lGu2jbCPEW1McZQ== - dependencies: - tslib "~2.3.0" - -"@graphql-tools/utils@8.9.0": - version "8.9.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.9.0.tgz#c6aa5f651c9c99e1aca55510af21b56ec296cdb7" - integrity sha512-pjJIWH0XOVnYGXCqej8g/u/tsfV4LvLlj0eATKQu5zwnxd/TiTHq7Cg313qUPTFFHZ3PP5wJ15chYVtLDwaymg== - dependencies: - tslib "^2.4.0" - -"@graphql-tools/utils@^10.0.0": - version "10.0.7" - resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-10.0.7.tgz#ed88968b5ce53dabacbdd185df967aaab35f8549" - integrity sha512-KOdeMj6Hd/MENDaqPbws3YJl3wVy0DeYnL7PyUms5Skyf7uzI9INynDwPMhLXfSb0/ph6BXTwMd5zBtWbF8tBQ== - dependencies: - "@graphql-typed-document-node/core" "^3.1.1" - dset "^3.1.2" - tslib "^2.4.0" - -"@graphql-tools/utils@^6.0.18": - version "6.2.4" - resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-6.2.4.tgz#38a2314d2e5e229ad4f78cca44e1199e18d55856" - integrity sha512-ybgZ9EIJE3JMOtTrTd2VcIpTXtDrn2q6eiYkeYMKRVh3K41+LZa6YnR2zKERTXqTWqhobROwLt4BZbw2O3Aeeg== - dependencies: - "@ardatan/aggregate-error" "0.0.6" - camel-case "4.1.1" - tslib "~2.0.1" - -"@graphql-tools/utils@^7.9.1": - version "7.10.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-7.10.0.tgz#07a4cb5d1bec1ff1dc1d47a935919ee6abd38699" - integrity sha512-d334r6bo9mxdSqZW6zWboEnnOOFRrAPVQJ7LkU8/6grglrbcu6WhwCLzHb90E94JI3TD3ricC3YGbUqIi9Xg0w== - dependencies: - "@ardatan/aggregate-error" "0.0.6" - camel-case "4.1.2" - tslib "~2.2.0" - -"@graphql-tools/utils@^8.5.1", "@graphql-tools/utils@^8.8.0": - version "8.13.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.13.1.tgz#b247607e400365c2cd87ff54654d4ad25a7ac491" - integrity sha512-qIh9yYpdUFmctVqovwMdheVNJqFh+DQNWIhX87FJStfXYnmweBUDATok9fWPleKeFwxnW8IapKmY8m8toJEkAw== - dependencies: - tslib "^2.4.0" - -"@graphql-tools/utils@^9.0.0", "@graphql-tools/utils@^9.1.1", "@graphql-tools/utils@^9.2.1": - version "9.2.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-9.2.1.tgz#1b3df0ef166cfa3eae706e3518b17d5922721c57" - integrity sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A== - dependencies: - "@graphql-typed-document-node/core" "^3.1.1" - tslib "^2.4.0" - -"@graphql-typed-document-node/core@^3.1.1": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" - integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== - -"@hapi/hoek@^9.0.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" - integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== - -"@hapi/topo@^5.0.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" - integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== - dependencies: - "@hapi/hoek" "^9.0.0" - "@humanwhocodes/config-array@^0.11.11": version "0.11.11" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" @@ -7074,31 +6414,11 @@ dependencies: nx "15.9.7" -"@octokit/auth-token@^2.4.4": - version "2.5.0" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36" - integrity sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g== - dependencies: - "@octokit/types" "^6.0.3" - "@octokit/auth-token@^3.0.0": version "3.0.4" resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-3.0.4.tgz#70e941ba742bdd2b49bdb7393e821dea8520a3db" integrity sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ== -"@octokit/core@^3.5.1": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.6.0.tgz#3376cb9f3008d9b3d110370d90e0a1fcd5fe6085" - integrity sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q== - dependencies: - "@octokit/auth-token" "^2.4.4" - "@octokit/graphql" "^4.5.8" - "@octokit/request" "^5.6.3" - "@octokit/request-error" "^2.0.5" - "@octokit/types" "^6.0.3" - before-after-hook "^2.2.0" - universal-user-agent "^6.0.0" - "@octokit/core@^4.2.1": version "4.2.4" resolved "https://registry.yarnpkg.com/@octokit/core/-/core-4.2.4.tgz#d8769ec2b43ff37cc3ea89ec4681a20ba58ef907" @@ -7112,15 +6432,6 @@ before-after-hook "^2.2.0" universal-user-agent "^6.0.0" -"@octokit/endpoint@^6.0.1": - version "6.0.12" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658" - integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA== - dependencies: - "@octokit/types" "^6.0.3" - is-plain-object "^5.0.0" - universal-user-agent "^6.0.0" - "@octokit/endpoint@^7.0.0": version "7.0.6" resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-7.0.6.tgz#791f65d3937555141fb6c08f91d618a7d645f1e2" @@ -7130,15 +6441,6 @@ is-plain-object "^5.0.0" universal-user-agent "^6.0.0" -"@octokit/graphql@^4.5.8": - version "4.8.0" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.8.0.tgz#664d9b11c0e12112cbf78e10f49a05959aa22cc3" - integrity sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg== - dependencies: - "@octokit/request" "^5.6.0" - "@octokit/types" "^6.0.3" - universal-user-agent "^6.0.0" - "@octokit/graphql@^5.0.0": version "5.0.6" resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-5.0.6.tgz#9eac411ac4353ccc5d3fca7d76736e6888c5d248" @@ -7148,11 +6450,6 @@ "@octokit/types" "^9.0.0" universal-user-agent "^6.0.0" -"@octokit/openapi-types@^12.11.0": - version "12.11.0" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-12.11.0.tgz#da5638d64f2b919bca89ce6602d059f1b52d3ef0" - integrity sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ== - "@octokit/openapi-types@^18.0.0": version "18.1.1" resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-18.1.1.tgz#09bdfdabfd8e16d16324326da5148010d765f009" @@ -7163,13 +6460,6 @@ resolved "https://registry.yarnpkg.com/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz#e07896739618dab8da7d4077c658003775f95437" integrity sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw== -"@octokit/plugin-paginate-rest@^2.16.8": - version "2.21.3" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz#7f12532797775640dbb8224da577da7dc210c87e" - integrity sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw== - dependencies: - "@octokit/types" "^6.40.0" - "@octokit/plugin-paginate-rest@^6.1.2": version "6.1.2" resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.2.tgz#f86456a7a1fe9e58fec6385a85cf1b34072341f8" @@ -7183,14 +6473,6 @@ resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85" integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA== -"@octokit/plugin-rest-endpoint-methods@^5.12.0": - version "5.16.2" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz#7ee8bf586df97dd6868cf68f641354e908c25342" - integrity sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw== - dependencies: - "@octokit/types" "^6.39.0" - deprecation "^2.3.1" - "@octokit/plugin-rest-endpoint-methods@^7.1.2": version "7.2.3" resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.2.3.tgz#37a84b171a6cb6658816c82c4082ac3512021797" @@ -7198,15 +6480,6 @@ dependencies: "@octokit/types" "^10.0.0" -"@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677" - integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg== - dependencies: - "@octokit/types" "^6.0.3" - deprecation "^2.0.0" - once "^1.4.0" - "@octokit/request-error@^3.0.0": version "3.0.3" resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-3.0.3.tgz#ef3dd08b8e964e53e55d471acfe00baa892b9c69" @@ -7216,18 +6489,6 @@ deprecation "^2.0.0" once "^1.4.0" -"@octokit/request@^5.6.0", "@octokit/request@^5.6.3": - version "5.6.3" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.3.tgz#19a022515a5bba965ac06c9d1334514eb50c48b0" - integrity sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A== - dependencies: - "@octokit/endpoint" "^6.0.1" - "@octokit/request-error" "^2.1.0" - "@octokit/types" "^6.16.1" - is-plain-object "^5.0.0" - node-fetch "^2.6.7" - universal-user-agent "^6.0.0" - "@octokit/request@^6.0.0": version "6.2.8" resolved "https://registry.yarnpkg.com/@octokit/request/-/request-6.2.8.tgz#aaf480b32ab2b210e9dadd8271d187c93171d8eb" @@ -7240,16 +6501,6 @@ node-fetch "^2.6.7" universal-user-agent "^6.0.0" -"@octokit/rest@^18.0.9": - version "18.12.0" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.12.0.tgz#f06bc4952fc87130308d810ca9d00e79f6988881" - integrity sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q== - dependencies: - "@octokit/core" "^3.5.1" - "@octokit/plugin-paginate-rest" "^2.16.8" - "@octokit/plugin-request-log" "^1.0.4" - "@octokit/plugin-rest-endpoint-methods" "^5.12.0" - "@octokit/rest@^19.0.3": version "19.0.13" resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-19.0.13.tgz#e799393264edc6d3c67eeda9e5bd7832dcf974e4" @@ -7272,13 +6523,6 @@ dependencies: "@octokit/openapi-types" "^18.0.0" -"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.39.0", "@octokit/types@^6.40.0": - version "6.41.0" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.41.0.tgz#e58ef78d78596d2fb7df9c6259802464b5f84a04" - integrity sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg== - dependencies: - "@octokit/openapi-types" "^12.11.0" - "@octokit/types@^9.0.0", "@octokit/types@^9.2.3": version "9.3.2" resolved "https://registry.yarnpkg.com/@octokit/types/-/types-9.3.2.tgz#3f5f89903b69f6a2d196d78ec35f888c0013cac5" @@ -7407,54 +6651,12 @@ dependencies: type-detect "4.0.8" -"@sinonjs/commons@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-2.0.0.tgz#fd4ca5b063554307e8327b4564bd56d3b73924a3" - integrity sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg== - dependencies: - type-detect "4.0.8" - -"@sinonjs/commons@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.0.tgz#beb434fe875d965265e04722ccfc21df7f755d72" - integrity sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA== - dependencies: - type-detect "4.0.8" - -"@sinonjs/fake-timers@^10.0.2": - version "10.3.0" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" - integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== - dependencies: - "@sinonjs/commons" "^3.0.0" - "@sinonjs/fake-timers@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== dependencies: - "@sinonjs/commons" "^1.7.0" - -"@sinonjs/fake-timers@^9.1.2": - version "9.1.2" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz#4eaab737fab77332ab132d396a3c0d364bd0ea8c" - integrity sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw== - dependencies: - "@sinonjs/commons" "^1.7.0" - -"@sinonjs/samsam@^7.0.1": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-7.0.1.tgz#5b5fa31c554636f78308439d220986b9523fc51f" - integrity sha512-zsAk2Jkiq89mhZovB2LLOdTCxJF4hqqTToGP0ASWlhp4I1hqOjcfmZGafXntCN7MDC6yySH0mFHrYtHceOeLmw== - dependencies: - "@sinonjs/commons" "^2.0.0" - lodash.get "^4.4.2" - type-detect "^4.0.8" - -"@sinonjs/text-encoding@^0.7.1": - version "0.7.2" - resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz#5981a8db18b56ba38ef0efb7d995b12aa7b51918" - integrity sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ== + "@sinonjs/commons" "^1.7.0" "@size-limit/file@6.0.4": version "6.0.4" @@ -8999,11 +8201,6 @@ resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.3.3.tgz#85bc74ba782fb7aa3a514d11767832b0e3bc6803" integrity sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow== -"@types/detect-port@^1.3.0": - version "1.3.3" - resolved "https://registry.yarnpkg.com/@types/detect-port/-/detect-port-1.3.3.tgz#124c5d4c283f48a21f80826bcf39433b3e64aa81" - integrity sha512-bV/jQlAJ/nPY3XqSatkGpu+nGzou+uSwrH1cROhn+jBFg47yaNH+blW4C7p9KhopC7QxCv/6M86s37k8dMk0Yg== - "@types/eslint-scope@^3.7.3": version "3.7.5" resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.5.tgz#e28b09dbb1d9d35fdfa8a884225f00440dfc5a3e" @@ -9218,7 +8415,7 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== -"@types/semver@^7.3.10", "@types/semver@^7.3.12", "@types/semver@^7.5.0": +"@types/semver@^7.3.10", "@types/semver@^7.3.12": version "7.5.3" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.3.tgz#9a726e116beb26c24f1ccd6850201e1246122e04" integrity sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw== @@ -9238,11 +8435,6 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.5.tgz#25a71eb73eba95ac0e559ff3dd018fc08294acf6" integrity sha512-xfHdwa1FMJ082prjSJpoEI57GZITiQz10r3vEJCHa2khEFQjKy91aWKz6+zybzssCvXUwE1LQWgWVwZ4nYUvHQ== -"@types/which@^1.3.2": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@types/which/-/which-1.3.2.tgz#9c246fc0c93ded311c8512df2891fb41f6227fdf" - integrity sha512-8oDqyLC7eD4HM307boe2QWKyuzdzWBj56xI/imSl2cpL+U3tCMaTAkMJ4ee5JBZ/FsOJlvRGeIShiZDAl1qERA== - "@types/ws@^7.4.4": version "7.4.7" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" @@ -9484,30 +8676,6 @@ "@webassemblyjs/ast" "1.11.6" "@xtuc/long" "4.2.2" -"@whatwg-node/events@^0.1.0": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@whatwg-node/events/-/events-0.1.1.tgz#0ca718508249419587e130da26d40e29d99b5356" - integrity sha512-AyQEn5hIPV7Ze+xFoXVU3QTHXVbWPrzaOkxtENMPMuNL6VVHrp4hHfDt9nrQpjO7BgvuM95dMtkycX5M/DZR3w== - -"@whatwg-node/fetch@^0.9.0": - version "0.9.13" - resolved "https://registry.yarnpkg.com/@whatwg-node/fetch/-/fetch-0.9.13.tgz#1d084cd546b9cd425ae89cbb1252a3e47a9a2e1c" - integrity sha512-PPtMwhjtS96XROnSpowCQM85gCUG2m7AXZFw0PZlGbhzx2GK7f2iOXilfgIJ0uSlCuuGbOIzfouISkA7C4FJOw== - dependencies: - "@whatwg-node/node-fetch" "^0.4.17" - urlpattern-polyfill "^9.0.0" - -"@whatwg-node/node-fetch@^0.4.17": - version "0.4.19" - resolved "https://registry.yarnpkg.com/@whatwg-node/node-fetch/-/node-fetch-0.4.19.tgz#29c72ff65a8e450949238612ff17a3d3717736d3" - integrity sha512-AW7/m2AuweAoSXmESrYQr/KBafueScNbn2iNO0u6xFr2JZdPmYsSm5yvAXYk6yDLv+eDmSSKrf7JnFZ0CsJIdA== - dependencies: - "@whatwg-node/events" "^0.1.0" - busboy "^1.6.0" - fast-querystring "^1.1.1" - fast-url-parser "^1.1.3" - tslib "^2.3.1" - "@wry/equality@^0.1.2": version "0.1.11" resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.1.11.tgz#35cb156e4a96695aa81a9ecc4d03787bc17f1790" @@ -9577,14 +8745,6 @@ abbrev@1, abbrev@^1.0.0: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -accepts@~1.3.8: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - acorn-globals@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" @@ -9628,11 +8788,6 @@ add-stream@^1.0.0: resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" integrity sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ== -address@^1.0.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e" - integrity sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA== - agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -9722,84 +8877,11 @@ amazon-cognito-identity-js@5.2.14: isomorphic-unfetch "^3.0.0" js-cookie "^2.2.1" -amplify-codegen@^4.9.3: - version "4.9.3" - resolved "https://registry.npmjs.org/amplify-codegen/-/amplify-codegen-4.9.3.tgz#f4dc7ed6653c8f4154348a9c7aa0353f5da47bfb" - integrity sha512-cWngx1CBHEx3uATh15WdF2J2y+twviRIDms8z1Gi0Rcm1fNZRYh0AFYXibkWSLyBVeQlIPq3DRgKyWocxvAEkg== - dependencies: - "@aws-amplify/graphql-directives" "^1.0.1" - "@aws-amplify/graphql-docs-generator" "4.2.1" - "@aws-amplify/graphql-generator" "0.4.3" - "@aws-amplify/graphql-types-generator" "3.6.0" - "@graphql-codegen/core" "2.6.6" - chalk "^3.0.0" - fs-extra "^8.1.0" - glob-parent "^6.0.2" - globby "^11.1.0" - graphql "^15.5.0" - graphql-config "^2.2.1" - inquirer "^7.3.3" - js-yaml "^4.0.0" - ora "^4.0.3" - prettier "^1.19.1" - semver "^7.3.5" - slash "^3.0.0" - -amplify-function-plugin-interface@^1.9.7: - version "1.9.7" - resolved "https://registry.yarnpkg.com/amplify-function-plugin-interface/-/amplify-function-plugin-interface-1.9.7.tgz#cd872a8c619f5b50661e7ca073fa59feaed12b28" - integrity sha512-CMch7pWKtnEP8Y0OC8CTJ0vJSoT82yshG2e7dffkoxk29n7aeHgirMUFKgQ+MUFEXYsU+G5zJ4iksU/VtVQJ4w== - -amplify-headless-interface@1.17.7, amplify-headless-interface@^1.17.7: +amplify-headless-interface@^1.17.7: version "1.17.7" resolved "https://registry.npmjs.org/amplify-headless-interface/-/amplify-headless-interface-1.17.7.tgz#8a6c00ed8e97fd082ace95d99f84811d2ec447b1" integrity sha512-ZrRuoLkusCL8hxox+O5ZvnoMYoURd/10EvA9mdw2ORYv2ZuTfJY3ItixCq6qexM+SbuIfTKqLxj60zsnEV/nFg== -amplify-nodejs-function-runtime-provider@^2.5.23: - version "2.5.23" - resolved "https://registry.npmjs.org/amplify-nodejs-function-runtime-provider/-/amplify-nodejs-function-runtime-provider-2.5.23.tgz#21f4c3311771763a1d7cbf27369c3f282e582e66" - integrity sha512-tulXWCNQGss49ZYo94BSVL85zVunuH39jlf7/gZW02n73k4vg5OM5HDsqkScXVPCXesNRfhXP7QjjOXJITQdag== - dependencies: - "@aws-amplify/amplify-cli-core" "4.3.9" - "@aws-amplify/amplify-function-plugin-interface" "1.12.1" - execa "^5.1.1" - exit "^0.1.2" - fs-extra "^8.1.0" - glob "^7.2.0" - -amplify-storage-simulator@^1.11.3: - version "1.11.3" - resolved "https://registry.npmjs.org/amplify-storage-simulator/-/amplify-storage-simulator-1.11.3.tgz#9e5e2b180a43b5aa9927f6ed305defe23f70fd3b" - integrity sha512-c9Iz+0cugzTac3rULtU7/j42bsLq3gEBqZTosvHp1yqpfpOtZP3OPFuvKj8Y2nj+4uPv4nRLkuX0VNAGYb2Y+A== - dependencies: - body-parser "^1.19.2" - cors "^2.8.5" - etag "^1.8.1" - express "^4.17.3" - fs-extra "^8.1.0" - glob "^7.2.0" - object-to-xml "^2.0.0" - promise-toolbox "^0.20.0" - serve-static "^1.14.2" - uuid "^8.3.2" - xml "^1.0.1" - xml-js "^1.6.11" - -amplify-util-headless-input@^1.9.18: - version "1.9.18" - resolved "https://registry.npmjs.org/amplify-util-headless-input/-/amplify-util-headless-input-1.9.18.tgz#eb35e8b4fb4ef09d1810043505751f61e46579ea" - integrity sha512-Vj8NSEdIYJmPeH7k6vgoe7IVTxLl1BwWcNB/P3a+RhDaXpvQWHzBNgHkYHs4Vazae2fbBmO+l1a5gyskF3hm9A== - dependencies: - ajv "^6.12.6" - amplify-headless-interface "1.17.7" - -amplify-velocity-template@1.4.14: - version "1.4.14" - resolved "https://registry.npmjs.org/amplify-velocity-template/-/amplify-velocity-template-1.4.14.tgz#99565e048591ff843db4588319a8ef16cfc6592c" - integrity sha512-2IdMZMQtmEAbpdruid0T5GRfRgQ8y8EJYuHT764IK2096mWWFdB68+d37nmecnfZTAfximSBx9401g18UrwaOg== - dependencies: - lodash "^4.17.21" - ansi-align@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" @@ -10130,11 +9212,6 @@ array-differ@^3.0.0: resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== - array-ify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" @@ -10182,7 +9259,7 @@ array.prototype.flat@^1.3.1: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.2.4, array.prototype.flatmap@^1.3.1: +array.prototype.flatmap@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== @@ -10226,7 +9303,7 @@ arrify@^2.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== -asap@^2.0.0, asap@~2.0.3: +asap@^2.0.0: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== @@ -10287,11 +9364,6 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -auto-bind@~4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-4.0.0.tgz#e3589fc6c2da8f7ca43ba9f84fa52a744fc997fb" - integrity sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ== - available-typed-arrays@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" @@ -10341,7 +9413,7 @@ aws-appsync-subscription-link@^2.4.2: url "^0.11.0" zen-observable-ts "^1.2.5" -aws-appsync@^4.1.1, aws-appsync@^4.1.9: +aws-appsync@^4.1.1: version "4.1.9" resolved "https://registry.yarnpkg.com/aws-appsync/-/aws-appsync-4.1.9.tgz#ec084d9b6a3a40334822e49864fed14fbf9558ef" integrity sha512-YlOxC81Ij25UmSUVocbFF+TA5tItYAkL+04Y+gPBvZGCmrKI4+g/Z9b6c6IrX4IaG0eh4msizeZuwlUUjsEvlQ== @@ -10385,19 +9457,10 @@ aws-cdk-lib@2.129.0, aws-cdk-lib@~2.129.0: table "^6.8.1" yaml "1.10.2" -aws-sdk-mock@^5.6.2: - version "5.8.0" - resolved "https://registry.yarnpkg.com/aws-sdk-mock/-/aws-sdk-mock-5.8.0.tgz#2556a79010a883f4bd5a566ce63bc244cee67579" - integrity sha512-s0Vy4DObFmVJ6h1uTw1LGInOop77oF0JXH2N39Lv+1Wss274EowVk9odhM4Sji4mynXcM5oSu68uYqkJRviDRA== - dependencies: - aws-sdk "^2.1231.0" - sinon "^14.0.1" - traverse "^0.6.6" - -aws-sdk@2.518.0, aws-sdk@^2.1113.0, aws-sdk@^2.1141.0, aws-sdk@^2.1231.0, aws-sdk@^2.1464.0: - version "2.1669.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1669.0.tgz#23aae49658cd199b08b59d9b36cb51a1ab71ed96" - integrity sha512-ua3AfvS2rUiOpf9choxNXLKE3T70yY6klGovdekXd5ZTwzDXQoYw1dokfArIub/2BM9Dmgi/bFq/crnz83tX0w== +aws-sdk@2.518.0, aws-sdk@^2.1113.0, aws-sdk@^2.1141.0: + version "2.1643.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1643.0.tgz#ecd91156900eb23b9ada5a32df8654bcc4eaa521" + integrity sha512-1k8W0cU7K9rPwPBzv84Z2IE5aT3jhv3Jswn8XerZliiLl1MTj6F4wjxCeY5BpmAv+Zyy4zM0w98M8vVqKeHEeA== dependencies: buffer "4.9.2" events "1.1.1" @@ -10443,20 +9506,6 @@ babel-eslint@^10.1.0: eslint-visitor-keys "^1.0.0" resolve "^1.12.0" -babel-generator@^6.26.1: - version "6.26.1" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" - integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== - dependencies: - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - detect-indent "^4.0.0" - jsesc "^1.3.0" - lodash "^4.17.4" - source-map "^0.5.7" - trim-right "^1.0.1" - babel-jest@^26.6.3: version "26.6.3" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" @@ -10481,13 +9530,6 @@ babel-loader@^8.1.0: make-dir "^3.1.0" schema-utils "^2.6.5" -babel-messages@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - integrity sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w== - dependencies: - babel-runtime "^6.22.0" - babel-plugin-dynamic-import-node@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" @@ -10516,11 +9558,6 @@ babel-plugin-jest-hoist@^26.6.2: "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" -babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0: - version "7.0.0-beta.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz#aa213c1435e2bffeb6fca842287ef534ad05d5cf" - integrity sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ== - babel-preset-current-node-syntax@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" @@ -10539,39 +9576,6 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-fbjs@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz#38a14e5a7a3b285a3f3a86552d650dca5cf6111c" - integrity sha512-9ywCsCvo1ojrw0b+XYk7aFvTH6D9064t0RIL1rtMf3nsa02Xw41MS7sZw216Im35xj/UY0PDBQsa1brUDDF1Ow== - dependencies: - "@babel/plugin-proposal-class-properties" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.0.0" - "@babel/plugin-syntax-class-properties" "^7.0.0" - "@babel/plugin-syntax-flow" "^7.0.0" - "@babel/plugin-syntax-jsx" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.0.0" - "@babel/plugin-transform-arrow-functions" "^7.0.0" - "@babel/plugin-transform-block-scoped-functions" "^7.0.0" - "@babel/plugin-transform-block-scoping" "^7.0.0" - "@babel/plugin-transform-classes" "^7.0.0" - "@babel/plugin-transform-computed-properties" "^7.0.0" - "@babel/plugin-transform-destructuring" "^7.0.0" - "@babel/plugin-transform-flow-strip-types" "^7.0.0" - "@babel/plugin-transform-for-of" "^7.0.0" - "@babel/plugin-transform-function-name" "^7.0.0" - "@babel/plugin-transform-literals" "^7.0.0" - "@babel/plugin-transform-member-expression-literals" "^7.0.0" - "@babel/plugin-transform-modules-commonjs" "^7.0.0" - "@babel/plugin-transform-object-super" "^7.0.0" - "@babel/plugin-transform-parameters" "^7.0.0" - "@babel/plugin-transform-property-literals" "^7.0.0" - "@babel/plugin-transform-react-display-name" "^7.0.0" - "@babel/plugin-transform-react-jsx" "^7.0.0" - "@babel/plugin-transform-shorthand-properties" "^7.0.0" - "@babel/plugin-transform-spread" "^7.0.0" - "@babel/plugin-transform-template-literals" "^7.0.0" - babel-plugin-syntax-trailing-function-commas "^7.0.0-beta.0" - babel-preset-jest@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" @@ -10580,24 +9584,6 @@ babel-preset-jest@^26.6.2: babel-plugin-jest-hoist "^26.6.2" babel-preset-current-node-syntax "^1.0.0" -babel-runtime@^6.22.0, babel-runtime@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - integrity sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g== - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - -babel-types@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - integrity sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g== - dependencies: - babel-runtime "^6.26.0" - esutils "^2.0.2" - lodash "^4.17.4" - to-fast-properties "^1.0.3" - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -10683,34 +9669,11 @@ bl@^4.0.3, bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" -body-parser@1.20.2, body-parser@^1.19.2: - version "1.20.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" - integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== - dependencies: - bytes "3.1.2" - content-type "~1.0.5" - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - http-errors "2.0.0" - iconv-lite "0.4.24" - on-finished "2.4.1" - qs "6.11.0" - raw-body "2.5.2" - type-is "~1.6.18" - unpipe "1.0.0" - boolbase@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== -bottleneck@2.19.5: - version "2.19.5" - resolved "https://registry.yarnpkg.com/bottleneck/-/bottleneck-2.19.5.tgz#5df0b90f59fd47656ebe63c78a98419205cadd91" - integrity sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw== - bowser@^2.11.0: version "2.11.0" resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" @@ -10771,13 +9734,6 @@ browser-process-hrtime@^1.0.0: resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== -browserify-zlib@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" - integrity sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ== - dependencies: - pako "~0.2.0" - browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.21.4, browserslist@^4.21.9: version "4.22.1" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.1.tgz#ba91958d1a59b87dab6fed8dfbcb3da5e2e9c619" @@ -10807,11 +9763,6 @@ buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3: resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== -buffer-equal-constant-time@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" - integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== - buffer-from@1.x, buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" @@ -10859,13 +9810,6 @@ builtins@^5.0.0: dependencies: semver "^7.0.0" -busboy@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" - integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== - dependencies: - streamsearch "^1.1.0" - byte-size@^7.0.0: version "7.0.1" resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-7.0.1.tgz#b1daf3386de7ab9d706b941a748dbfc71130dee3" @@ -10876,11 +9820,6 @@ bytes-iec@^3.1.1: resolved "https://registry.yarnpkg.com/bytes-iec/-/bytes-iec-3.1.1.tgz#94cd36bf95c2c22a82002c247df8772d1d591083" integrity sha512-fey6+4jDK7TFtFg/klGSvNKJctyU7n2aQdnM+CO0ruLPbqqMOM8Tio0Pc+deqUeVKX1tL5DQep1zQ7+37aTAsA== -bytes@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" - integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== - cacache@^16.0.0, cacache@^16.0.6, cacache@^16.1.0: version "16.1.3" resolved "https://registry.yarnpkg.com/cacache/-/cacache-16.1.3.tgz#a02b9f34ecfaf9a78c9f4bc16fceb94d5d67a38e" @@ -10988,22 +9927,6 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camel-case@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.1.tgz#1fc41c854f00e2f7d0139dfeba1542d6896fe547" - integrity sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q== - dependencies: - pascal-case "^3.1.1" - tslib "^1.10.0" - -camel-case@4.1.2, camel-case@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" - integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== - dependencies: - pascal-case "^3.1.2" - tslib "^2.0.3" - camelcase-keys@6.2.2, camelcase-keys@^6.2.2: version "6.2.2" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" @@ -11043,15 +9966,6 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001541: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001547.tgz#d4f92efc488aab3c7f92c738d3977c2a3180472b" integrity sha512-W7CrtIModMAxobGhz8iXmDfuJiiKg1WADMO/9x7/CLNin5cpSbuBjooyoIUVB5eyCc36QuTVlkVa1iB2S5+/eA== -capital-case@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669" - integrity sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - upper-case-first "^2.0.2" - capture-exit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" @@ -11080,7 +9994,7 @@ chalk@^1.0.0, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2: +chalk@^2.0.1, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -11105,56 +10019,6 @@ chalk@^4, chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" -change-case-all@1.0.14: - version "1.0.14" - resolved "https://registry.yarnpkg.com/change-case-all/-/change-case-all-1.0.14.tgz#bac04da08ad143278d0ac3dda7eccd39280bfba1" - integrity sha512-CWVm2uT7dmSHdO/z1CXT/n47mWonyypzBbuCy5tN7uMg22BsfkhwT6oHmFCAk+gL1LOOxhdbB9SZz3J1KTY3gA== - dependencies: - change-case "^4.1.2" - is-lower-case "^2.0.2" - is-upper-case "^2.0.2" - lower-case "^2.0.2" - lower-case-first "^2.0.2" - sponge-case "^1.0.1" - swap-case "^2.0.2" - title-case "^3.0.3" - upper-case "^2.0.2" - upper-case-first "^2.0.2" - -change-case-all@1.0.15: - version "1.0.15" - resolved "https://registry.yarnpkg.com/change-case-all/-/change-case-all-1.0.15.tgz#de29393167fc101d646cd76b0ef23e27d09756ad" - integrity sha512-3+GIFhk3sNuvFAJKU46o26OdzudQlPNBCu1ZQi3cMeMHhty1bhDxu2WrEilVNYaGvqUtR1VSigFcJOiS13dRhQ== - dependencies: - change-case "^4.1.2" - is-lower-case "^2.0.2" - is-upper-case "^2.0.2" - lower-case "^2.0.2" - lower-case-first "^2.0.2" - sponge-case "^1.0.1" - swap-case "^2.0.2" - title-case "^3.0.3" - upper-case "^2.0.2" - upper-case-first "^2.0.2" - -change-case@^4.1.1, change-case@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/change-case/-/change-case-4.1.2.tgz#fedfc5f136045e2398c0410ee441f95704641e12" - integrity sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A== - dependencies: - camel-case "^4.1.2" - capital-case "^1.0.4" - constant-case "^3.0.4" - dot-case "^3.0.4" - header-case "^2.0.4" - no-case "^3.0.4" - param-case "^3.0.4" - pascal-case "^3.1.2" - path-case "^3.0.4" - sentence-case "^3.0.4" - snake-case "^3.0.4" - tslib "^2.0.3" - char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -11170,7 +10034,7 @@ charenc@0.0.2, charenc@^0.0.2: resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== -chokidar@^3.4.0, chokidar@^3.5.2, chokidar@^3.5.3: +chokidar@^3.4.0, chokidar@^3.5.2: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -11497,7 +10361,7 @@ colorspace@1.1.x: color "^3.1.3" text-hex "1.0.x" -columnify@^1.5.4, columnify@^1.6.0: +columnify@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.6.0.tgz#6989531713c9008bb29735e61e37acf5bd553cf3" integrity sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q== @@ -11527,11 +10391,6 @@ commander@^2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" - integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== - commander@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" @@ -11557,16 +10416,6 @@ common-ancestor-path@^1.0.1: resolved "https://registry.yarnpkg.com/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz#4f7d2d1394d91b7abdf51871c62f71eadb0182a7" integrity sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w== -common-tags@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" - integrity sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw== - -common-tags@1.8.2, common-tags@^1.8.0: - version "1.8.2" - resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" - integrity sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA== - commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -11644,32 +10493,11 @@ console-control-strings@^1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== -constant-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-3.0.4.tgz#3b84a9aeaf4cf31ec45e6bf5de91bdfb0589faf1" - integrity sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - upper-case "^2.0.2" - -constructs@10.3.0, constructs@^10.0.5: +constructs@10.3.0: version "10.3.0" resolved "https://registry.yarnpkg.com/constructs/-/constructs-10.3.0.tgz#4c246fce9cf8e77711ad45944e9fbd41f1501965" integrity sha512-vbK8i3rIb/xwZxSpTjz3SagHn1qq9BChLEfy5Hf6fB3/2eFbrwt2n9kHwQcS0CPTRBesreeAcsJfMq2229FnbQ== -content-disposition@0.5.4: - version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - -content-type@~1.0.4, content-type@~1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" - integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== - conventional-changelog-angular@^5.0.11, conventional-changelog-angular@^5.0.12: version "5.0.13" resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz#896885d63b914a70d4934b59d2fe7bde1832b28c" @@ -11771,16 +10599,6 @@ convert-source-map@^2.0.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== - -cookie@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" - integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== - cookie@^0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" @@ -11804,29 +10622,11 @@ copyfiles@^2.2.0: untildify "^4.0.0" yargs "^16.1.0" -core-js@^2.4.0: - version "2.6.12" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" - integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== - -core-js@^3.6.4: - version "3.33.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.33.0.tgz#70366dbf737134761edb017990cf5ce6c6369c40" - integrity sha512-HoZr92+ZjFEKar5HS6MC776gYslNOKHt75mEBKWKnPeFDpZ6nH5OeF3S6HFT1mUAUZKrzkez05VboaX8myjSuw== - core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -cors@^2.8.5: - version "2.8.5" - resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" - integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== - dependencies: - object-assign "^4" - vary "^1" - cosmiconfig-typescript-loader@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-2.0.2.tgz#7e7ce6064af041c910e1e43fb0fd9625cee56e93" @@ -11874,7 +10674,7 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-fetch@2.2.2, cross-fetch@^2.2.6, cross-fetch@^3.1.5: +cross-fetch@2.2.2, cross-fetch@^2.2.6: version "2.2.6" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.2.6.tgz#2ef0bb39a24ac034787965c457368a28730e220a" integrity sha512-9JZz+vXCmfKUZ68zAptS7k4Nu8e2qcibe7WVZYps7sAgk5R8GYTc+T1WR0v1rlP9HxgARmOX1UTIJZFytajpNA== @@ -12062,16 +10862,6 @@ damerau-levenshtein@^1.0.8: resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== -dank-each@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/dank-each/-/dank-each-1.0.0.tgz#a861343a4b28d362203d405c77864dc9a6403730" - integrity sha512-gMDy24y+3LlnAaHq4WFwRKliMZRkGp41Gy9JVsD1BO5tprb/lEh4afJlkankcTqRoppSaHRwgFQX61QjJ5ClfQ== - -dank-map@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/dank-map/-/dank-map-0.1.0.tgz#e99e77f382c68f2e5ab2b3f3a82b8031957529a8" - integrity sha512-mQoLySkWc5bQM8XKXz0rIuISX/+12rSSfPojYlTVT6KPj3LsvfLURtrv0w+QEt1gRIKwp9mxnwOcL5nsOTkk2Q== - dargs@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" @@ -12091,11 +10881,6 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" -dataloader@^2.0.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-2.2.2.tgz#216dc509b5abe39d43a9b9d97e6e5e473dfbe3e0" - integrity sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g== - date-fns@^1.27.2: version "1.30.1" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" @@ -12292,17 +11077,7 @@ denque@^2.1.0: resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== -depd@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - -dependency-graph@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.11.0.tgz#ac0ce7ed68a54da22165a85e97a01d53f5eb2e27" - integrity sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg== - -deprecation@^2.0.0, deprecation@^2.3.1: +deprecation@^2.0.0: version "2.3.1" resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== @@ -12312,18 +11087,6 @@ dequal@^2.0.3: resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== -destroy@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - -detect-indent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - integrity sha512-BDKtmHlOzwI7iRuEkhzsnPoi5ypEhWAJB5RvHWe1kMr06js3uK5B3734i3ui5Yd+wOJV1cpE4JnivPD283GU/A== - dependencies: - repeating "^2.0.0" - detect-indent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" @@ -12349,14 +11112,6 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -detect-port@^1.3.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-1.5.1.tgz#451ca9b6eaf20451acb0799b8ab40dff7718727b" - integrity sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ== - dependencies: - address "^1.0.1" - debug "4" - dezalgo@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81" @@ -12380,11 +11135,6 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -diff@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" - integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== - diff@^5.1.0: version "5.2.0" resolved "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" @@ -12448,14 +11198,6 @@ domutils@^2.8.0: domelementtype "^2.2.0" domhandler "^4.2.0" -dot-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" - integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - dot-prop@^5.1.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" @@ -12489,43 +11231,16 @@ downlevel-dts@^0.11.0: shelljs "^0.8.3" typescript next -dset@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.2.tgz#89c436ca6450398396dc6538ea00abc0c54cd45a" - integrity sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q== - duplexer@^0.1.1, duplexer@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== -duplexify@^3.5.0, duplexify@^3.6.0: - version "3.7.1" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" - integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== -ecdsa-sig-formatter@1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" - integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== - dependencies: - safe-buffer "^5.0.1" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== - ejs@^3.1.7: version "3.1.10" resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" @@ -12568,11 +11283,6 @@ enabled@2.0.x: resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== - encoding@^0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" @@ -12580,7 +11290,7 @@ encoding@^0.1.13: dependencies: iconv-lite "^0.6.2" -end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: +end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -12747,11 +11457,6 @@ escape-goat@^4.0.0: resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-4.0.0.tgz#9424820331b510b0666b98f7873fe11ac4aa8081" integrity sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg== -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== - escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -13028,11 +11733,6 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -etag@^1.8.1, etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== - eventemitter3@^4.0.4: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -13171,43 +11871,6 @@ exponential-backoff@^3.1.1: resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6" integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== -express@^4.17.3: - version "4.19.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" - integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== - dependencies: - accepts "~1.3.8" - array-flatten "1.1.1" - body-parser "1.20.2" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.6.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "2.0.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "1.2.0" - fresh "0.5.2" - http-errors "2.0.0" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "2.4.1" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.7" - qs "6.11.0" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" - setprototypeof "1.2.0" - statuses "2.0.1" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -13251,11 +11914,6 @@ fast-base64-decode@^1.0.0: resolved "https://registry.yarnpkg.com/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz#b434a0dd7d92b12b43f26819300d2dafb83ee418" integrity sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q== -fast-decode-uri-component@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" - integrity sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg== - fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -13298,13 +11956,6 @@ fast-memoize@^2.5.2: resolved "https://registry.yarnpkg.com/fast-memoize/-/fast-memoize-2.5.2.tgz#79e3bb6a4ec867ea40ba0e7146816f6cdce9b57e" integrity sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw== -fast-querystring@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/fast-querystring/-/fast-querystring-1.1.2.tgz#a6d24937b4fc6f791b4ee31dcb6f53aeafb89f53" - integrity sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg== - dependencies: - fast-decode-uri-component "^1.0.1" - fast-url-parser@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" @@ -13352,24 +12003,6 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -fbjs-css-vars@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8" - integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== - -fbjs@^3.0.0: - version "3.0.5" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.5.tgz#aa0edb7d5caa6340011790bd9249dbef8a81128d" - integrity sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg== - dependencies: - cross-fetch "^3.1.5" - fbjs-css-vars "^1.0.0" - loose-envify "^1.0.0" - object-assign "^4.1.0" - promise "^7.1.1" - setimmediate "^1.0.5" - ua-parser-js "^1.0.35" - fecha@^4.2.0: version "4.2.3" resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" @@ -13430,19 +12063,6 @@ fill-range@^7.1.1: dependencies: to-regex-range "^5.0.1" -finalhandler@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" - integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "2.4.1" - parseurl "~1.3.3" - statuses "2.0.1" - unpipe "~1.0.0" - find-cache-dir@^3.3.1: version "3.3.2" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" @@ -13499,15 +12119,7 @@ fn.name@1.x.x: resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== -folder-hash@^4.0.2: - version "4.0.4" - resolved "https://registry.yarnpkg.com/folder-hash/-/folder-hash-4.0.4.tgz#f5ffa14e9fc6f3213598f6a367207adf7d419edc" - integrity sha512-zEyYH+UsHEfJJcCRSf9ai5I4CTZwZ8ObONRuEI5hcEmJY5pS0FUWKruX9mMnYJrgC7MlPFDYnGsK1R+WFYjLlQ== - dependencies: - debug "^4.3.3" - minimatch "~5.1.2" - -follow-redirects@^1.15.6: +follow-redirects@^1.15.0: version "1.15.6" resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== @@ -13555,11 +12167,6 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -forwarded@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" - integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== - fp-and-or@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/fp-and-or/-/fp-and-or-0.1.4.tgz#0268c800c359ede259cdcbc352654e698b7ea299" @@ -13572,11 +12179,6 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== - from2@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" @@ -13941,7 +12543,7 @@ glob@^8.0.1, glob@^8.1.0: minimatch "^5.0.1" once "^1.3.0" -global-dirs@^0.1.0, global-dirs@^0.1.1: +global-dirs@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" integrity sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg== @@ -14039,6 +12641,17 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== +graphql-auth-transformer@7.2.82: + version "7.2.82" + resolved "https://registry.npmjs.org/graphql-auth-transformer/-/graphql-auth-transformer-7.2.82.tgz#b2844fb002f33da77cd91e576b68d269ee733fae" + integrity sha512-64hOveNW1lB0Cn1jArl3tE34k+V4u/YZdImT/92PmCGwCsV5R+l77R58zeWr+7WGFbXmlWz4aAtmviyWoMUmVA== + dependencies: + graphql "^15.5.0" + graphql-connection-transformer "5.2.80" + graphql-mapping-template "4.20.16" + graphql-transformer-common "4.31.1" + graphql-transformer-core "8.2.13" + graphql-config@^2.2.1: version "2.2.2" resolved "https://registry.yarnpkg.com/graphql-config/-/graphql-config-2.2.2.tgz#a4b577826bba9b83e7b0f6cd617be43ca67da045" @@ -14050,6 +12663,66 @@ graphql-config@^2.2.1: lodash "^4.17.4" minimatch "^3.0.4" +graphql-connection-transformer@5.2.80: + version "5.2.80" + resolved "https://registry.npmjs.org/graphql-connection-transformer/-/graphql-connection-transformer-5.2.80.tgz#8f98c010af0485e6ebde4568a5e6178a30a499cd" + integrity sha512-TOc2wdezaUZZNTb9OKGH6G3+m03MkpXfyTx5yqq/M3LXYsqthhrRhRT51cswJvvDiL5SZzgubRLX5MNcZyaTQg== + dependencies: + cloudform-types "^4.2.0" + graphql "^15.5.0" + graphql-dynamodb-transformer "7.2.80" + graphql-key-transformer "3.2.80" + graphql-mapping-template "4.20.16" + graphql-transformer-common "4.31.1" + graphql-transformer-core "8.2.13" + +graphql-dynamodb-transformer@7.2.80: + version "7.2.80" + resolved "https://registry.npmjs.org/graphql-dynamodb-transformer/-/graphql-dynamodb-transformer-7.2.80.tgz#2938359c5a241009652dc30ee15dafe5ccc56063" + integrity sha512-TTcl2uuqRH7FaUX2sZaVhYIREABgT1gToV8GxMWTRRxr0MhdKs0VxtOAXa1AJ+ei9k1zTTA+ZZCHFEn8qaXwuA== + dependencies: + "@types/pluralize" "^0.0.29" + cloudform-types "^4.2.0" + graphql "^15.5.0" + graphql-mapping-template "4.20.16" + graphql-transformer-common "4.31.1" + graphql-transformer-core "8.2.13" + md5 "^2.2.1" + pluralize "^8.0.0" + +graphql-elasticsearch-transformer@5.2.81: + version "5.2.81" + resolved "https://registry.npmjs.org/graphql-elasticsearch-transformer/-/graphql-elasticsearch-transformer-5.2.81.tgz#3f6f61cb0ee2ff183840eb19dae951ced38d719d" + integrity sha512-TLG4N5V9VBKmllrK87qLQ8JsSD+yxatreEKtYpgD6rFOPqMhj5OAFATcze5egbfezVA6DXiaRDYqrimxNFPSBA== + dependencies: + cloudform-types "^4.2.0" + graphql "^15.5.0" + graphql-mapping-template "4.20.16" + graphql-transformer-common "4.31.1" + graphql-transformer-core "8.2.13" + +graphql-function-transformer@3.3.71: + version "3.3.71" + resolved "https://registry.npmjs.org/graphql-function-transformer/-/graphql-function-transformer-3.3.71.tgz#cdc78fab2ca9032e2b784b9a2387624934d3f087" + integrity sha512-29tmgd5bketVppNK9i2/xmLBG4LGmiuRzzwasP89X2PDvSF88Ztmjr1k0F3vR1LiEOMIpJpMP8zKeFZSdkRccg== + dependencies: + cloudform-types "^4.2.0" + graphql "^15.5.0" + graphql-mapping-template "4.20.16" + graphql-transformer-common "4.31.1" + graphql-transformer-core "8.2.13" + +graphql-http-transformer@5.2.80: + version "5.2.80" + resolved "https://registry.npmjs.org/graphql-http-transformer/-/graphql-http-transformer-5.2.80.tgz#4b84b31a8bcfa4e7ff11ca72e5e99436d08eef72" + integrity sha512-a5Km3dRWi8EfEIXLNgEH2XnzBpFqRoUI6+/md+MAR0pXyO3mNTUjAT1OSfsmQuYESpqvVhxG8BmOZp35AErZ/A== + dependencies: + cloudform-types "^4.2.0" + graphql "^15.5.0" + graphql-mapping-template "4.20.16" + graphql-transformer-common "4.31.1" + graphql-transformer-core "8.2.13" + graphql-import@^0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/graphql-import/-/graphql-import-0.7.1.tgz#4add8d91a5f752d764b0a4a7a461fcd93136f223" @@ -14058,10 +12731,29 @@ graphql-import@^0.7.1: lodash "^4.17.4" resolve-from "^4.0.0" -graphql-iso-date@^3.6.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/graphql-iso-date/-/graphql-iso-date-3.6.1.tgz#bd2d0dc886e0f954cbbbc496bbf1d480b57ffa96" - integrity sha512-AwFGIuYMJQXOEAgRlJlFL4H1ncFM8n8XmoVDTNypNOZyQ8LFDG2ppMFlsS862BSTCDcSUfHp8PD3/uJhv7t59Q== +graphql-key-transformer@3.2.80: + version "3.2.80" + resolved "https://registry.npmjs.org/graphql-key-transformer/-/graphql-key-transformer-3.2.80.tgz#918f8c440e7c51651b8d978e8857893d37e2b7b1" + integrity sha512-+refGi/BxpoWHs8xZ9SKyet+35hRFmpXtQM1HaYgDwzVep8Q6SYr5/5zs+2DFlYeuB19Bh23iKXu/2W6FZAGwQ== + dependencies: + cloudform-types "^4.2.0" + graphql "^15.5.0" + graphql-dynamodb-transformer "7.2.80" + graphql-mapping-template "4.20.16" + graphql-transformer-common "4.31.1" + graphql-transformer-core "8.2.13" + lodash "^4.17.21" + +graphql-predictions-transformer@3.2.80: + version "3.2.80" + resolved "https://registry.npmjs.org/graphql-predictions-transformer/-/graphql-predictions-transformer-3.2.80.tgz#e4df8bf333bac6cb894d23da53fe44f4a8be1eef" + integrity sha512-bo6ko/qMGFp1OE8HeJagVpUWTFErPYB/uTnqLOKdzMc3qreycizC2F6WhGEsLEXNdhkhC+gTmtCDEZFxEEyQ0Q== + dependencies: + cloudform-types "^4.2.0" + graphql "^15.5.0" + graphql-mapping-template "4.20.16" + graphql-transformer-common "4.31.1" + graphql-transformer-core "8.2.13" graphql-request@^1.5.0: version "1.8.2" @@ -14070,20 +12762,23 @@ graphql-request@^1.5.0: dependencies: cross-fetch "2.2.2" -graphql-subscriptions@^1.1.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/graphql-subscriptions/-/graphql-subscriptions-1.2.1.tgz#2142b2d729661ddf967b7388f7cf1dd4cf2e061d" - integrity sha512-95yD/tKi24q8xYa7Q9rhQN16AYj5wPbrb8tmHGM3WRc9EBmWrG/0kkMl+tQG8wcEuE9ibR4zyOM31p5Sdr2v4g== - dependencies: - iterall "^1.3.0" - -graphql-tag@^2.10.1, graphql-tag@^2.11.0: +graphql-tag@^2.10.1: version "2.12.6" resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== dependencies: tslib "^2.1.0" +graphql-versioned-transformer@5.2.80: + version "5.2.80" + resolved "https://registry.npmjs.org/graphql-versioned-transformer/-/graphql-versioned-transformer-5.2.80.tgz#cec826cf091b64d1f44ab12e42d4c35f2cc5612d" + integrity sha512-8fmuuTRZ9v4syn1cjUQOnRaZidpch7Ximq9bbpj4wsdcZbgSquRnodtyGVlIuHp8irMbAxX5TnDlvpSf2k71qw== + dependencies: + graphql "^15.5.0" + graphql-mapping-template "4.20.16" + graphql-transformer-common "4.31.1" + graphql-transformer-core "8.2.13" + graphql@15.8.0, graphql@^15.5.0: version "15.8.0" resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.8.0.tgz#33410e96b012fa3bdb1091cc99a94769db212b38" @@ -14094,18 +12789,6 @@ growly@^1.3.0: resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw== -gunzip-maybe@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/gunzip-maybe/-/gunzip-maybe-1.4.2.tgz#b913564ae3be0eda6f3de36464837a9cd94b98ac" - integrity sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw== - dependencies: - browserify-zlib "^0.1.4" - is-deflate "^1.0.0" - is-gzip "^1.0.0" - peek-stream "^1.1.0" - pumpify "^1.3.3" - through2 "^2.0.3" - gzip-size@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" @@ -14113,18 +12796,6 @@ gzip-size@^6.0.0: dependencies: duplexer "^0.1.2" -handlebars@4.7.7: - version "4.7.7" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" - integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== - dependencies: - minimist "^1.2.5" - neo-async "^2.6.0" - source-map "^0.6.1" - wordwrap "^1.0.0" - optionalDependencies: - uglify-js "^3.1.4" - handlebars@^4.7.7: version "4.7.8" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" @@ -14234,22 +12905,6 @@ has@^1.0.3: resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6" integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ== -hash.js@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -header-case@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/header-case/-/header-case-2.0.4.tgz#5a42e63b55177349cf405beb8d775acabb92c063" - integrity sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q== - dependencies: - capital-case "^1.0.4" - tslib "^2.0.3" - hjson@^3.2.1, hjson@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/hjson/-/hjson-3.2.2.tgz#a5a81138f4c0bb427e4b2ac917fafd4b454436cf" @@ -14305,17 +12960,6 @@ http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== -http-errors@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" - integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== - dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" - http-proxy-agent@^4.0.0, http-proxy-agent@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" @@ -14490,11 +13134,6 @@ immutable-tuple@^0.4.9: resolved "https://registry.yarnpkg.com/immutable-tuple/-/immutable-tuple-0.4.10.tgz#e0b1625384f514084a7a84b749a3bb26e9179929" integrity sha512-45jheDbc3Kr5Cw8EtDD+4woGRUV0utIrJBZT8XH0TPZRfm8tzT0/sLGGzyyCCFqFMG5Pv5Igf3WY/arn6+8V9Q== -immutable@~3.7.6: - version "3.7.6" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b" - integrity sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw== - import-fresh@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" @@ -14511,24 +13150,10 @@ import-fresh@^3.0.0, import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" -import-from@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/import-from/-/import-from-4.0.0.tgz#2710b8d66817d232e16f4166e319248d3d5492e2" - integrity sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ== - -import-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/import-from/-/import-from-3.0.0.tgz#055cfec38cd5a27d8057ca51376d7d3bf0891966" - integrity sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ== - dependencies: - resolve-from "^5.0.0" - -import-global@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/import-global/-/import-global-0.1.0.tgz#97b38fd444114eec16824a935f8da575b57aa1ce" - integrity sha512-8+hPJLML+m1ym9NSeZXTXFkY5+ml0fYFAzO5yhZiaFQvk9kO0NkE7vd7e7kCVjkTmAxsDPbrWwLQACMwGTDgIg== - dependencies: - global-dirs "^0.1.0" +import-from@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/import-from/-/import-from-4.0.0.tgz#2710b8d66817d232e16f4166e319248d3d5492e2" + integrity sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ== import-lazy@^4.0.0, import-lazy@~4.0.0: version "4.0.0" @@ -14563,11 +13188,6 @@ infer-owner@^1.0.4: resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== -inflected@^2.0.4: - version "2.1.0" - resolved "https://registry.yarnpkg.com/inflected/-/inflected-2.1.0.tgz#2816ac17a570bbbc8303ca05bca8bf9b3f959687" - integrity sha512-hAEKNxvHf2Iq3H60oMBHkB4wl5jn3TPF3+fXek/sRwAB5gP9xWs4r7aweSF95f99HFoz69pnZTcu8f0SIHV18w== - inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -14576,7 +13196,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -14614,17 +13234,6 @@ init-package-json@^3.0.2: validate-npm-package-license "^3.0.4" validate-npm-package-name "^4.0.0" -inquirer-datepicker@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/inquirer-datepicker/-/inquirer-datepicker-2.0.2.tgz#eaf331a9489585b336c5bd42598c25eda32ba377" - integrity sha512-Jyb8nc383c/q2hwhTXhUyjAWV2GXHahlET/Fn/WtJWX4+05z8i4YUnNHj50f6W/5oTPy4G2/NlYNlEcZmcJC/Q== - dependencies: - chalk "^4.1.2" - cli-cursor "^3.1.0" - lodash "^4.17.21" - moment "^2.29.3" - rxjs "^7.5.5" - inquirer@^6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" @@ -14711,14 +13320,7 @@ into-stream@^6.0.0: from2 "^2.3.0" p-is-promise "^3.0.0" -invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -ip@^1.1.8, ip@^1.1.9: +ip@^1.1.8: version "1.1.9" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.9.tgz#8dfbcc99a754d07f425310b86a99546b1151e396" integrity sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ== @@ -14728,19 +13330,6 @@ ip@^2.0.0: resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105" integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ== -ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - -is-absolute@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576" - integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA== - dependencies: - is-relative "^1.0.0" - is-windows "^1.0.1" - is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -14875,11 +13464,6 @@ is-date-object@^1.0.1, is-date-object@^1.0.5: dependencies: has-tostringtag "^1.0.0" -is-deflate@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-deflate/-/is-deflate-1.0.0.tgz#c862901c3c161fb09dac7cdc7e784f80e98f2f14" - integrity sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ== - is-descriptor@^0.1.0: version "0.1.6" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" @@ -14932,11 +13516,6 @@ is-finalizationregistry@^1.0.2: dependencies: call-bind "^1.0.2" -is-finite@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" - integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== - is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" @@ -14978,11 +13557,6 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" -is-gzip@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-gzip/-/is-gzip-1.0.0.tgz#6ca8b07b99c77998025900e555ced8ed80879a83" - integrity sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ== - is-installed-globally@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" @@ -15001,13 +13575,6 @@ is-lambda@^1.0.1: resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== -is-lower-case@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-lower-case/-/is-lower-case-2.0.2.tgz#1c0884d3012c841556243483aa5d522f47396d2a" - integrity sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ== - dependencies: - tslib "^2.0.3" - is-map@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" @@ -15119,13 +13686,6 @@ is-regexp@^1.0.0: resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" integrity sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA== -is-relative@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d" - integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA== - dependencies: - is-unc-path "^1.0.0" - is-set@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" @@ -15193,25 +13753,11 @@ is-typedarray@^1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== -is-unc-path@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d" - integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ== - dependencies: - unc-path-regex "^0.1.2" - is-unicode-supported@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-upper-case@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-upper-case/-/is-upper-case-2.0.2.tgz#f1105ced1fe4de906a5f39553e7d3803fd804649" - integrity sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ== - dependencies: - tslib "^2.0.3" - is-weakmap@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" @@ -15232,7 +13778,7 @@ is-weakset@^2.0.1: call-bind "^1.0.2" get-intrinsic "^1.1.1" -is-windows@^1.0.1, is-windows@^1.0.2: +is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== @@ -15349,11 +13895,6 @@ istanbul-reports@^3.0.2: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -iterall@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" - integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== - iterator.prototype@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" @@ -15835,21 +14376,11 @@ jora@1.0.0-beta.8: dependencies: "@discoveryjs/natural-compare" "^1.0.0" -jose@^4.15.5: - version "4.15.7" - resolved "https://registry.npmjs.org/jose/-/jose-4.15.7.tgz#96ad68d786632bd03c9068aa281810dbbe1b60d8" - integrity sha512-L7ioP+JAuZe8v+T5+zVI9Tx8LtU8BL7NxkyDFVMv+Qr3JW0jSoYDedLtodaXwfqMpeCyx4WXFNyu9tJt4WvC1A== - js-cookie@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== -js-string-escape@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" - integrity sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg== - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -15908,11 +14439,6 @@ jsdom@^16.4.0: ws "^7.4.6" xml-name-validator "^3.0.0" -jsesc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - integrity sha512-Mke0DA0QjUWuJlhsE0ZPPhYiJkRap642SmI/4ztCFaUs6V2AiH1sfecc+57NgaryfAA2VR3v6O+CSjC1jZJKOA== - jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" @@ -16112,27 +14638,6 @@ jsonschema@^1.4.1: resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.1.tgz#cc4c3f0077fb4542982973d8a083b6b34f482dab" integrity sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ== -jsonwebtoken@^9.0.0: - version "9.0.2" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" - integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== - dependencies: - jws "^3.2.2" - lodash.includes "^4.3.0" - lodash.isboolean "^3.0.3" - lodash.isinteger "^4.0.4" - lodash.isnumber "^3.0.3" - lodash.isplainobject "^4.0.6" - lodash.isstring "^4.0.1" - lodash.once "^4.0.0" - ms "^2.1.1" - semver "^7.5.4" - -jstreemap@^1.28.2: - version "1.28.2" - resolved "https://registry.yarnpkg.com/jstreemap/-/jstreemap-1.28.2.tgz#fe884994039e5ee23a157cf7ddd6c01c3a6d134d" - integrity sha512-JYVDYwLat+OVXLpIXgUPy06wPSEkQafGOeotpGFodkM5+K8x3IrVPGaTw+Fd9MmZy092cLG/N+3q90oSBHZoQQ== - "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3: version "3.3.5" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" @@ -16153,33 +14658,6 @@ just-diff@^5.0.1: resolved "https://registry.yarnpkg.com/just-diff/-/just-diff-5.2.0.tgz#60dca55891cf24cd4a094e33504660692348a241" integrity sha512-6ufhP9SHjb7jibNFrNxyFZ6od3g+An6Ai9mhGRvcYe8UJlH0prseN64M+6ZBBUoKYHZsitDP42gAJ8+eVWr3lw== -just-extend@^4.0.2: - version "4.2.1" - resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.2.1.tgz#ef5e589afb61e5d66b24eca749409a8939a8c744" - integrity sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg== - -jwa@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" - integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== - dependencies: - buffer-equal-constant-time "1.0.1" - ecdsa-sig-formatter "1.0.11" - safe-buffer "^5.0.1" - -jws@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" - integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== - dependencies: - jwa "^1.4.1" - safe-buffer "^5.0.1" - -jwt-decode@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-2.2.0.tgz#7d86bd56679f58ce6a84704a657dd392bba81a79" - integrity sha512-86GgN2vzfUu7m9Wcj63iUkuDzFNYFVmjeDm2GzWpUk+opB0pEpMsw6ePCMrhYkumz2C1ihqtZzOMAg7FiXcNoQ== - keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -16538,46 +15016,21 @@ lodash.get@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== -lodash.includes@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" - integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== - -lodash.isboolean@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" - integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== - lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== -lodash.isinteger@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" - integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== - lodash.ismatch@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" integrity sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g== -lodash.isnumber@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" - integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== - lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== -lodash.isstring@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" - integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== - lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -16593,16 +15046,6 @@ lodash.mergewith@^4.6.2: resolved "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== -lodash.once@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" - integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== - -lodash.throttle@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" - integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ== - lodash.truncate@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" @@ -16618,7 +15061,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== -lodash@4.x, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.7.0, lodash@~4.17.0, lodash@~4.17.15: +lodash@4.x, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.2.1, lodash@^4.7.0, lodash@~4.17.15: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -16676,13 +15119,6 @@ log4js@^6.9.1: rfdc "^1.3.0" streamroller "^3.1.5" -logdown@^3.3.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/logdown/-/logdown-3.3.1.tgz#836d5a195b5949c6db631ccc9fecce0492e01d10" - integrity sha512-pjX0vlIJsYQlgVzFba2amXI1wZZnhrEorL68MdLI7B0/sN1TNUozBNFaHfcPHMM3A+INZ0OXFDxtnoaEgOmGjQ== - dependencies: - chalk "^2.3.0" - logform@^2.3.2, logform@^2.4.0: version "2.5.1" resolved "https://registry.yarnpkg.com/logform/-/logform-2.5.1.tgz#44c77c34becd71b3a42a3970c77929e52c6ed48b" @@ -16700,27 +15136,13 @@ long@^5.2.1: resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== dependencies: js-tokens "^3.0.0 || ^4.0.0" -lower-case-first@^2.0.1, lower-case-first@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/lower-case-first/-/lower-case-first-2.0.2.tgz#64c2324a2250bf7c37c5901e76a5b5309301160b" - integrity sha512-EVm/rR94FJTZi3zefZ82fLWab+GX14LJN4HrWBcuo6Evmsl9hEfnqxgcHCKb9q+mNf6EVdsjx/qucYFIIB84pg== - dependencies: - tslib "^2.0.3" - -lower-case@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" - integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== - dependencies: - tslib "^2.0.3" - lowercase-keys@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" @@ -16777,7 +15199,7 @@ make-dir@^4.0.0: dependencies: semver "^7.5.3" -make-error@1.x, make-error@^1.1.1, make-error@^1.3.2: +make-error@1.x, make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== @@ -16832,7 +15254,7 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" -map-cache@^0.2.0, map-cache@^0.2.2: +map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== @@ -16873,11 +15295,6 @@ mdurl@~1.0.1: resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g== -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== - meow@^8.0.0: version "8.1.2" resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" @@ -16895,11 +15312,6 @@ meow@^8.0.0: type-fest "^0.18.0" yargs-parser "^20.2.3" -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== - merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -16910,11 +15322,6 @@ merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== - micromatch@4.0.5, micromatch@^4.0.2, micromatch@^4.0.4: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" @@ -16947,18 +15354,13 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@^2.1.27: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" -mime@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" @@ -16989,11 +15391,6 @@ min-indent@^1.0.0: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== -minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - minimatch@3.0.5: version "3.0.5" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.5.tgz#4da8f1290ee0f0f8e83d60ca69f8f134068604a3" @@ -17008,7 +15405,7 @@ minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatc dependencies: brace-expansion "^1.1.7" -minimatch@^5.0.1, minimatch@^5.1.0, minimatch@~5.1.2: +minimatch@^5.0.1, minimatch@^5.1.0: version "5.1.6" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== @@ -17170,19 +15567,14 @@ modify-values@^1.0.0: resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== -moment-jdateformatparser@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/moment-jdateformatparser/-/moment-jdateformatparser-1.2.1.tgz#336c41ef7a6db8021d7ca086385a35fb8a648456" - integrity sha512-lpUeQtMaxmpK+pPPHGWMnqzgsB/nunbAGPg72mzvRNbxxeQ2uBurdq9EJmvJtOiYB6k/4T9kuvQFbb+8Tirn4A== - -moment-timezone@0.5.35, moment-timezone@^0.5.35: +moment-timezone@^0.5.35: version "0.5.45" resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.45.tgz#cb685acd56bac10e69d93c536366eb65aa6bcf5c" integrity sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ== dependencies: moment "^2.29.4" -moment@^2.24.0, moment@^2.29.1, moment@^2.29.3: +moment@^2.24.0, moment@^2.29.1: version "2.29.4" resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== @@ -17202,7 +15594,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.0.0, ms@^2.1.1: +ms@^2.0.0, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -17306,12 +15698,12 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -negotiator@0.6.3, negotiator@^0.6.3: +negotiator@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== -neo-async@^2.6.0, neo-async@^2.6.2: +neo-async@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== @@ -17326,25 +15718,6 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -nise@^5.1.2: - version "5.1.4" - resolved "https://registry.yarnpkg.com/nise/-/nise-5.1.4.tgz#491ce7e7307d4ec546f5a659b2efe94a18b4bbc0" - integrity sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg== - dependencies: - "@sinonjs/commons" "^2.0.0" - "@sinonjs/fake-timers" "^10.0.2" - "@sinonjs/text-encoding" "^0.7.1" - just-extend "^4.0.2" - path-to-regexp "^1.7.0" - -no-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" - integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== - dependencies: - lower-case "^2.0.2" - tslib "^2.0.3" - node-abi@^3.3.0: version "3.49.0" resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.49.0.tgz#b0267a615f58939886ddb8324bfbe21bfc0482a9" @@ -17731,11 +16104,6 @@ nth-check@^2.0.1: dependencies: boolbase "^1.0.0" -nullthrows@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" - integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== - number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" @@ -17797,7 +16165,7 @@ nx@15.9.7, "nx@>=14.8.1 < 16": "@nrwl/nx-win32-arm64-msvc" "15.9.7" "@nrwl/nx-win32-x64-msvc" "15.9.7" -object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== @@ -17831,15 +16199,6 @@ object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object-to-xml@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/object-to-xml/-/object-to-xml-2.0.0.tgz#3349b60a381a3ada47b0faef54dcd2b1657d150f" - integrity sha512-bArXy7WCF1V9R88/zF9adSZSeFQnFmmKhMqNuNLAxqrbkvzcWP8HgnaRCcVJsfvIgvpdHiYd0qzJi7LM7QFfcQ== - dependencies: - dank-each "^1.0.0" - dank-map "~0.1.0" - sanitizer "0.1.3" - object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" @@ -17914,13 +16273,6 @@ obliterator@^1.6.1: resolved "https://registry.npmjs.org/obliterator/-/obliterator-1.6.1.tgz#dea03e8ab821f6c4d96a299e17aef6a3af994ef3" integrity sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig== -on-finished@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -18265,19 +16617,6 @@ pako@^2.0.4: resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86" integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug== -pako@~0.2.0: - version "0.2.9" - resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" - integrity sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA== - -param-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" - integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== - dependencies: - dot-case "^3.0.4" - tslib "^2.0.3" - parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -18294,15 +16633,6 @@ parse-conflict-json@^2.0.1: just-diff "^5.0.1" just-diff-apply "^5.2.0" -parse-filepath@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891" - integrity sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q== - dependencies: - is-absolute "^1.0.0" - map-cache "^0.2.0" - path-root "^0.1.1" - parse-github-url@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/parse-github-url/-/parse-github-url-1.0.2.tgz#242d3b65cbcdda14bb50439e3242acf6971db395" @@ -18345,32 +16675,11 @@ parse5@6.0.1: resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== -parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -pascal-case@^3.1.1, pascal-case@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" - integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== -path-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/path-case/-/path-case-3.0.4.tgz#9168645334eb942658375c56f80b4c0cb5f82c6f" - integrity sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg== - dependencies: - dot-case "^3.0.4" - tslib "^2.0.3" - path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -18406,18 +16715,6 @@ path-parse@^1.0.6, path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-root-regex@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" - integrity sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ== - -path-root@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7" - integrity sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg== - dependencies: - path-root-regex "^0.1.0" - path-scurry@^1.10.1: version "1.10.1" resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" @@ -18426,18 +16723,6 @@ path-scurry@^1.10.1: lru-cache "^9.1.1 || ^10.0.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== - -path-to-regexp@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" - integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== - dependencies: - isarray "0.0.1" - path-type@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -18450,15 +16735,6 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -peek-stream@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/peek-stream/-/peek-stream-1.1.3.tgz#3b35d84b7ccbbd262fff31dc10da56856ead6d67" - integrity sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA== - dependencies: - buffer-from "^1.0.0" - duplexify "^3.5.0" - through2 "^2.0.3" - pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -18926,11 +17202,6 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier@^1.19.1: - version "1.19.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" - integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== - prettier@^2.8.8: version "2.8.8" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" @@ -18999,25 +17270,6 @@ promise-retry@^2.0.1: err-code "^2.0.2" retry "^0.12.0" -promise-sequential@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/promise-sequential/-/promise-sequential-1.1.1.tgz#f79e8950ef86e7a7a85bf320452643592f6d2fb2" - integrity sha512-gpziThEJPnPEeaHNqjy9f4PE1JwXb07fX3dz+41nhALpIAaEI9VZU8Q89eyBBAa2xAhnz0KgUTDtCA7FZYbZQQ== - -promise-toolbox@^0.20.0: - version "0.20.0" - resolved "https://registry.yarnpkg.com/promise-toolbox/-/promise-toolbox-0.20.0.tgz#af04d7338038c2362b8fb7c27546c57d893bf562" - integrity sha512-VXF6waqUheD19yOU7zxsXhw/HCKlXqXwUc4jM8mchtBqZFNA+GHA7dbJsQDLHP4IUpQuTLpCQRd0lCr5z4CqXQ== - dependencies: - make-error "^1.3.2" - -promise@^7.1.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" - integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== - dependencies: - asap "~2.0.3" - prompts-ncu@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/prompts-ncu/-/prompts-ncu-3.0.0.tgz#716feb4874fca3dbe00af0f3de17a15d43d2228d" @@ -19060,14 +17312,6 @@ protocols@^2.0.0, protocols@^2.0.1: resolved "https://registry.yarnpkg.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86" integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q== -proxy-addr@~2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" - integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.1" - proxy-agent@^6.3.0: version "6.3.1" resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.3.1.tgz#40e7b230552cf44fd23ffaf7c59024b692612687" @@ -19092,14 +17336,6 @@ psl@^1.1.33: resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== -pump@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" - integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -19108,15 +17344,6 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -pumpify@^1.3.3: - version "1.5.1" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" - integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== - dependencies: - duplexify "^3.6.0" - inherits "^2.0.3" - pump "^2.0.0" - punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" @@ -19149,13 +17376,6 @@ q@^1.5.1: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== -qs@6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== - dependencies: - side-channel "^1.0.4" - qs@^6.11.2: version "6.11.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" @@ -19195,21 +17415,6 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" -range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.5.2: - version "2.5.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" - integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - rc-config-loader@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/rc-config-loader/-/rc-config-loader-4.1.3.tgz#1352986b8a2d8d96d6fd054a5bb19a60c576876a" @@ -19445,11 +17650,6 @@ reflect.getprototypeof@^1.0.4: globalthis "^1.0.3" which-builtin-type "^1.1.3" -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== - regenerator-runtime@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" @@ -19486,15 +17686,6 @@ registry-url@^6.0.0: dependencies: rc "1.2.8" -relay-runtime@12.0.0: - version "12.0.0" - resolved "https://registry.yarnpkg.com/relay-runtime/-/relay-runtime-12.0.0.tgz#1e039282bdb5e0c1b9a7dc7f6b9a09d4f4ff8237" - integrity sha512-QU6JKr1tMsry22DXNy9Whsq5rmvwr3LSZiiWV/9+DFpuTWvp+WFhobWMc8TC4OjKFfNhEZy7mOiqUAn5atQtug== - dependencies: - "@babel/runtime" "^7.0.0" - fbjs "^3.0.0" - invariant "^2.2.4" - remote-git-tags@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/remote-git-tags/-/remote-git-tags-3.0.0.tgz#424f8ec2cdea00bb5af1784a49190f25e16983c3" @@ -19505,13 +17696,6 @@ remove-trailing-separator@^1.0.1: resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" integrity sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw== -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A== - dependencies: - is-finite "^1.0.0" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -19727,7 +17911,7 @@ safe-array-concat@^1.0.1: has-symbols "^1.0.3" isarray "^2.0.5" -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -19778,17 +17962,12 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -sanitizer@0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/sanitizer/-/sanitizer-0.1.3.tgz#d4f0af7475d9a7baf2a9e5a611718baa178a39e1" - integrity sha512-j05vL56tR90rsYqm9ZD05v6K4HI7t4yMDEvvU0x4f+IADXM9Jx1x9mzatxOs5drJq6dGhugxDW99mcPvXVLl+Q== - sax@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" integrity sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA== -sax@>=0.6.0, sax@^1.2.4: +sax@>=0.6.0: version "1.3.0" resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0" integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA== @@ -19866,34 +18045,6 @@ semver-utils@^1.1.4: dependencies: lru-cache "^6.0.0" -send@0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== - dependencies: - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "2.0.0" - mime "1.6.0" - ms "2.1.3" - on-finished "2.4.1" - range-parser "~1.2.1" - statuses "2.0.1" - -sentence-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-3.0.4.tgz#3645a7b8c117c787fde8702056225bb62a45131f" - integrity sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - upper-case-first "^2.0.2" - seq-queue@^0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" @@ -19906,16 +18057,6 @@ serialize-javascript@^6.0.0, serialize-javascript@^6.0.1: dependencies: randombytes "^2.1.0" -serve-static@1.15.0, serve-static@^1.14.2: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.18.0" - set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -19945,11 +18086,6 @@ setimmediate@^1.0.5: resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - shallow-clone@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" @@ -20014,11 +18150,6 @@ signal-exit@^4.0.1: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== -signedsource@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/signedsource/-/signedsource-1.0.0.tgz#1ddace4981798f93bd833973803d80d52e93ad6a" - integrity sha512-6+eerH9fEnNmi/hyM1DXcRK3pWdoMQtlkQ+ns0ntzunjKqp5i3sKCc80ym8Fib3iaYhdJUOPdhlJWj1tvge2Ww== - sigstore@^1.3.0: version "1.9.0" resolved "https://registry.yarnpkg.com/sigstore/-/sigstore-1.9.0.tgz#1e7ad8933aa99b75c6898ddd0eeebc3eb0d59875" @@ -20060,18 +18191,6 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" -sinon@^14.0.1: - version "14.0.2" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-14.0.2.tgz#585a81a3c7b22cf950762ac4e7c28eb8b151c46f" - integrity sha512-PDpV0ZI3ZCS3pEqx0vpNp6kzPhHrLx72wA0G+ZLaaJjLIYeE0n8INlgaohKuGy7hP0as5tbUd23QWu5U233t+w== - dependencies: - "@sinonjs/commons" "^2.0.0" - "@sinonjs/fake-timers" "^9.1.2" - "@sinonjs/samsam" "^7.0.1" - diff "^5.0.0" - nise "^5.1.2" - supports-color "^7.2.0" - sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" @@ -20127,14 +18246,6 @@ smart-buffer@^4.2.0: resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== -snake-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" - integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== - dependencies: - dot-case "^3.0.4" - tslib "^2.0.3" - snapdragon@^0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" @@ -20214,7 +18325,7 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.16, source-map-support@^0.5.17, source-map-support@^0.5.21, source-map-support@^0.5.6, source-map-support@~0.5.20: +source-map-support@^0.5.17, source-map-support@^0.5.21, source-map-support@^0.5.6, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -20227,7 +18338,7 @@ source-map-url@^0.4.0: resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== -source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: +source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== @@ -20311,13 +18422,6 @@ split@^1.0.0: dependencies: through "2" -sponge-case@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/sponge-case/-/sponge-case-1.0.1.tgz#260833b86453883d974f84854cdb63aecc5aef4c" - integrity sha512-dblb9Et4DAtiZ5YSUZHLl4XhH4uK80GhAZrVXdN4O2P4gQ40Wa5UIOPUHlA/nFd2PLblBZWUioLMMAVrgpoYcA== - dependencies: - tslib "^2.0.3" - sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -20367,11 +18471,6 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -statuses@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" - integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== - stream-browserify@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" @@ -20411,11 +18510,6 @@ stream-meter@^1.0.4: dependencies: readable-stream "^2.1.4" -stream-shift@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" - integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== - streamroller@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.1.5.tgz#1263182329a45def1ffaef58d31b15d13d2ee7ff" @@ -20425,11 +18519,6 @@ streamroller@^3.1.5: debug "^4.3.4" fs-extra "^8.1.0" -streamsearch@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" - integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== - string-argv@0.3.2, string-argv@^0.3.0, string-argv@~0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" @@ -20679,7 +18768,7 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^7.0.0, supports-color@^7.1.0, supports-color@^7.2.0: +supports-color@^7.0.0, supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -20719,13 +18808,6 @@ svgo@^2.7.0: picocolors "^1.0.0" stable "^0.1.8" -swap-case@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/swap-case/-/swap-case-2.0.2.tgz#671aedb3c9c137e2985ef51c51f9e98445bf70d9" - integrity sha512-kc6S2YS/2yXbtkSMunBtKdah4VFETZ8Oh6ONSmSd9bRxhqTrtARUCBUiWXH3xVPpvR7tz2CSnkuXVE42EcGnMw== - dependencies: - tslib "^2.0.3" - symbol-observable@^1.0.2, symbol-observable@^1.0.3, symbol-observable@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" @@ -20864,7 +18946,7 @@ throat@^5.0.0: resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== -through2@^2.0.0, through2@^2.0.1, through2@^2.0.3: +through2@^2.0.0, through2@^2.0.1: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== @@ -20889,13 +18971,6 @@ tildify@2.0.0: resolved "https://registry.yarnpkg.com/tildify/-/tildify-2.0.0.tgz#f205f3674d677ce698b7067a99e949ce03b4754a" integrity sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw== -title-case@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/title-case/-/title-case-3.0.3.tgz#bc689b46f02e411f1d1e1d081f7c3deca0489982" - integrity sha512-e1zGYRvbffpcHIrnuqT0Dh+gEJtDaxDSoG4JAIpq4oDFyooziLBIiYQv0GBT4FUAnUop5uZ1hiIAj7oAF6sOCA== - dependencies: - tslib "^2.0.3" - tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -20915,11 +18990,6 @@ tmpl@1.0.5: resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== -to-fast-properties@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" - integrity sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og== - to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -20949,11 +19019,6 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - tough-cookie@^4.0.0: version "4.1.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" @@ -20976,11 +19041,6 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== -traverse@^0.6.6: - version "0.6.7" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.7.tgz#46961cd2d57dd8706c36664acde06a248f1173fe" - integrity sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg== - treeverse@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/treeverse/-/treeverse-2.0.0.tgz#036dcef04bc3fd79a9b79a68d4da03e882d8a9ca" @@ -20991,21 +19051,11 @@ trim-newlines@^3.0.0, trim-newlines@^3.0.1: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw== - triple-beam@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984" integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== -ts-dedent@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-1.2.0.tgz#6aa2229d837159bb6d635b6b233002423b91e0b0" - integrity sha512-6zSJp23uQI+Txyz5LlXMXAHpUhY4Hi0oluXny0OgIR7g/Cromq4vDBnhtbBdyIV34g0pgwxUvnvg+jLJe4c1NA== - ts-dedent@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" @@ -21088,31 +19138,11 @@ tslib@^1.10.0, tslib@^1.11.1, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1 resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.2: +tslib@^2.0.0, tslib@^2.0.1, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== -tslib@~2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c" - integrity sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ== - -tslib@~2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" - integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== - -tslib@~2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== - -tslib@~2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" - integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== - tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" @@ -21143,7 +19173,7 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" -type-detect@4.0.8, type-detect@^4.0.8: +type-detect@4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== @@ -21188,14 +19218,6 @@ type-fest@^2.13.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== -type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - typed-array-buffer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" @@ -21290,17 +19312,12 @@ typescript@~5.4: resolved "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== -ua-parser-js@^1.0.35: - version "1.0.36" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.36.tgz#a9ab6b9bd3a8efb90bb0816674b412717b7c428c" - integrity sha512-znuyCIXzl8ciS3+y3fHJI/2OhQIXbXw9MWC/o3qwyR+RGppjZHrM27CGFSKCJXi2Kctiz537iOu2KnXs1lMQhw== - uglify-js@^3.1.4: version "3.17.4" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== -ulid@2.3.0, ulid@^2.3.0: +ulid@2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/ulid/-/ulid-2.3.0.tgz#93063522771a9774121a84d126ecd3eb9804071f" integrity sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw== @@ -21315,11 +19332,6 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -unc-path-regex@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" - integrity sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg== - undici-types@~5.25.1: version "5.25.3" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.25.3.tgz#e044115914c85f0bcbb229f346ab739f064998c3" @@ -21408,11 +19420,6 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== - unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" @@ -21459,20 +19466,6 @@ update-notifier@^6.0.2: semver-diff "^4.0.0" xdg-basedir "^5.1.0" -upper-case-first@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324" - integrity sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg== - dependencies: - tslib "^2.0.3" - -upper-case@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-2.0.2.tgz#d89810823faab1df1549b7d97a76f8662bae6f7a" - integrity sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg== - dependencies: - tslib "^2.0.3" - uri-js@^4.2.2, uri-js@^4.4.1: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -21516,11 +19509,6 @@ urlgrey@1.0.0: dependencies: fast-url-parser "^1.1.3" -urlpattern-polyfill@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-9.0.0.tgz#bc7e386bb12fd7898b58d1509df21d3c29ab3460" - integrity sha512-WHN8KDQblxd32odxeIgo83rdVDE2bvdkb86it7bMhYZwWKJz0+O0RK/eZiHYnM+zgt/U7hAHOlCQGfjjvSkw2g== - use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" @@ -21542,11 +19530,6 @@ util@^0.12.4: is-typed-array "^1.1.3" which-typed-array "^1.1.2" -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== - uuid@3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" @@ -21625,21 +19608,6 @@ validator@^13.7.0: resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b" integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ== -value-or-promise@1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.11.tgz#3e90299af31dd014fe843fe309cefa7c1d94b140" - integrity sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg== - -value-or-promise@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.12.tgz#0e5abfeec70148c78460a849f6b003ea7986f15c" - integrity sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q== - -vary@^1, vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== - w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" @@ -21654,15 +19622,6 @@ w3c-xmlserializer@^2.0.0: dependencies: xml-name-validator "^3.0.0" -wait-port@^0.2.7: - version "0.2.14" - resolved "https://registry.yarnpkg.com/wait-port/-/wait-port-0.2.14.tgz#6df40629be2c95aa4073ceb895abef7d872b28c6" - integrity sha512-kIzjWcr6ykl7WFbZd0TMae8xovwqcqbx6FM9l+7agOgUByhzdjfzZBPK2CPufldTOMxbUivss//Sh9MFawmPRQ== - dependencies: - chalk "^2.4.2" - commander "^3.0.2" - debug "^4.1.1" - walk-up-path@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/walk-up-path/-/walk-up-path-1.0.0.tgz#d4745e893dd5fd0dbb58dd0a4c6a33d9c9fec53e" @@ -22025,11 +19984,6 @@ ws@^7.4.6, ws@^7.5.7: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== -ws@^8.5.0: - version "8.17.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" - integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== - xcode@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/xcode/-/xcode-2.1.0.tgz#bab64a7e954bb50ca8d19da7e09531c65a43ecfe" @@ -22043,13 +19997,6 @@ xdg-basedir@^5.0.1, xdg-basedir@^5.1.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-5.1.0.tgz#1efba19425e73be1bc6f2a6ceb52a3d2c884c0c9" integrity sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ== -xml-js@^1.6.11: - version "1.6.11" - resolved "https://registry.yarnpkg.com/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9" - integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g== - dependencies: - sax "^1.2.4" - xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" @@ -22083,11 +20030,6 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -xstate@^4.14.0: - version "4.38.2" - resolved "https://registry.yarnpkg.com/xstate/-/xstate-4.38.2.tgz#1b74544fc9c8c6c713ba77f81c6017e65aa89804" - integrity sha512-Fba/DwEPDLneHT3tbJ9F3zafbQXszOlyCJyQqqdzmtlY/cwE2th462KK48yaANf98jHlP6lJvxfNtN0LFKXPQg== - xtend@^4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -22151,7 +20093,7 @@ yargs-parser@^18.1.2: camelcase "^5.0.0" decamelize "^1.2.0" -yargs@^15.1.0, yargs@^15.3.1, yargs@^15.4.1: +yargs@^15.1.0, yargs@^15.4.1: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== From e999c2d782f097569a1f7b5e57d3c833b6be447c Mon Sep 17 00:00:00 2001 From: Doesnt Matter Date: Mon, 5 Aug 2024 19:31:40 -0700 Subject: [PATCH 14/23] chore: consume appsync simulator for tests --- codebuild_specs/e2e_workflow.yml | 45 +- .../package.json | 9 +- .../NoneEnvFunctionTransformer.e2e.test.ts | 176 ------- .../tsconfig.tests.json | 11 +- yarn.lock | 487 ++++++++++++++++-- 5 files changed, 467 insertions(+), 261 deletions(-) delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/NoneEnvFunctionTransformer.e2e.test.ts diff --git a/codebuild_specs/e2e_workflow.yml b/codebuild_specs/e2e_workflow.yml index 8ec02944d0..43a7ef9470 100644 --- a/codebuild_specs/e2e_workflow.yml +++ b/codebuild_specs/e2e_workflow.yml @@ -1810,111 +1810,110 @@ batch: depend-on: - publish_to_local_registry - identifier: >- - PerFieldAuthTests_NoneEnvFunctionTransformer_MutationCondition_DefaultValueTransformer + PerFieldAuthTests_MutationCondition_DefaultValueTransformer_PerFieldAuthV2TransformerWithFF buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/PerFieldAuthTests.e2e.test.ts|src/__tests__/NoneEnvFunctionTransformer.e2e.test.ts|src/__tests__/MutationCondition.e2e.test.ts|src/__tests__/DefaultValueTransformer.e2e.test.ts - CLI_REGION: ap-south-1 + src/__tests__/PerFieldAuthTests.e2e.test.ts|src/__tests__/MutationCondition.e2e.test.ts|src/__tests__/DefaultValueTransformer.e2e.test.ts|src/__tests__/PerFieldAuthV2TransformerWithFF.e2e.test.ts + CLI_REGION: ap-southeast-1 depend-on: - publish_to_local_registry - identifier: >- - PerFieldAuthV2TransformerWithFF_PerFieldAuthV2Transformer_BelongsToTransformerV2_RelationalWithAuthV2WithFF + PerFieldAuthV2Transformer_BelongsToTransformerV2_RelationalWithAuthV2WithFF_IndexWithAuthV2 buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/PerFieldAuthV2TransformerWithFF.e2e.test.ts|src/__tests__/PerFieldAuthV2Transformer.e2e.test.ts|src/__tests__/BelongsToTransformerV2.e2e.test.ts|src/__tests__/RelationalWithAuthV2WithFF.e2e.test.ts + src/__tests__/PerFieldAuthV2Transformer.e2e.test.ts|src/__tests__/BelongsToTransformerV2.e2e.test.ts|src/__tests__/RelationalWithAuthV2WithFF.e2e.test.ts|src/__tests__/IndexWithAuthV2.e2e.test.ts CLI_REGION: ap-southeast-2 depend-on: - publish_to_local_registry - identifier: >- - IndexWithAuthV2_IndexWithAuthV2WithFF_SubscriptionsWithAuthV2WithFF_MultiAuthV2Transformer + IndexWithAuthV2WithFF_SubscriptionsWithAuthV2WithFF_MultiAuthV2Transformer_ModelTransformer buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/IndexWithAuthV2.e2e.test.ts|src/__tests__/IndexWithAuthV2WithFF.e2e.test.ts|src/__tests__/SubscriptionsWithAuthV2WithFF.e2e.test.ts|src/__tests__/MultiAuthV2Transformer.e2e.test.ts + src/__tests__/IndexWithAuthV2WithFF.e2e.test.ts|src/__tests__/SubscriptionsWithAuthV2WithFF.e2e.test.ts|src/__tests__/MultiAuthV2Transformer.e2e.test.ts|src/__tests__/ModelTransformer.e2e.test.ts CLI_REGION: ca-central-1 depend-on: - publish_to_local_registry - identifier: >- - ModelTransformer_SubscriptionsWithAuthV2_RelationalWithAuthV2_MapsToTransformer + SubscriptionsWithAuthV2_RelationalWithAuthV2_MapsToTransformer_MultiAuthV2TransformerWithFF buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/ModelTransformer.e2e.test.ts|src/__tests__/SubscriptionsWithAuthV2.e2e.test.ts|src/__tests__/RelationalWithAuthV2.e2e.test.ts|src/__tests__/MapsToTransformer.e2e.test.ts + src/__tests__/SubscriptionsWithAuthV2.e2e.test.ts|src/__tests__/RelationalWithAuthV2.e2e.test.ts|src/__tests__/MapsToTransformer.e2e.test.ts|src/__tests__/MultiAuthV2TransformerWithFF.e2e.test.ts CLI_REGION: eu-central-1 depend-on: - publish_to_local_registry - identifier: >- - MultiAuthV2TransformerWithFF_AuthV2Transformer_AuthV2ExhaustiveT1B_AuthV2ExhaustiveT1A + AuthV2Transformer_AuthV2ExhaustiveT1B_AuthV2ExhaustiveT1A_AuthV2TransformerWithFF buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/MultiAuthV2TransformerWithFF.e2e.test.ts|src/__tests__/AuthV2Transformer.e2e.test.ts|src/__tests__/AuthV2ExhaustiveT1B.test.ts|src/__tests__/AuthV2ExhaustiveT1A.test.ts + src/__tests__/AuthV2Transformer.e2e.test.ts|src/__tests__/AuthV2ExhaustiveT1B.test.ts|src/__tests__/AuthV2ExhaustiveT1A.test.ts|src/__tests__/AuthV2TransformerWithFF.e2e.test.ts CLI_REGION: eu-north-1 depend-on: - publish_to_local_registry - identifier: >- - AuthV2TransformerWithFF_SubscriptionsRuntimeFiltering_AuthV2ExhaustiveT2A_AuthV2ExhaustiveT1C + SubscriptionsRuntimeFiltering_AuthV2ExhaustiveT2A_AuthV2ExhaustiveT1C_AuthV2ExhaustiveT1D buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/AuthV2TransformerWithFF.e2e.test.ts|src/__tests__/SubscriptionsRuntimeFiltering.e2e.test.ts|src/__tests__/AuthV2ExhaustiveT2A.test.ts|src/__tests__/AuthV2ExhaustiveT1C.test.ts + src/__tests__/SubscriptionsRuntimeFiltering.e2e.test.ts|src/__tests__/AuthV2ExhaustiveT2A.test.ts|src/__tests__/AuthV2ExhaustiveT1C.test.ts|src/__tests__/AuthV2ExhaustiveT1D.test.ts CLI_REGION: eu-south-1 depend-on: - publish_to_local_registry - identifier: >- - AuthV2ExhaustiveT1D_AuthV2ExhaustiveT2B_AuthV2ExhaustiveT2D_AuthV2ExhaustiveT2C + AuthV2ExhaustiveT2B_AuthV2ExhaustiveT2D_AuthV2ExhaustiveT2C_RelationalWithAuthV2Redacted buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/AuthV2ExhaustiveT1D.test.ts|src/__tests__/AuthV2ExhaustiveT2B.test.ts|src/__tests__/AuthV2ExhaustiveT2D.test.ts|src/__tests__/AuthV2ExhaustiveT2C.test.ts + src/__tests__/AuthV2ExhaustiveT2B.test.ts|src/__tests__/AuthV2ExhaustiveT2D.test.ts|src/__tests__/AuthV2ExhaustiveT2C.test.ts|src/__tests__/RelationalWithAuthV2Redacted.e2e.test.ts CLI_REGION: eu-west-1 depend-on: - publish_to_local_registry - identifier: >- - RelationalWithAuthV2Redacted_RelationalWithAuthV2NonRedacted_AuthV2TransformerIAM_AuthV2ExhaustiveT3D + RelationalWithAuthV2NonRedacted_AuthV2TransformerIAM_AuthV2ExhaustiveT3D_AuthV2ExhaustiveT3C buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/RelationalWithAuthV2Redacted.e2e.test.ts|src/__tests__/RelationalWithAuthV2NonRedacted.e2e.test.ts|src/__tests__/AuthV2TransformerIAM.test.ts|src/__tests__/AuthV2ExhaustiveT3D.test.ts + src/__tests__/RelationalWithAuthV2NonRedacted.e2e.test.ts|src/__tests__/AuthV2TransformerIAM.test.ts|src/__tests__/AuthV2ExhaustiveT3D.test.ts|src/__tests__/AuthV2ExhaustiveT3C.test.ts CLI_REGION: eu-west-2 depend-on: - publish_to_local_registry - identifier: >- - AuthV2ExhaustiveT3C_AuthV2ExhaustiveT3B_AuthV2ExhaustiveT3A_SearchableModelTransformerV2 + AuthV2ExhaustiveT3B_AuthV2ExhaustiveT3A_SearchableModelTransformerV2_SearchableWithAuthV2WithFF buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/AuthV2ExhaustiveT3C.test.ts|src/__tests__/AuthV2ExhaustiveT3B.test.ts|src/__tests__/AuthV2ExhaustiveT3A.test.ts|src/__tests__/SearchableModelTransformerV2.e2e.test.ts + src/__tests__/AuthV2ExhaustiveT3B.test.ts|src/__tests__/AuthV2ExhaustiveT3A.test.ts|src/__tests__/SearchableModelTransformerV2.e2e.test.ts|src/__tests__/SearchableWithAuthV2WithFF.e2e.test.ts CLI_REGION: us-east-1 depend-on: - publish_to_local_registry - - identifier: SearchableWithAuthV2WithFF_SearchableWithAuthV2 + - identifier: SearchableWithAuthV2 buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: - TEST_SUITE: >- - src/__tests__/SearchableWithAuthV2WithFF.e2e.test.ts|src/__tests__/SearchableWithAuthV2.e2e.test.ts + TEST_SUITE: src/__tests__/SearchableWithAuthV2.e2e.test.ts CLI_REGION: us-east-2 depend-on: - publish_to_local_registry @@ -1934,7 +1933,7 @@ batch: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/HttpTransformerV2.e2e.test.ts - CLI_REGION: ap-southeast-2 + CLI_REGION: ap-southeast-1 depend-on: - publish_to_local_registry - identifier: cleanup_e2e_resources diff --git a/packages/graphql-transformers-e2e-tests/package.json b/packages/graphql-transformers-e2e-tests/package.json index bf84dce2ea..19a8e3e1ec 100644 --- a/packages/graphql-transformers-e2e-tests/package.json +++ b/packages/graphql-transformers-e2e-tests/package.json @@ -40,20 +40,13 @@ "@aws-amplify/graphql-transformer-core": "2.9.3", "@aws-amplify/graphql-transformer-interfaces": "3.10.1", "@aws-amplify/graphql-transformer-test-utils": "0.5.6", + "@aws-amplify/amplify-appsync-simulator": "2.16.4", "@types/node": "^12.12.6", "aws-amplify": "^4.2.8", "aws-appsync": "^4.1.1", "aws-sdk": "^2.1113.0", "execa": "^5.1.1", "fs-extra": "^8.1.0", - "graphql-auth-transformer": "7.2.82", - "graphql-connection-transformer": "5.2.80", - "graphql-dynamodb-transformer": "7.2.80", - "graphql-elasticsearch-transformer": "5.2.81", - "graphql-function-transformer": "3.3.71", - "graphql-http-transformer": "5.2.80", - "graphql-key-transformer": "3.2.80", - "graphql-predictions-transformer": "3.2.80", "graphql-tag": "^2.10.1", "graphql-versioned-transformer": "5.2.80", "isomorphic-fetch": "^3.0.0", diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/NoneEnvFunctionTransformer.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/NoneEnvFunctionTransformer.e2e.test.ts deleted file mode 100644 index 6a4f8d18f4..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/NoneEnvFunctionTransformer.e2e.test.ts +++ /dev/null @@ -1,176 +0,0 @@ -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { FunctionTransformer } from 'graphql-function-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as moment } from 'moment'; -import { default as S3 } from 'aws-sdk/clients/s3'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { GraphQLClient } from '../GraphQLClient'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { S3Client } from '../S3Client'; -import { LambdaHelper } from '../LambdaHelper'; -import { IAMHelper } from '../IAMHelper'; -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `NoneEnvFunctionTransformerTests-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `appsync-none-env-func-trans-test-bucket-${BUILD_TIMESTAMP}`; -const LOCAL_FS_BUILD_DIR = '/tmp/none_env_function_transformer_tests/'; -const S3_ROOT_DIR_KEY = 'deployments'; -// Note: there is no env in the name. -const ECHO_FUNCTION_NAME = `e2e-tests-echo-${BUILD_TIMESTAMP}`; -const LAMBDA_EXECUTION_ROLE_NAME = `amplify_e2e_tests_lambda_basic_none_${BUILD_TIMESTAMP}`; -const LAMBDA_EXECUTION_POLICY_NAME = `amplify_e2e_tests_lambda_basic_access_none_${BUILD_TIMESTAMP}`; -let LAMBDA_EXECUTION_POLICY_ARN = ''; - -let GRAPHQL_CLIENT = undefined; - -const LAMBDA_HELPER = new LambdaHelper(); -const IAM_HELPER = new IAMHelper(); - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -beforeAll(async () => { - const validSchema = ` - type Query { - echoNoEnv(msg: String!): Context @function(name: "e2e-tests-echo-${BUILD_TIMESTAMP}-\${env}") - } - type Context { - arguments: Arguments - typeName: String - fieldName: String - } - type Arguments { - msg: String! - } - `; - try { - await awsS3Client.createBucket({ Bucket: BUCKET_NAME }).promise(); - } catch (e) { - console.warn(`Could not create bucket: ${e}`); - } - try { - const role = await IAM_HELPER.createLambdaExecutionRole(LAMBDA_EXECUTION_ROLE_NAME); - await wait(5000); - const policy = await IAM_HELPER.createLambdaExecutionPolicy(LAMBDA_EXECUTION_POLICY_NAME); - await wait(5000); - LAMBDA_EXECUTION_POLICY_ARN = policy.Policy.Arn; - await IAM_HELPER.attachPolicy(policy.Policy.Arn, role.Role.RoleName); - await wait(10000); - await LAMBDA_HELPER.createFunction(ECHO_FUNCTION_NAME, role.Role.Arn, 'echoFunction'); - } catch (e) { - console.warn(`Could not setup function: ${e}`); - } - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new FunctionTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const out = transformer.transform(validSchema); - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { CreateAPIKey: '1' }, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - // Arbitrary wait to make sure everything is ready. - await cf.wait(5, () => Promise.resolve()); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - const endpoint = getApiEndpoint(finishedStack.Outputs); - const apiKey = getApiKey(finishedStack.Outputs); - expect(apiKey).toBeDefined(); - expect(endpoint).toBeDefined(); - GRAPHQL_CLIENT = new GraphQLClient(endpoint, { 'x-api-key': apiKey }); -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf); - - try { - await LAMBDA_HELPER.deleteFunction(ECHO_FUNCTION_NAME); - } catch (e) { - console.warn(`Error during function cleanup: ${e}`); - } - try { - await IAM_HELPER.detachPolicy(LAMBDA_EXECUTION_POLICY_ARN, LAMBDA_EXECUTION_ROLE_NAME); - } catch (e) { - console.warn(`Error during policy dissociation: ${e}`); - } - try { - await IAM_HELPER.deleteRole(LAMBDA_EXECUTION_ROLE_NAME); - } catch (e) { - console.warn(`Error during role cleanup: ${e}`); - } - try { - await IAM_HELPER.deletePolicy(LAMBDA_EXECUTION_POLICY_ARN); - } catch (e) { - console.warn(`Error during policy cleanup: ${e}`); - } -}); - -/** - * Test queries below - */ -test('simple echo function', async () => { - const response = await GRAPHQL_CLIENT.query( - `query { - echoNoEnv(msg: "Hello") { - arguments { - msg - } - typeName - fieldName - } - }`, - {}, - ); - expect(response.data.echoNoEnv.arguments.msg).toEqual('Hello'); - expect(response.data.echoNoEnv.typeName).toEqual('Query'); - expect(response.data.echoNoEnv.fieldName).toEqual('echoNoEnv'); -}); - -function wait(ms: number) { - return new Promise((resolve, reject) => { - setTimeout(() => resolve(), ms); - }); -} diff --git a/packages/graphql-transformers-e2e-tests/tsconfig.tests.json b/packages/graphql-transformers-e2e-tests/tsconfig.tests.json index 582142dcc8..f9ae43e6ba 100644 --- a/packages/graphql-transformers-e2e-tests/tsconfig.tests.json +++ b/packages/graphql-transformers-e2e-tests/tsconfig.tests.json @@ -7,18 +7,9 @@ "outDir": "lib" }, "references": [ - { "path": "../graphql-auth-transformer" }, - { "path": "../graphql-connection-transformer" }, - { "path": "../graphql-dynamodb-transformer" }, - { "path": "../graphql-elasticsearch-transformer" }, - { "path": "../graphql-function-transformer" }, - { "path": "../graphql-http-transformer" }, - { "path": "../graphql-key-transformer" }, { "path": "../graphql-mapping-template" }, - { "path": "../graphql-predictions-transformer" }, { "path": "../graphql-transformer-common" }, - { "path": "../graphql-transformer-core" }, - { "path": "../graphql-versioned-transformer" } + { "path": "../graphql-transformer-core" } ], "exclude": ["**/lib/**/*", "resources/**/*"] } diff --git a/yarn.lock b/yarn.lock index 97072f6d0b..9d0c925b51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -36,6 +36,39 @@ xcode "^2.1.0" yargs "^15.1.0" +"@aws-amplify/amplify-appsync-simulator@2.16.4": + version "2.16.4" + resolved "https://registry.npmjs.org/@aws-amplify/amplify-appsync-simulator/-/amplify-appsync-simulator-2.16.4.tgz#372be8358e847c43fc27f15e12c5aed07df1cd58" + integrity sha512-CFPIlCiNfOxJRoo35yS16kAgH9hdR8/HJp2sE3EyuNuyRAZKcN9vytACKDwQ7MyTkja1HZnfXCu4i46oRi/70g== + dependencies: + "@aws-amplify/amplify-cli-core" "4.3.9" + "@aws-amplify/amplify-prompts" "2.8.6" + "@graphql-tools/schema" "^8.3.1" + "@graphql-tools/utils" "^8.5.1" + amplify-velocity-template "1.4.14" + aws-sdk "^2.1464.0" + chalk "^4.1.1" + cors "^2.8.5" + dataloader "^2.0.0" + express "^4.17.3" + get-port "^5.1.1" + graphql "^15.5.0" + graphql-iso-date "^3.6.1" + graphql-subscriptions "^1.1.0" + ip "^1.1.9" + js-string-escape "^1.0.1" + jwt-decode "^2.2.0" + libphonenumber-js "1.9.47" + lodash "^4.17.21" + moment "^2.24.0" + moment-jdateformatparser "^1.2.1" + moment-timezone "0.5.35" + promise-toolbox "^0.20.0" + slash "^3.0.0" + ulid "^2.3.0" + uuid "^8.3.2" + ws "^8.5.0" + "@aws-amplify/amplify-cli-core@4.3.9", "@aws-amplify/amplify-cli-core@^4.3.9": version "4.3.9" resolved "https://registry.npmjs.org/@aws-amplify/amplify-cli-core/-/amplify-cli-core-4.3.9.tgz#48feec280b22695dce144407beb7372713b1bb1a" @@ -5091,6 +5124,38 @@ resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== +"@graphql-tools/merge@8.3.1": + version "8.3.1" + resolved "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.3.1.tgz#06121942ad28982a14635dbc87b5d488a041d722" + integrity sha512-BMm99mqdNZbEYeTPK3it9r9S6rsZsQKtlqJsSBknAclXq2pGEfOxjcIZi+kBSkHZKPKCRrYDd5vY0+rUmIHVLg== + dependencies: + "@graphql-tools/utils" "8.9.0" + tslib "^2.4.0" + +"@graphql-tools/schema@^8.3.1": + version "8.5.1" + resolved "https://registry.npmjs.org/@graphql-tools/schema/-/schema-8.5.1.tgz#c2f2ff1448380919a330312399c9471db2580b58" + integrity sha512-0Esilsh0P/qYcB5DKQpiKeQs/jevzIadNTaT0jeWklPMwNbT7yMX4EqZany7mbeRRlSRwMzNzL5olyFdffHBZg== + dependencies: + "@graphql-tools/merge" "8.3.1" + "@graphql-tools/utils" "8.9.0" + tslib "^2.4.0" + value-or-promise "1.0.11" + +"@graphql-tools/utils@8.9.0": + version "8.9.0" + resolved "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.9.0.tgz#c6aa5f651c9c99e1aca55510af21b56ec296cdb7" + integrity sha512-pjJIWH0XOVnYGXCqej8g/u/tsfV4LvLlj0eATKQu5zwnxd/TiTHq7Cg313qUPTFFHZ3PP5wJ15chYVtLDwaymg== + dependencies: + tslib "^2.4.0" + +"@graphql-tools/utils@^8.5.1": + version "8.13.1" + resolved "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.13.1.tgz#b247607e400365c2cd87ff54654d4ad25a7ac491" + integrity sha512-qIh9yYpdUFmctVqovwMdheVNJqFh+DQNWIhX87FJStfXYnmweBUDATok9fWPleKeFwxnW8IapKmY8m8toJEkAw== + dependencies: + tslib "^2.4.0" + "@humanwhocodes/config-array@^0.11.11": version "0.11.11" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" @@ -8745,6 +8810,14 @@ abbrev@1, abbrev@^1.0.0: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + acorn-globals@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" @@ -8882,6 +8955,13 @@ amplify-headless-interface@^1.17.7: resolved "https://registry.npmjs.org/amplify-headless-interface/-/amplify-headless-interface-1.17.7.tgz#8a6c00ed8e97fd082ace95d99f84811d2ec447b1" integrity sha512-ZrRuoLkusCL8hxox+O5ZvnoMYoURd/10EvA9mdw2ORYv2ZuTfJY3ItixCq6qexM+SbuIfTKqLxj60zsnEV/nFg== +amplify-velocity-template@1.4.14: + version "1.4.14" + resolved "https://registry.npmjs.org/amplify-velocity-template/-/amplify-velocity-template-1.4.14.tgz#99565e048591ff843db4588319a8ef16cfc6592c" + integrity sha512-2IdMZMQtmEAbpdruid0T5GRfRgQ8y8EJYuHT764IK2096mWWFdB68+d37nmecnfZTAfximSBx9401g18UrwaOg== + dependencies: + lodash "^4.17.21" + ansi-align@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" @@ -9212,6 +9292,11 @@ array-differ@^3.0.0: resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + array-ify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" @@ -9457,7 +9542,7 @@ aws-cdk-lib@2.129.0, aws-cdk-lib@~2.129.0: table "^6.8.1" yaml "1.10.2" -aws-sdk@2.518.0, aws-sdk@^2.1113.0, aws-sdk@^2.1141.0: +aws-sdk@2.518.0, aws-sdk@^2.1113.0, aws-sdk@^2.1141.0, aws-sdk@^2.1464.0: version "2.1643.0" resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1643.0.tgz#ecd91156900eb23b9ada5a32df8654bcc4eaa521" integrity sha512-1k8W0cU7K9rPwPBzv84Z2IE5aT3jhv3Jswn8XerZliiLl1MTj6F4wjxCeY5BpmAv+Zyy4zM0w98M8vVqKeHEeA== @@ -9669,6 +9754,24 @@ bl@^4.0.3, bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" +body-parser@1.20.2: + version "1.20.2" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + boolbase@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" @@ -9820,6 +9923,11 @@ bytes-iec@^3.1.1: resolved "https://registry.yarnpkg.com/bytes-iec/-/bytes-iec-3.1.1.tgz#94cd36bf95c2c22a82002c247df8772d1d591083" integrity sha512-fey6+4jDK7TFtFg/klGSvNKJctyU7n2aQdnM+CO0ruLPbqqMOM8Tio0Pc+deqUeVKX1tL5DQep1zQ7+37aTAsA== +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + cacache@^16.0.0, cacache@^16.0.6, cacache@^16.1.0: version "16.1.3" resolved "https://registry.yarnpkg.com/cacache/-/cacache-16.1.3.tgz#a02b9f34ecfaf9a78c9f4bc16fceb94d5d67a38e" @@ -10498,6 +10606,18 @@ constructs@10.3.0: resolved "https://registry.yarnpkg.com/constructs/-/constructs-10.3.0.tgz#4c246fce9cf8e77711ad45944e9fbd41f1501965" integrity sha512-vbK8i3rIb/xwZxSpTjz3SagHn1qq9BChLEfy5Hf6fB3/2eFbrwt2n9kHwQcS0CPTRBesreeAcsJfMq2229FnbQ== +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + conventional-changelog-angular@^5.0.11, conventional-changelog-angular@^5.0.12: version "5.0.13" resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz#896885d63b914a70d4934b59d2fe7bde1832b28c" @@ -10599,6 +10719,16 @@ convert-source-map@^2.0.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== + cookie@^0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" @@ -10627,6 +10757,14 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== +cors@^2.8.5: + version "2.8.5" + resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + cosmiconfig-typescript-loader@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-2.0.2.tgz#7e7ce6064af041c910e1e43fb0fd9625cee56e93" @@ -10881,6 +11019,11 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" +dataloader@^2.0.0: + version "2.2.2" + resolved "https://registry.npmjs.org/dataloader/-/dataloader-2.2.2.tgz#216dc509b5abe39d43a9b9d97e6e5e473dfbe3e0" + integrity sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g== + date-fns@^1.27.2: version "1.30.1" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" @@ -11077,6 +11220,11 @@ denque@^2.1.0: resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== +depd@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + deprecation@^2.0.0: version "2.3.1" resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" @@ -11087,6 +11235,11 @@ dequal@^2.0.3: resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + detect-indent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" @@ -11241,6 +11394,11 @@ eastasianwidth@^0.2.0: resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + ejs@^3.1.7: version "3.1.10" resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" @@ -11283,6 +11441,11 @@ enabled@2.0.x: resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + encoding@^0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" @@ -11457,6 +11620,11 @@ escape-goat@^4.0.0: resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-4.0.0.tgz#9424820331b510b0666b98f7873fe11ac4aa8081" integrity sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg== +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -11733,6 +11901,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + eventemitter3@^4.0.4: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -11871,6 +12044,43 @@ exponential-backoff@^3.1.1: resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6" integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== +express@^4.17.3: + version "4.19.2" + resolved "https://registry.npmjs.org/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" + integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.2" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.6.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -12063,6 +12273,19 @@ fill-range@^7.1.1: dependencies: to-regex-range "^5.0.1" +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + find-cache-dir@^3.3.1: version "3.3.2" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" @@ -12167,6 +12390,11 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + fp-and-or@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/fp-and-or/-/fp-and-or-0.1.4.tgz#0268c800c359ede259cdcbc352654e698b7ea299" @@ -12179,6 +12407,11 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + from2@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" @@ -12690,28 +12923,6 @@ graphql-dynamodb-transformer@7.2.80: md5 "^2.2.1" pluralize "^8.0.0" -graphql-elasticsearch-transformer@5.2.81: - version "5.2.81" - resolved "https://registry.npmjs.org/graphql-elasticsearch-transformer/-/graphql-elasticsearch-transformer-5.2.81.tgz#3f6f61cb0ee2ff183840eb19dae951ced38d719d" - integrity sha512-TLG4N5V9VBKmllrK87qLQ8JsSD+yxatreEKtYpgD6rFOPqMhj5OAFATcze5egbfezVA6DXiaRDYqrimxNFPSBA== - dependencies: - cloudform-types "^4.2.0" - graphql "^15.5.0" - graphql-mapping-template "4.20.16" - graphql-transformer-common "4.31.1" - graphql-transformer-core "8.2.13" - -graphql-function-transformer@3.3.71: - version "3.3.71" - resolved "https://registry.npmjs.org/graphql-function-transformer/-/graphql-function-transformer-3.3.71.tgz#cdc78fab2ca9032e2b784b9a2387624934d3f087" - integrity sha512-29tmgd5bketVppNK9i2/xmLBG4LGmiuRzzwasP89X2PDvSF88Ztmjr1k0F3vR1LiEOMIpJpMP8zKeFZSdkRccg== - dependencies: - cloudform-types "^4.2.0" - graphql "^15.5.0" - graphql-mapping-template "4.20.16" - graphql-transformer-common "4.31.1" - graphql-transformer-core "8.2.13" - graphql-http-transformer@5.2.80: version "5.2.80" resolved "https://registry.npmjs.org/graphql-http-transformer/-/graphql-http-transformer-5.2.80.tgz#4b84b31a8bcfa4e7ff11ca72e5e99436d08eef72" @@ -12731,6 +12942,11 @@ graphql-import@^0.7.1: lodash "^4.17.4" resolve-from "^4.0.0" +graphql-iso-date@^3.6.1: + version "3.6.1" + resolved "https://registry.npmjs.org/graphql-iso-date/-/graphql-iso-date-3.6.1.tgz#bd2d0dc886e0f954cbbbc496bbf1d480b57ffa96" + integrity sha512-AwFGIuYMJQXOEAgRlJlFL4H1ncFM8n8XmoVDTNypNOZyQ8LFDG2ppMFlsS862BSTCDcSUfHp8PD3/uJhv7t59Q== + graphql-key-transformer@3.2.80: version "3.2.80" resolved "https://registry.npmjs.org/graphql-key-transformer/-/graphql-key-transformer-3.2.80.tgz#918f8c440e7c51651b8d978e8857893d37e2b7b1" @@ -12744,17 +12960,6 @@ graphql-key-transformer@3.2.80: graphql-transformer-core "8.2.13" lodash "^4.17.21" -graphql-predictions-transformer@3.2.80: - version "3.2.80" - resolved "https://registry.npmjs.org/graphql-predictions-transformer/-/graphql-predictions-transformer-3.2.80.tgz#e4df8bf333bac6cb894d23da53fe44f4a8be1eef" - integrity sha512-bo6ko/qMGFp1OE8HeJagVpUWTFErPYB/uTnqLOKdzMc3qreycizC2F6WhGEsLEXNdhkhC+gTmtCDEZFxEEyQ0Q== - dependencies: - cloudform-types "^4.2.0" - graphql "^15.5.0" - graphql-mapping-template "4.20.16" - graphql-transformer-common "4.31.1" - graphql-transformer-core "8.2.13" - graphql-request@^1.5.0: version "1.8.2" resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-1.8.2.tgz#398d10ae15c585676741bde3fc01d5ca948f8fbe" @@ -12762,6 +12967,13 @@ graphql-request@^1.5.0: dependencies: cross-fetch "2.2.2" +graphql-subscriptions@^1.1.0: + version "1.2.1" + resolved "https://registry.npmjs.org/graphql-subscriptions/-/graphql-subscriptions-1.2.1.tgz#2142b2d729661ddf967b7388f7cf1dd4cf2e061d" + integrity sha512-95yD/tKi24q8xYa7Q9rhQN16AYj5wPbrb8tmHGM3WRc9EBmWrG/0kkMl+tQG8wcEuE9ibR4zyOM31p5Sdr2v4g== + dependencies: + iterall "^1.3.0" + graphql-tag@^2.10.1: version "2.12.6" resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" @@ -12960,6 +13172,17 @@ http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + http-proxy-agent@^4.0.0, http-proxy-agent@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" @@ -13196,7 +13419,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -13320,7 +13543,7 @@ into-stream@^6.0.0: from2 "^2.3.0" p-is-promise "^3.0.0" -ip@^1.1.8: +ip@^1.1.8, ip@^1.1.9: version "1.1.9" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.9.tgz#8dfbcc99a754d07f425310b86a99546b1151e396" integrity sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ== @@ -13330,6 +13553,11 @@ ip@^2.0.0: resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105" integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ== +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -13895,6 +14123,11 @@ istanbul-reports@^3.0.2: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" +iterall@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" + integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== + iterator.prototype@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" @@ -14381,6 +14614,11 @@ js-cookie@^2.2.1: resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== +js-string-escape@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" + integrity sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -14658,6 +14896,11 @@ just-diff@^5.0.1: resolved "https://registry.yarnpkg.com/just-diff/-/just-diff-5.2.0.tgz#60dca55891cf24cd4a094e33504660692348a241" integrity sha512-6ufhP9SHjb7jibNFrNxyFZ6od3g+An6Ai9mhGRvcYe8UJlH0prseN64M+6ZBBUoKYHZsitDP42gAJ8+eVWr3lw== +jwt-decode@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz#7d86bd56679f58ce6a84704a657dd392bba81a79" + integrity sha512-86GgN2vzfUu7m9Wcj63iUkuDzFNYFVmjeDm2GzWpUk+opB0pEpMsw6ePCMrhYkumz2C1ihqtZzOMAg7FiXcNoQ== + keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -15199,7 +15442,7 @@ make-dir@^4.0.0: dependencies: semver "^7.5.3" -make-error@1.x, make-error@^1.1.1: +make-error@1.x, make-error@^1.1.1, make-error@^1.3.2: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== @@ -15295,6 +15538,11 @@ mdurl@~1.0.1: resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g== +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + meow@^8.0.0: version "8.1.2" resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" @@ -15312,6 +15560,11 @@ meow@^8.0.0: type-fest "^0.18.0" yargs-parser "^20.2.3" +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -15322,6 +15575,11 @@ merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + micromatch@4.0.5, micromatch@^4.0.2, micromatch@^4.0.4: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" @@ -15354,13 +15612,18 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@^2.1.27: +mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" +mime@1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" @@ -15567,7 +15830,12 @@ modify-values@^1.0.0: resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== -moment-timezone@^0.5.35: +moment-jdateformatparser@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/moment-jdateformatparser/-/moment-jdateformatparser-1.2.1.tgz#336c41ef7a6db8021d7ca086385a35fb8a648456" + integrity sha512-lpUeQtMaxmpK+pPPHGWMnqzgsB/nunbAGPg72mzvRNbxxeQ2uBurdq9EJmvJtOiYB6k/4T9kuvQFbb+8Tirn4A== + +moment-timezone@0.5.35, moment-timezone@^0.5.35: version "0.5.45" resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.45.tgz#cb685acd56bac10e69d93c536366eb65aa6bcf5c" integrity sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ== @@ -15594,7 +15862,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.0.0, ms@^2.1.1: +ms@2.1.3, ms@^2.0.0, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -15698,7 +15966,7 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -negotiator@^0.6.3: +negotiator@0.6.3, negotiator@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== @@ -16165,7 +16433,7 @@ nx@15.9.7, "nx@>=14.8.1 < 16": "@nrwl/nx-win32-arm64-msvc" "15.9.7" "@nrwl/nx-win32-x64-msvc" "15.9.7" -object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== @@ -16273,6 +16541,13 @@ obliterator@^1.6.1: resolved "https://registry.npmjs.org/obliterator/-/obliterator-1.6.1.tgz#dea03e8ab821f6c4d96a299e17aef6a3af994ef3" integrity sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig== +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -16675,6 +16950,11 @@ parse5@6.0.1: resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" @@ -16723,6 +17003,11 @@ path-scurry@^1.10.1: lru-cache "^9.1.1 || ^10.0.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + path-type@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -17270,6 +17555,13 @@ promise-retry@^2.0.1: err-code "^2.0.2" retry "^0.12.0" +promise-toolbox@^0.20.0: + version "0.20.0" + resolved "https://registry.npmjs.org/promise-toolbox/-/promise-toolbox-0.20.0.tgz#af04d7338038c2362b8fb7c27546c57d893bf562" + integrity sha512-VXF6waqUheD19yOU7zxsXhw/HCKlXqXwUc4jM8mchtBqZFNA+GHA7dbJsQDLHP4IUpQuTLpCQRd0lCr5z4CqXQ== + dependencies: + make-error "^1.3.2" + prompts-ncu@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/prompts-ncu/-/prompts-ncu-3.0.0.tgz#716feb4874fca3dbe00af0f3de17a15d43d2228d" @@ -17312,6 +17604,14 @@ protocols@^2.0.0, protocols@^2.0.1: resolved "https://registry.yarnpkg.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86" integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q== +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + proxy-agent@^6.3.0: version "6.3.1" resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.3.1.tgz#40e7b230552cf44fd23ffaf7c59024b692612687" @@ -17376,6 +17676,13 @@ q@^1.5.1: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== +qs@6.11.0: + version "6.11.0" + resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + qs@^6.11.2: version "6.11.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" @@ -17415,6 +17722,21 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + rc-config-loader@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/rc-config-loader/-/rc-config-loader-4.1.3.tgz#1352986b8a2d8d96d6fd054a5bb19a60c576876a" @@ -17911,7 +18233,7 @@ safe-array-concat@^1.0.1: has-symbols "^1.0.3" isarray "^2.0.5" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -18045,6 +18367,25 @@ semver-utils@^1.1.4: dependencies: lru-cache "^6.0.0" +send@0.18.0: + version "0.18.0" + resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + seq-queue@^0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" @@ -18057,6 +18398,16 @@ serialize-javascript@^6.0.0, serialize-javascript@^6.0.1: dependencies: randombytes "^2.1.0" +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -18086,6 +18437,11 @@ setimmediate@^1.0.5: resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + shallow-clone@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" @@ -18471,6 +18827,11 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + stream-browserify@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" @@ -19019,6 +19380,11 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + tough-cookie@^4.0.0: version "4.1.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" @@ -19218,6 +19584,14 @@ type-fest@^2.13.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + typed-array-buffer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" @@ -19317,7 +19691,7 @@ uglify-js@^3.1.4: resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== -ulid@2.3.0: +ulid@2.3.0, ulid@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/ulid/-/ulid-2.3.0.tgz#93063522771a9774121a84d126ecd3eb9804071f" integrity sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw== @@ -19420,6 +19794,11 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" @@ -19530,6 +19909,11 @@ util@^0.12.4: is-typed-array "^1.1.3" which-typed-array "^1.1.2" +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + uuid@3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" @@ -19608,6 +19992,16 @@ validator@^13.7.0: resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b" integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ== +value-or-promise@1.0.11: + version "1.0.11" + resolved "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.11.tgz#3e90299af31dd014fe843fe309cefa7c1d94b140" + integrity sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg== + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" @@ -19984,6 +20378,11 @@ ws@^7.4.6, ws@^7.5.7: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== +ws@^8.5.0: + version "8.18.0" + resolved "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== + xcode@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/xcode/-/xcode-2.1.0.tgz#bab64a7e954bb50ca8d19da7e09531c65a43ecfe" From 5140658ac7d9c726f5b9515a11b1aea28bd12959 Mon Sep 17 00:00:00 2001 From: Doesnt Matter Date: Tue, 6 Aug 2024 21:57:46 -0700 Subject: [PATCH 15/23] chore: remove v1 to v2 migration tests and mock e2e job --- codebuild_specs/createapi_canary_workflow.yml | 6 - codebuild_specs/e2e_workflow.yml | 6 - codebuild_specs/e2e_workflow_base.yml | 6 - codebuild_specs/mock_e2e_tests.yml | 13 - codebuild_specs/pr_workflow.yml | 4 - codebuild_specs/release_workflow.yml | 5 - dependency_licenses.txt | 2648 ++++++++++------- .../CHANGELOG.md | 515 ---- .../package.json | 84 - .../graphql-version-migration.test.ts | 46 - .../src/feature-flag-stub.ts | 5 - .../src/migrate-schema-wrapper.ts | 21 - .../src/nested-stack-diff-rules.ts | 60 - .../src/test-case-registry.ts | 143 - .../src/test-case-types.ts | 17 - .../src/v1-transformer-provider.ts | 46 - .../src/v2-transformer-provider.ts | 62 - .../tsconfig.json | 8 - scripts/split-e2e-tests.ts | 13 - 19 files changed, 1614 insertions(+), 2094 deletions(-) delete mode 100644 codebuild_specs/mock_e2e_tests.yml delete mode 100644 packages/amplify-graphql-migration-tests/CHANGELOG.md delete mode 100644 packages/amplify-graphql-migration-tests/package.json delete mode 100644 packages/amplify-graphql-migration-tests/src/__tests__/graphql-version-migration.test.ts delete mode 100644 packages/amplify-graphql-migration-tests/src/feature-flag-stub.ts delete mode 100644 packages/amplify-graphql-migration-tests/src/migrate-schema-wrapper.ts delete mode 100644 packages/amplify-graphql-migration-tests/src/nested-stack-diff-rules.ts delete mode 100644 packages/amplify-graphql-migration-tests/src/test-case-registry.ts delete mode 100644 packages/amplify-graphql-migration-tests/src/test-case-types.ts delete mode 100644 packages/amplify-graphql-migration-tests/src/v1-transformer-provider.ts delete mode 100644 packages/amplify-graphql-migration-tests/src/v2-transformer-provider.ts delete mode 100644 packages/amplify-graphql-migration-tests/tsconfig.json diff --git a/codebuild_specs/createapi_canary_workflow.yml b/codebuild_specs/createapi_canary_workflow.yml index d91ed77583..d4dc4c9ea4 100644 --- a/codebuild_specs/createapi_canary_workflow.yml +++ b/codebuild_specs/createapi_canary_workflow.yml @@ -15,12 +15,6 @@ batch: compute-type: BUILD_GENERAL1_LARGE depend-on: - build_linux - - identifier: mock_e2e_tests - buildspec: codebuild_specs/mock_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_MEDIUM - depend-on: - - build_linux - identifier: publish_to_local_registry buildspec: codebuild_specs/publish_to_local_registry.yml env: diff --git a/codebuild_specs/e2e_workflow.yml b/codebuild_specs/e2e_workflow.yml index 43a7ef9470..6698aebd04 100644 --- a/codebuild_specs/e2e_workflow.yml +++ b/codebuild_specs/e2e_workflow.yml @@ -24,12 +24,6 @@ batch: compute-type: BUILD_GENERAL1_LARGE depend-on: - build_linux - - identifier: mock_e2e_tests - buildspec: codebuild_specs/mock_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_MEDIUM - depend-on: - - build_linux - identifier: verify_cdk_version buildspec: codebuild_specs/verify_cdk_version.yml env: diff --git a/codebuild_specs/e2e_workflow_base.yml b/codebuild_specs/e2e_workflow_base.yml index 347d375c34..7ef55dd914 100644 --- a/codebuild_specs/e2e_workflow_base.yml +++ b/codebuild_specs/e2e_workflow_base.yml @@ -29,12 +29,6 @@ batch: compute-type: BUILD_GENERAL1_LARGE depend-on: - build_linux - - identifier: mock_e2e_tests - buildspec: codebuild_specs/mock_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_MEDIUM - depend-on: - - build_linux - identifier: verify_cdk_version buildspec: codebuild_specs/verify_cdk_version.yml env: diff --git a/codebuild_specs/mock_e2e_tests.yml b/codebuild_specs/mock_e2e_tests.yml deleted file mode 100644 index 8a27fa6837..0000000000 --- a/codebuild_specs/mock_e2e_tests.yml +++ /dev/null @@ -1,13 +0,0 @@ -version: 0.2 -env: - shell: bash - variables: - JEST_JUNIT_OUTPUT: 'reports/junit/js-test-results.xml' - NODE_OPTIONS: --max-old-space-size=4096 -phases: - build: - commands: - - source ./shared-scripts.sh && _mockE2ETests -artifacts: - files: - - 'shared-scripts.sh' diff --git a/codebuild_specs/pr_workflow.yml b/codebuild_specs/pr_workflow.yml index 9769c6c694..ce453b5493 100644 --- a/codebuild_specs/pr_workflow.yml +++ b/codebuild_specs/pr_workflow.yml @@ -47,7 +47,3 @@ batch: compute-type: BUILD_GENERAL1_MEDIUM depend-on: - build_linux - - identifier: mock_e2e_tests - buildspec: codebuild_specs/mock_e2e_tests.yml - depend-on: - - build_linux diff --git a/codebuild_specs/release_workflow.yml b/codebuild_specs/release_workflow.yml index 89f8e69f48..19791bfc60 100644 --- a/codebuild_specs/release_workflow.yml +++ b/codebuild_specs/release_workflow.yml @@ -43,13 +43,8 @@ batch: compute-type: BUILD_GENERAL1_MEDIUM depend-on: - build_linux - - identifier: mock_e2e_tests - buildspec: codebuild_specs/mock_e2e_tests.yml - depend-on: - - build_linux - identifier: deploy buildspec: codebuild_specs/deploy.yml depend-on: - test - - mock_e2e_tests - build_windows diff --git a/dependency_licenses.txt b/dependency_licenses.txt index d14904439d..5f86cb0572 100644 --- a/dependency_licenses.txt +++ b/dependency_licenses.txt @@ -233,7 +233,7 @@ Apache License ----- -The following software may be included in this product: @aws-amplify/amplify-app, @aws-amplify/amplify-cli-core, @aws-amplify/amplify-cli-logger, @aws-amplify/amplify-cli-shared-interfaces, @aws-amplify/amplify-frontend-android, @aws-amplify/amplify-frontend-flutter, @aws-amplify/amplify-frontend-ios, @aws-amplify/amplify-frontend-javascript, @aws-amplify/amplify-function-plugin-interface, @aws-amplify/amplify-prompts, amplify-headless-interface. A copy of the source code may be downloaded from https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-app), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-cli-core), git+https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-cli-logger), git+https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-cli-shared-interfaces), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-frontend-android), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-frontend-flutter), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-frontend-ios), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-frontend-javascript), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-function-plugin-interface), git+https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-prompts). This software contains the following license and notice below: +The following software may be included in this product: @aws-amplify/amplify-app, @aws-amplify/amplify-appsync-simulator, @aws-amplify/amplify-cli-core, @aws-amplify/amplify-cli-logger, @aws-amplify/amplify-cli-shared-interfaces, @aws-amplify/amplify-frontend-android, @aws-amplify/amplify-frontend-flutter, @aws-amplify/amplify-frontend-ios, @aws-amplify/amplify-frontend-javascript, @aws-amplify/amplify-function-plugin-interface, @aws-amplify/amplify-prompts, amplify-headless-interface. A copy of the source code may be downloaded from https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-app), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-appsync-simulator), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-cli-core), git+https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-cli-logger), git+https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-cli-shared-interfaces), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-frontend-android), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-frontend-flutter), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-frontend-ios), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-frontend-javascript), https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-function-plugin-interface), git+https://github.com/aws-amplify/amplify-cli.git (@aws-amplify/amplify-prompts). This software contains the following license and notice below: Apache License Version 2.0, January 2004 @@ -645,211 +645,6 @@ Apache License ----- - -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright 2017 - 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - ------ - The following software may be included in this product: @aws-cdk/asset-awscli-v1, @aws-cdk/asset-kubectl-v20, @aws-cdk/asset-node-proxy-agent-v6, jsii. A copy of the source code may be downloaded from https://github.com/cdklabs/awscdk-asset-awscli.git (@aws-cdk/asset-awscli-v1), https://github.com/cdklabs/awscdk-asset-kubectl.git (@aws-cdk/asset-kubectl-v20), https://github.com/cdklabs/awscdk-asset-node-proxy-agent.git (@aws-cdk/asset-node-proxy-agent-v6), https://github.com/aws/jsii-compiler.git (jsii). This software contains the following license and notice below: Apache License @@ -1273,430 +1068,6 @@ Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. ----- -The following software may be included in this product: @aws-cdk/cfnspec. A copy of the source code may be downloaded from https://github.com/aws/aws-cdk.git. This software contains the following license and notice below: - -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - -NOTICE - -AWS Cloud Development Kit (AWS CDK) -Copyright 2018-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. - ------ - -The following software may be included in this product: @aws-cdk/cloudformation-diff. A copy of the source code may be downloaded from https://github.com/aws/aws-cdk.git. This software contains the following license and notice below: - -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - -NOTICE - -AWS Cloud Development Kit (AWS CDK) -Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. - ------ - The following software may be included in this product: @aws-crypto/crc32, @aws-crypto/crc32c, @aws-crypto/util. A copy of the source code may be downloaded from git@github.com:aws/aws-sdk-js-crypto-helpers.git (@aws-crypto/crc32), git@github.com:aws/aws-sdk-js-crypto-helpers.git (@aws-crypto/crc32c), git@github.com:aws/aws-sdk-js-crypto-helpers.git (@aws-crypto/util). This software contains the following license and notice below: Apache License @@ -6712,6 +6083,34 @@ OTHER DEALINGS IN THE SOFTWARE. ----- +The following software may be included in this product: accepts, mime-types. A copy of the source code may be downloaded from https://github.com/jshttp/accepts.git (accepts), https://github.com/jshttp/mime-types.git (mime-types). This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2014 Jonathan Ong +Copyright (c) 2015 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: acorn. A copy of the source code may be downloaded from https://github.com/acornjs/acorn.git. This software contains the following license and notice below: MIT License @@ -7153,6 +6552,31 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- +The following software may be included in this product: amplify-velocity-template. A copy of the source code may be downloaded from https://github.com/aws-amplify/amplify-cli.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2012-2013 Eward Song + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the 'Software'), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: ansi-align, which-module. A copy of the source code may be downloaded from git+https://github.com/nexdrew/ansi-align.git (ansi-align), git+https://github.com/nexdrew/which-module.git (which-module). This software contains the following license and notice below: Copyright (c) 2016, Contributors @@ -8054,6 +7478,32 @@ SOFTWARE. ----- +The following software may be included in this product: array-flatten, path-to-regexp, ts-node. A copy of the source code may be downloaded from git://github.com/blakeembrey/array-flatten.git (array-flatten), https://github.com/component/path-to-regexp.git (path-to-regexp), git://github.com/TypeStrong/ts-node.git (ts-node). This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +----- + The following software may be included in this product: array-includes, define-properties. A copy of the source code may be downloaded from git://github.com/es-shims/array-includes.git (array-includes), git://github.com/ljharb/define-properties.git (define-properties). This software contains the following license and notice below: The MIT License (MIT) @@ -11057,6 +10507,34 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI ----- +The following software may be included in this product: body-parser, type-is. A copy of the source code may be downloaded from https://github.com/expressjs/body-parser.git (body-parser), https://github.com/jshttp/type-is.git (type-is). This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2014 Jonathan Ong +Copyright (c) 2014-2015 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: bowser. A copy of the source code may be downloaded from git+https://github.com/lancedikson/bowser.git. This software contains the following license and notice below: Copyright 2015, Dustin Diaz (the "Original Author") @@ -11392,6 +10870,34 @@ SOFTWARE. ----- +The following software may be included in this product: bytes. A copy of the source code may be downloaded from https://github.com/visionmedia/bytes.js.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2012-2014 TJ Holowaychuk +Copyright (c) 2015 Jed Watson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: bytes-iec. A copy of the source code may be downloaded from https://github.com/Saevon/bytes.js.git. This software contains the following license and notice below: (The MIT License) @@ -13250,6 +12756,60 @@ Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. ----- +The following software may be included in this product: content-disposition, forwarded, vary. A copy of the source code may be downloaded from https://github.com/jshttp/content-disposition.git (content-disposition), https://github.com/jshttp/forwarded.git (forwarded), https://github.com/jshttp/vary.git (vary). This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2014-2017 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + +The following software may be included in this product: content-type. A copy of the source code may be downloaded from https://github.com/jshttp/content-type.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2015 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: conventional-changelog-angular, conventional-changelog-conventionalcommits. A copy of the source code may be downloaded from https://github.com/conventional-changelog/conventional-changelog.git (conventional-changelog-angular), https://github.com/conventional-changelog/conventional-changelog.git (conventional-changelog-conventionalcommits). This software contains the following license and notice below: ### ISC License @@ -13452,6 +13012,33 @@ IN THE SOFTWARE. ----- +The following software may be included in this product: cors. A copy of the source code may be downloaded from https://github.com/expressjs/cors.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2013 Troy Goode + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: cosmiconfig. A copy of the source code may be downloaded from git+https://github.com/davidtheclark/cosmiconfig.git. This software contains the following license and notice below: The MIT License (MIT) @@ -14102,6 +13689,32 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI ----- +The following software may be included in this product: dataloader, graphql. A copy of the source code may be downloaded from http://github.com/graphql/dataloader.git (dataloader), https://github.com/graphql/graphql-js.git (graphql). This software contains the following license and notice below: + +MIT License + +Copyright (c) GraphQL Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + The following software may be included in this product: date-fns. A copy of the source code may be downloaded from https://github.com/date-fns/date-fns. This software contains the following license and notice below: # License @@ -14698,6 +14311,33 @@ Apache License ----- +The following software may be included in this product: depd. A copy of the source code may be downloaded from https://github.com/dougwilson/nodejs-depd.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2014-2018 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: deprecation. A copy of the source code may be downloaded from https://github.com/gr2m/deprecation.git. This software contains the following license and notice below: The ISC License @@ -14744,6 +14384,33 @@ THE SOFTWARE. ----- +The following software may be included in this product: destroy. A copy of the source code may be downloaded from https://github.com/stream-utils/destroy.git. This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2014 Jonathan Ong me@jongleberry.com +Copyright (c) 2015-2022 Douglas Christopher Wilson doug@somethingdoug.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +----- + The following software may be included in this product: diff. A copy of the source code may be downloaded from git://github.com/kpdecker/jsdiff.git. This software contains the following license and notice below: Software License Agreement (BSD License) @@ -14780,40 +14447,6 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----- -The following software may be included in this product: diff. A copy of the source code may be downloaded from git://github.com/kpdecker/jsdiff.git. This software contains the following license and notice below: - -BSD 3-Clause License - -Copyright (c) 2009-2015, Kevin Decker -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------ - The following software may be included in this product: doctrine. A copy of the source code may be downloaded from https://github.com/eslint/doctrine.git. This software contains the following license and notice below: Apache License @@ -15091,6 +14724,32 @@ SOFTWARE. ----- +The following software may be included in this product: ee-first, fs-readdir-recursive. A copy of the source code may be downloaded from https://github.com/jonathanong/ee-first.git (ee-first), https://github.com/fs-utils/fs-readdir-recursive.git (fs-readdir-recursive). This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2014 Jonathan Ong me@jongleberry.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +----- + The following software may be included in this product: electron-to-chromium. A copy of the source code may be downloaded from https://github.com/kilian/electron-to-chromium/. This software contains the following license and notice below: Copyright 2018 Kilian Valkhof @@ -15115,6 +14774,33 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I ----- +The following software may be included in this product: encodeurl. A copy of the source code may be downloaded from https://github.com/pillarjs/encodeurl.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2016 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: encoding. A copy of the source code may be downloaded from https://github.com/andris9/encoding.git. This software contains the following license and notice below: Copyright (c) 2012-2014 Andris Reinman @@ -15347,6 +15033,35 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI ----- +The following software may be included in this product: escape-html. A copy of the source code may be downloaded from https://github.com/component/escape-html.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2012-2013 TJ Holowaychuk +Copyright (c) 2015 Andreas Lubbe +Copyright (c) 2015 Tiancheng "Timothy" Gu + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: escodegen. A copy of the source code may be downloaded from http://github.com/estools/escodegen.git. This software contains the following license and notice below: Copyright (C) 2012 Yusuke Suzuki (twitter: @Constellation) and other contributors. @@ -15951,6 +15666,33 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----- +The following software may be included in this product: etag, proxy-addr. A copy of the source code may be downloaded from https://github.com/jshttp/etag.git (etag), https://github.com/jshttp/proxy-addr.git (proxy-addr). This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2014-2016 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: eventemitter3. A copy of the source code may be downloaded from git://github.com/primus/eventemitter3.git. This software contains the following license and notice below: The MIT License (MIT) @@ -16262,6 +16004,35 @@ Apache License ----- +The following software may be included in this product: express. A copy of the source code may be downloaded from https://github.com/expressjs/express.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2009-2014 TJ Holowaychuk +Copyright (c) 2013-2014 Roman Shtylman +Copyright (c) 2014-2015 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: extend-shallow, mixin-deep. A copy of the source code may be downloaded from https://github.com/jonschlinkert/extend-shallow.git (extend-shallow), https://github.com/jonschlinkert/mixin-deep.git (mixin-deep). This software contains the following license and notice below: The MIT License (MIT) @@ -16615,6 +16386,33 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- +The following software may be included in this product: finalhandler. A copy of the source code may be downloaded from https://github.com/pillarjs/finalhandler.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2014-2022 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: flat. A copy of the source code may be downloaded from git://github.com/hughsk/flat.git. This software contains the following license and notice below: Copyright (c) 2014, Hugh Kennedy @@ -16849,6 +16647,34 @@ THE SOFTWARE. ----- +The following software may be included in this product: fresh. A copy of the source code may be downloaded from https://github.com/jshttp/fresh.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2012 TJ Holowaychuk +Copyright (c) 2016-2017 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: from2. A copy of the source code may be downloaded from git://github.com/hughsk/from2. This software contains the following license and notice below: ## The MIT License (MIT) ## @@ -16921,32 +16747,6 @@ OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHE ----- -The following software may be included in this product: fs-readdir-recursive. A copy of the source code may be downloaded from https://github.com/fs-utils/fs-readdir-recursive.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2014 Jonathan Ong me@jongleberry.com - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - The following software may be included in this product: fs.realpath. A copy of the source code may be downloaded from git+https://github.com/isaacs/fs.realpath.git. This software contains the following license and notice below: The ISC License @@ -17424,11 +17224,37 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: graphql. A copy of the source code may be downloaded from https://github.com/graphql/graphql-js.git. This software contains the following license and notice below: +The following software may be included in this product: graphql-config. A copy of the source code may be downloaded from https://github.com/kamilkisiela/graphql-config.git. This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2016 Kamil + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + +The following software may be included in this product: graphql-import, graphql-request. A copy of the source code may be downloaded from git@github.com:graphcool/graphql-import.git (graphql-import), git+https://github.com/graphcool/graphql-request.git (graphql-request). This software contains the following license and notice below: MIT License -Copyright (c) GraphQL Contributors +Copyright (c) 2017 Graphcool Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -17450,11 +17276,11 @@ SOFTWARE. ----- -The following software may be included in this product: graphql-config. A copy of the source code may be downloaded from https://github.com/kamilkisiela/graphql-config.git. This software contains the following license and notice below: +The following software may be included in this product: graphql-iso-date. A copy of the source code may be downloaded from https://github.com/excitement-engineer/graphql-iso-date.git. This software contains the following license and notice below: The MIT License (MIT) -Copyright (c) 2016 Kamil +Copyright (c) 2017 Dirk-Jan Rutten Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -17476,11 +17302,11 @@ SOFTWARE. ----- -The following software may be included in this product: graphql-import, graphql-request. A copy of the source code may be downloaded from git@github.com:graphcool/graphql-import.git (graphql-import), git+https://github.com/graphcool/graphql-request.git (graphql-request). This software contains the following license and notice below: +The following software may be included in this product: graphql-subscriptions. A copy of the source code may be downloaded from https://github.com/apollostack/graphql-subscriptions.git. This software contains the following license and notice below: -MIT License +The MIT License (MIT) -Copyright (c) 2017 Graphcool +Copyright (c) 2015 - 2016 Meteor Development Group, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -17528,6 +17354,211 @@ SOFTWARE. ----- + +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2017 - 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +----- + The following software may be included in this product: handlebars. A copy of the source code may be downloaded from https://github.com/handlebars-lang/handlebars.js.git. This software contains the following license and notice below: Copyright (C) 2011-2019 by Yehuda Katz @@ -17716,6 +17747,33 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ----- +The following software may be included in this product: http-errors. A copy of the source code may be downloaded from https://github.com/jshttp/http-errors.git. This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2014 Jonathan Ong me@jongleberry.com +Copyright (c) 2016 Douglas Christopher Wilson doug@somethingdoug.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +----- + The following software may be included in this product: http-proxy-agent. A copy of the source code may be downloaded from https://github.com/TooTallNate/proxy-agents.git. This software contains the following license and notice below: License @@ -18422,6 +18480,30 @@ OTHER DEALINGS IN THE SOFTWARE. ----- +The following software may be included in this product: ipaddr.js. A copy of the source code may be downloaded from git://github.com/whitequark/ipaddr.js. This software contains the following license and notice below: + +Copyright (C) 2011-2017 whitequark + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +----- + The following software may be included in this product: is-arguments, is-generator-function, is-negative-zero, is-regex. A copy of the source code may be downloaded from git://github.com/inspect-js/is-arguments.git (is-arguments), git://github.com/inspect-js/is-generator-function.git (is-generator-function), git://github.com/inspect-js/is-negative-zero.git (is-negative-zero), git://github.com/inspect-js/is-regex.git (is-regex). This software contains the following license and notice below: The MIT License (MIT) @@ -18838,32 +18920,55 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----- -The following software may be included in this product: istanbul-lib-source-maps. A copy of the source code may be downloaded from git+ssh://git@github.com/istanbuljs/istanbuljs.git. This software contains the following license and notice below: +The following software may be included in this product: istanbul-lib-source-maps. A copy of the source code may be downloaded from git+ssh://git@github.com/istanbuljs/istanbuljs.git. This software contains the following license and notice below: + +Copyright 2015 Yahoo! Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Yahoo! Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL YAHOO! INC. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----- + +The following software may be included in this product: iterall. A copy of the source code may be downloaded from https://github.com/leebyron/iterall.git. This software contains the following license and notice below: -Copyright 2015 Yahoo! Inc. -All rights reserved. +Copyright (c) 2016 Lee Byron -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Yahoo! Inc. nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL YAHOO! INC. BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- @@ -19229,6 +19334,32 @@ SOFTWARE. ----- +The following software may be included in this product: js-string-escape. A copy of the source code may be downloaded from https://github.com/joliss/js-string-escape. This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2013 Jo Liss + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +----- + The following software may be included in this product: js-tokens. A copy of the source code may be downloaded from https://github.com/lydell/js-tokens.git. This software contains the following license and notice below: The MIT License (MIT) @@ -19784,6 +19915,32 @@ SOFTWARE. ----- +The following software may be included in this product: jwt-decode. A copy of the source code may be downloaded from git://github.com/auth0/jwt-decode. This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2015 Auth0, Inc. (http://auth0.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + The following software may be included in this product: knex. A copy of the source code may be downloaded from git://github.com/knex/knex.git. This software contains the following license and notice below: Copyright (c) 2013-present Tim Griesser @@ -20669,6 +20826,61 @@ IN THE SOFTWARE. ----- +The following software may be included in this product: media-typer. A copy of the source code may be downloaded from https://github.com/jshttp/media-typer.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2014 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + +The following software may be included in this product: merge-descriptors. A copy of the source code may be downloaded from https://github.com/component/merge-descriptors.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2013 Jonathan Ong +Copyright (c) 2015 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: merge-stream. A copy of the source code may be downloaded from https://github.com/grncdr/merge-stream.git. This software contains the following license and notice below: The MIT License (MIT) @@ -20721,12 +20933,12 @@ SOFTWARE. ----- -The following software may be included in this product: mime-db. A copy of the source code may be downloaded from https://github.com/jshttp/mime-db.git. This software contains the following license and notice below: +The following software may be included in this product: methods. A copy of the source code may be downloaded from https://github.com/jshttp/methods.git. This software contains the following license and notice below: (The MIT License) -Copyright (c) 2014 Jonathan Ong -Copyright (c) 2015-2022 Douglas Christopher Wilson +Copyright (c) 2013-2014 TJ Holowaychuk +Copyright (c) 2015-2016 Douglas Christopher Wilson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -20749,12 +20961,38 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: mime-types. A copy of the source code may be downloaded from https://github.com/jshttp/mime-types.git. This software contains the following license and notice below: +The following software may be included in this product: mime. A copy of the source code may be downloaded from https://github.com/broofa/node-mime. This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2010 Benjamin Thomas, Robert Kieffer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +----- + +The following software may be included in this product: mime-db. A copy of the source code may be downloaded from https://github.com/jshttp/mime-db.git. This software contains the following license and notice below: (The MIT License) Copyright (c) 2014 Jonathan Ong -Copyright (c) 2015 Douglas Christopher Wilson +Copyright (c) 2015-2022 Douglas Christopher Wilson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -21170,6 +21408,31 @@ OTHER DEALINGS IN THE SOFTWARE. ----- +The following software may be included in this product: moment-jdateformatparser. A copy of the source code may be downloaded from https://github.com/MadMG/moment-jdateformatparser. This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2013 MadMG + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: moment-timezone. A copy of the source code may be downloaded from https://github.com/moment/moment-timezone.git. This software contains the following license and notice below: The MIT License (MIT) @@ -21975,11 +22238,89 @@ SOFTWARE. ----- -The following software may be included in this product: object-inspect. A copy of the source code may be downloaded from git://github.com/inspect-js/object-inspect.git. This software contains the following license and notice below: +The following software may be included in this product: object-inspect. A copy of the source code may be downloaded from git://github.com/inspect-js/object-inspect.git. This software contains the following license and notice below: + +MIT License + +Copyright (c) 2013 James Halliday + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + +The following software may be included in this product: object-keys. A copy of the source code may be downloaded from git://github.com/ljharb/object-keys.git. This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (C) 2013 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +----- + +The following software may be included in this product: object.assign. A copy of the source code may be downloaded from git://github.com/ljharb/object.assign.git. This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2014 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + +The following software may be included in this product: object.hasown. A copy of the source code may be downloaded from https://github.com/es-shims/Object.hasOwn.git. This software contains the following license and notice below: -MIT License +The MIT License (MIT) -Copyright (c) 2013 James Halliday +Copyright (c) 2016 Glen Mailer, Jordan Harband, and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -22001,11 +22342,11 @@ SOFTWARE. ----- -The following software may be included in this product: object-keys. A copy of the source code may be downloaded from git://github.com/ljharb/object-keys.git. This software contains the following license and notice below: +The following software may be included in this product: obliterator. A copy of the source code may be downloaded from git+https://github.com/yomguithereal/obliterator.git. This software contains the following license and notice below: The MIT License (MIT) -Copyright (C) 2013 Jordan Harband +Copyright (c) 2017 Guillaume Plique (Yomguithereal) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -22027,81 +22368,31 @@ THE SOFTWARE. ----- -The following software may be included in this product: object.assign. A copy of the source code may be downloaded from git://github.com/ljharb/object.assign.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2014 Jordan Harband - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The following software may be included in this product: on-finished. A copy of the source code may be downloaded from https://github.com/jshttp/on-finished.git. This software contains the following license and notice below: ------ - -The following software may be included in this product: object.hasown. A copy of the source code may be downloaded from https://github.com/es-shims/Object.hasOwn.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2016 Glen Mailer, Jordan Harband, and contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: obliterator. A copy of the source code may be downloaded from git+https://github.com/yomguithereal/obliterator.git. This software contains the following license and notice below: - -The MIT License (MIT) +(The MIT License) -Copyright (c) 2017 Guillaume Plique (Yomguithereal) +Copyright (c) 2013 Jonathan Ong +Copyright (c) 2014 Douglas Christopher Wilson -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- @@ -22253,6 +22544,34 @@ THE SOFTWARE. ----- +The following software may be included in this product: parseurl. A copy of the source code may be downloaded from https://github.com/pillarjs/parseurl.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2014 Jonathan Ong +Copyright (c) 2014-2017 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: path-parse. A copy of the source code may be downloaded from https://github.com/jbgutierrez/path-parse.git. This software contains the following license and notice below: The MIT License (MIT) @@ -29131,6 +29450,61 @@ SOFTWARE. ----- +The following software may be included in this product: range-parser. A copy of the source code may be downloaded from https://github.com/jshttp/range-parser.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2012-2014 TJ Holowaychuk +Copyright (c) 2015-2016 Douglas Christopher Wilson +Copyright (c) 2014-2022 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +----- + The following software may be included in this product: rc-config-loader. A copy of the source code may be downloaded from https://github.com/azu/rc-config-loader.git. This software contains the following license and notice below: Copyright (c) 2017 azu @@ -30446,6 +30820,34 @@ Apache-2.0 License Summary ----- +The following software may be included in this product: send. A copy of the source code may be downloaded from https://github.com/pillarjs/send.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2012 TJ Holowaychuk +Copyright (c) 2014-2022 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: seq-queue. A copy of the source code may be downloaded from git@github.com:changchang/seq-queue.git. This software contains the following license and notice below: (The MIT License) @@ -30505,6 +30907,36 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----- +The following software may be included in this product: serve-static. A copy of the source code may be downloaded from https://github.com/expressjs/serve-static.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2010 Sencha Inc. +Copyright (c) 2011 LearnBoost +Copyright (c) 2011 TJ Holowaychuk +Copyright (c) 2014-2016 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: set-function-name. A copy of the source code may be downloaded from git+https://github.com/ljharb/set-function-name.git. This software contains the following license and notice below: MIT License @@ -30556,6 +30988,24 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- +The following software may be included in this product: setprototypeof. A copy of the source code may be downloaded from https://github.com/wesleytodd/setprototypeof.git. This software contains the following license and notice below: + +Copyright (c) 2015, Wes Todd + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +----- + The following software may be included in this product: shallow-clone, to-regex-range, use. A copy of the source code may be downloaded from https://github.com/jonschlinkert/shallow-clone.git (shallow-clone), https://github.com/micromatch/to-regex-range.git (to-regex-range), https://github.com/jonschlinkert/use.git (use). This software contains the following license and notice below: The MIT License (MIT) @@ -31168,6 +31618,33 @@ THE SOFTWARE. ----- +The following software may be included in this product: statuses. A copy of the source code may be downloaded from https://github.com/jshttp/statuses.git. This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2014 Jonathan Ong +Copyright (c) 2016 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +----- + The following software may be included in this product: stream-browserify. A copy of the source code may be downloaded from git://github.com/browserify/stream-browserify.git. This software contains the following license and notice below: MIT License @@ -31803,6 +32280,32 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI ----- +The following software may be included in this product: toidentifier. A copy of the source code may be downloaded from https://github.com/component/toidentifier.git. This software contains the following license and notice below: + +MIT License + +Copyright (c) 2016 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + The following software may be included in this product: tough-cookie. A copy of the source code may be downloaded from git://github.com/salesforce/tough-cookie.git. This software contains the following license and notice below: Copyright (c) 2015, Salesforce.com, Inc. @@ -31950,32 +32453,6 @@ SOFTWARE. ----- -The following software may be included in this product: ts-node. A copy of the source code may be downloaded from git://github.com/TypeStrong/ts-node.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - The following software may be included in this product: tsconfig-paths. A copy of the source code may be downloaded from https://github.com/dividab/tsconfig-paths. This software contains the following license and notice below: The MIT License (MIT) @@ -32260,11 +32737,265 @@ SOFTWARE. ----- -The following software may be included in this product: unfetch. A copy of the source code may be downloaded from https://github.com/developit/unfetch.git. This software contains the following license and notice below: +The following software may be included in this product: unfetch. A copy of the source code may be downloaded from https://github.com/developit/unfetch.git. This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2017 Jason Miller + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + +The following software may be included in this product: unique-filename. A copy of the source code may be downloaded from https://github.com/npm/unique-filename.git. This software contains the following license and notice below: + +Copyright npm, Inc + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +----- + +The following software may be included in this product: unique-slug. A copy of the source code may be downloaded from https://github.com/npm/unique-slug.git. This software contains the following license and notice below: + +The ISC License + +Copyright npm, Inc + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +----- + +The following software may be included in this product: universal-cookie. A copy of the source code may be downloaded from https://github.com/reactivestack/cookies.git. This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2015 Benoit Tremblay + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +----- + +The following software may be included in this product: universal-user-agent. A copy of the source code may be downloaded from https://github.com/gr2m/universal-user-agent.git. This software contains the following license and notice below: + +# [ISC License](https://spdx.org/licenses/ISC) + +Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m) + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +----- + +The following software may be included in this product: universalify. A copy of the source code may be downloaded from git+https://github.com/RyanZim/universalify.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2017, Ryan Zimmerman + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the 'Software'), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + +The following software may be included in this product: unpipe. A copy of the source code may be downloaded from https://github.com/stream-utils/unpipe.git. This software contains the following license and notice below: + +(The MIT License) + +Copyright (c) 2015 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + +The following software may be included in this product: upath. A copy of the source code may be downloaded from git://github.com/anodynos/upath. This software contains the following license and notice below: + +Copyright(c) 2014-2020 Angelos Pikoulas (agelos.pikoulas@gmail.com) + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +----- + +The following software may be included in this product: update-browserslist-db. A copy of the source code may be downloaded from https://github.com/browserslist/update-db.git. This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright 2022 Andrey Sitnik and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + +The following software may be included in this product: update-notifier. A copy of the source code may be downloaded from https://github.com/yeoman/update-notifier.git. This software contains the following license and notice below: + +Copyright Google + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----- + +The following software may be included in this product: uri-js. A copy of the source code may be downloaded from http://github.com/garycourt/uri-js. This software contains the following license and notice below: + +Copyright 2011 Gary Court. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY GARY COURT "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARY COURT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of Gary Court. + +----- + +The following software may be included in this product: url. A copy of the source code may be downloaded from https://github.com/defunctzombie/node-url.git. This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright Joyent, Inc. and other Node contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + +The following software may be included in this product: url. A copy of the source code may be downloaded from https://github.com/defunctzombie/node-url.git. This software contains the following license and notice below: The MIT License (MIT) -Copyright (c) 2017 Jason Miller +Copyright 2014 Joyent, Inc. and other Node contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -32286,102 +33017,11 @@ SOFTWARE. ----- -The following software may be included in this product: unique-filename. A copy of the source code may be downloaded from https://github.com/npm/unique-filename.git. This software contains the following license and notice below: - -Copyright npm, Inc - -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ------ - -The following software may be included in this product: unique-slug. A copy of the source code may be downloaded from https://github.com/npm/unique-slug.git. This software contains the following license and notice below: - -The ISC License - -Copyright npm, Inc - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ------ - -The following software may be included in this product: universal-cookie. A copy of the source code may be downloaded from https://github.com/reactivestack/cookies.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2015 Benoit Tremblay - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - -The following software may be included in this product: universal-user-agent. A copy of the source code may be downloaded from https://github.com/gr2m/universal-user-agent.git. This software contains the following license and notice below: - -# [ISC License](https://spdx.org/licenses/ISC) - -Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m) - -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ------ - -The following software may be included in this product: universalify. A copy of the source code may be downloaded from git+https://github.com/RyanZim/universalify.git. This software contains the following license and notice below: +The following software may be included in this product: util-deprecate. A copy of the source code may be downloaded from git://github.com/TooTallNate/util-deprecate.git. This software contains the following license and notice below: (The MIT License) -Copyright (c) 2017, Ryan Zimmerman - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the 'Software'), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - -The following software may be included in this product: upath. A copy of the source code may be downloaded from git://github.com/anodynos/upath. This software contains the following license and notice below: - -Copyright(c) 2014-2020 Angelos Pikoulas (agelos.pikoulas@gmail.com) +Copyright (c) 2014 Nathan Rajlich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation @@ -32406,11 +33046,11 @@ OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: update-browserslist-db. A copy of the source code may be downloaded from https://github.com/browserslist/update-db.git. This software contains the following license and notice below: +The following software may be included in this product: utils-merge. A copy of the source code may be downloaded from git://github.com/jaredhanson/utils-merge.git. This software contains the following license and notice below: The MIT License (MIT) -Copyright 2022 Andrey Sitnik and other contributors +Copyright (c) 2013-2017 Jared Hanson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -32431,117 +33071,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: update-notifier. A copy of the source code may be downloaded from https://github.com/yeoman/update-notifier.git. This software contains the following license and notice below: - -Copyright Google - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------ - -The following software may be included in this product: uri-js. A copy of the source code may be downloaded from http://github.com/garycourt/uri-js. This software contains the following license and notice below: - -Copyright 2011 Gary Court. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY GARY COURT "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARY COURT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of Gary Court. - ------ - -The following software may be included in this product: url. A copy of the source code may be downloaded from https://github.com/defunctzombie/node-url.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright Joyent, Inc. and other Node contributors. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: url. A copy of the source code may be downloaded from https://github.com/defunctzombie/node-url.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright 2014 Joyent, Inc. and other Node contributors. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: util-deprecate. A copy of the source code may be downloaded from git://github.com/TooTallNate/util-deprecate.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2014 Nathan Rajlich - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: uuid. A copy of the source code may be downloaded from https://github.com/uuidjs/uuid.git. This software contains the following license and notice below: The MIT License (MIT) @@ -32689,6 +33218,32 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- +The following software may be included in this product: value-or-promise. A copy of the source code may be downloaded from https://github.com/yaacovCR/value-or-promise. This software contains the following license and notice below: + +MIT License + +Copyright (c) 2019 Yaacov Rydzinski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + The following software may be included in this product: w3c-hr-time. A copy of the source code may be downloaded from https://github.com/jsdom/w3c-hr-time. This software contains the following license and notice below: # The MIT License (MIT) @@ -33284,6 +33839,31 @@ SOFTWARE. ----- +The following software may be included in this product: ws. A copy of the source code may be downloaded from git+https://github.com/websockets/ws.git. This software contains the following license and notice below: + +Copyright (c) 2011 Einar Otto Stangvik +Copyright (c) 2013 Arnout Kazemier and contributors +Copyright (c) 2016 Luigi Pinca and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: xml. A copy of the source code may be downloaded from http://github.com/dylang/node-xml. This software contains the following license and notice below: (The MIT License) diff --git a/packages/amplify-graphql-migration-tests/CHANGELOG.md b/packages/amplify-graphql-migration-tests/CHANGELOG.md deleted file mode 100644 index 648d823d0b..0000000000 --- a/packages/amplify-graphql-migration-tests/CHANGELOG.md +++ /dev/null @@ -1,515 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [2.4.38](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.37...amplify-category-api-graphql-migration-tests@2.4.38) (2024-08-12) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.37](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.36...amplify-category-api-graphql-migration-tests@2.4.37) (2024-07-25) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.36](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.35...amplify-category-api-graphql-migration-tests@2.4.36) (2024-07-15) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.35](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.34...amplify-category-api-graphql-migration-tests@2.4.35) (2024-07-02) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.34](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.33...amplify-category-api-graphql-migration-tests@2.4.34) (2024-07-01) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.33](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.32...amplify-category-api-graphql-migration-tests@2.4.33) (2024-06-25) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.32](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.31...amplify-category-api-graphql-migration-tests@2.4.32) (2024-06-06) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.31](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.30...amplify-category-api-graphql-migration-tests@2.4.31) (2024-06-04) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.30](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.29...amplify-category-api-graphql-migration-tests@2.4.30) (2024-05-15) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.29](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.28...amplify-category-api-graphql-migration-tests@2.4.29) (2024-05-10) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.28](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.27...amplify-category-api-graphql-migration-tests@2.4.28) (2024-05-01) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.27](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.26...amplify-category-api-graphql-migration-tests@2.4.27) (2024-04-26) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.26](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.25...amplify-category-api-graphql-migration-tests@2.4.26) (2024-04-16) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.25](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.24...amplify-category-api-graphql-migration-tests@2.4.25) (2024-04-11) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.24](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.23...amplify-category-api-graphql-migration-tests@2.4.24) (2024-03-28) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.23](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.22...amplify-category-api-graphql-migration-tests@2.4.23) (2024-03-13) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.22](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.21...amplify-category-api-graphql-migration-tests@2.4.22) (2024-02-28) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.21](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.20...amplify-category-api-graphql-migration-tests@2.4.21) (2024-02-05) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.20](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.19...amplify-category-api-graphql-migration-tests@2.4.20) (2024-01-30) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.19](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.18...amplify-category-api-graphql-migration-tests@2.4.19) (2024-01-22) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.18](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.17...amplify-category-api-graphql-migration-tests@2.4.18) (2023-12-21) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.17](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.16...amplify-category-api-graphql-migration-tests@2.4.17) (2023-12-18) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.16](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.15...amplify-category-api-graphql-migration-tests@2.4.16) (2023-12-14) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.15](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.14...amplify-category-api-graphql-migration-tests@2.4.15) (2023-12-06) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.14](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.13...amplify-category-api-graphql-migration-tests@2.4.14) (2023-11-22) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.13](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.12...amplify-category-api-graphql-migration-tests@2.4.13) (2023-11-18) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.12](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.11...amplify-category-api-graphql-migration-tests@2.4.12) (2023-11-16) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.11](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.10...amplify-category-api-graphql-migration-tests@2.4.11) (2023-11-15) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.10](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.9...amplify-category-api-graphql-migration-tests@2.4.10) (2023-11-02) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.9](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.8...amplify-category-api-graphql-migration-tests@2.4.9) (2023-10-21) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.8](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.7...amplify-category-api-graphql-migration-tests@2.4.8) (2023-10-12) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.7](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.6...amplify-category-api-graphql-migration-tests@2.4.7) (2023-10-05) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.6](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.5...amplify-category-api-graphql-migration-tests@2.4.6) (2023-10-03) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.5](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.4...amplify-category-api-graphql-migration-tests@2.4.5) (2023-10-02) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.4](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.3...amplify-category-api-graphql-migration-tests@2.4.4) (2023-09-20) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.3](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.2...amplify-category-api-graphql-migration-tests@2.4.3) (2023-09-07) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.2](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.1...amplify-category-api-graphql-migration-tests@2.4.2) (2023-08-30) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.4.1](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.4.0...amplify-category-api-graphql-migration-tests@2.4.1) (2023-08-28) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -# [2.4.0](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.42...amplify-category-api-graphql-migration-tests@2.4.0) (2023-08-09) - -### Features - -- bump major version of transformer packages ([2458c84](https://github.com/aws-amplify/amplify-category-api/commit/2458c8426da5772aa669d37e11f99ee9c6c5ac2e)) - -## [2.3.42](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.41...amplify-category-api-graphql-migration-tests@2.3.42) (2023-07-21) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.41](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.40...amplify-category-api-graphql-migration-tests@2.3.41) (2023-07-17) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.40](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.39...amplify-category-api-graphql-migration-tests@2.3.40) (2023-07-07) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.39](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.38...amplify-category-api-graphql-migration-tests@2.3.39) (2023-07-07) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.38](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.37...amplify-category-api-graphql-migration-tests@2.3.38) (2023-07-07) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.37](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.36...amplify-category-api-graphql-migration-tests@2.3.37) (2023-06-29) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.36](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.35...amplify-category-api-graphql-migration-tests@2.3.36) (2023-06-20) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.35](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.34...amplify-category-api-graphql-migration-tests@2.3.35) (2023-06-05) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.34](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.33...amplify-category-api-graphql-migration-tests@2.3.34) (2023-05-23) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.33](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.32...amplify-category-api-graphql-migration-tests@2.3.33) (2023-05-17) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.32](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.31...amplify-category-api-graphql-migration-tests@2.3.32) (2023-04-25) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.31](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.30...amplify-category-api-graphql-migration-tests@2.3.31) (2023-03-30) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.30](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.29...amplify-category-api-graphql-migration-tests@2.3.30) (2023-03-15) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.29](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.28...amplify-category-api-graphql-migration-tests@2.3.29) (2023-03-01) - -### Bug Fixes - -- lock CDK v2 version ([#923](https://github.com/aws-amplify/amplify-category-api/issues/923)) ([2afe40c](https://github.com/aws-amplify/amplify-category-api/commit/2afe40cf13e7d1ee7db37988b9b3297768c7bd0a)) -- migrate to cdkv2 - e2e tests fixes ([#910](https://github.com/aws-amplify/amplify-category-api/issues/910)) ([c7b2503](https://github.com/aws-amplify/amplify-category-api/commit/c7b250361bf0c82fc067e03675101b9dfb6a25de)) - -## [2.3.28](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.27...amplify-category-api-graphql-migration-tests@2.3.28) (2023-02-27) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.27](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.26...amplify-category-api-graphql-migration-tests@2.3.27) (2023-02-15) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.26](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.25...amplify-category-api-graphql-migration-tests@2.3.26) (2023-02-10) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.25](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.24...amplify-category-api-graphql-migration-tests@2.3.25) (2023-01-26) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.24](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.23...amplify-category-api-graphql-migration-tests@2.3.24) (2023-01-12) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.23](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.22...amplify-category-api-graphql-migration-tests@2.3.23) (2023-01-12) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.22](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.21...amplify-category-api-graphql-migration-tests@2.3.22) (2022-12-13) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.21](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.20...amplify-category-api-graphql-migration-tests@2.3.21) (2022-12-09) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.20](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.19...amplify-category-api-graphql-migration-tests@2.3.20) (2022-12-03) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.19](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.18...amplify-category-api-graphql-migration-tests@2.3.19) (2022-11-08) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.18](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.17...amplify-category-api-graphql-migration-tests@2.3.18) (2022-11-04) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.17](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.16...amplify-category-api-graphql-migration-tests@2.3.17) (2022-10-26) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.16](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.15...amplify-category-api-graphql-migration-tests@2.3.16) (2022-10-24) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.15](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.14...amplify-category-api-graphql-migration-tests@2.3.15) (2022-10-04) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.14](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.13...amplify-category-api-graphql-migration-tests@2.3.14) (2022-09-20) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.13](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.12...amplify-category-api-graphql-migration-tests@2.3.13) (2022-09-14) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.12](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.11...amplify-category-api-graphql-migration-tests@2.3.12) (2022-08-23) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.11](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.10...amplify-category-api-graphql-migration-tests@2.3.11) (2022-08-18) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.10](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.9...amplify-category-api-graphql-migration-tests@2.3.10) (2022-08-18) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.9](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.8...amplify-category-api-graphql-migration-tests@2.3.9) (2022-08-18) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.8](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.7...amplify-category-api-graphql-migration-tests@2.3.8) (2022-08-16) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.7](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.6...amplify-category-api-graphql-migration-tests@2.3.7) (2022-08-04) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.6](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.5...amplify-category-api-graphql-migration-tests@2.3.6) (2022-07-26) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.5](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.3...amplify-category-api-graphql-migration-tests@2.3.5) (2022-07-20) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.4](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.3...amplify-category-api-graphql-migration-tests@2.3.4) (2022-07-14) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.3](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.2...amplify-category-api-graphql-migration-tests@2.3.3) (2022-07-01) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.2](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.1...amplify-category-api-graphql-migration-tests@2.3.2) (2022-06-23) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -## [2.3.1](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-graphql-migration-tests@2.3.0...amplify-category-api-graphql-migration-tests@2.3.1) (2022-06-13) - -**Note:** Version bump only for package amplify-category-api-graphql-migration-tests - -# 2.3.0 (2022-06-10) - -### Bug Fixes - -- move [@model](https://github.com/model) params to root stack and fix ds logical id ([#8736](https://github.com/aws-amplify/amplify-category-api/issues/8736)) ([df4408c](https://github.com/aws-amplify/amplify-category-api/commit/df4408c4080949ddd638778df9ae20e763dd5824)) - -### Features - -- **amplify-category-api:** rename private packages to scope them down ([e131d06](https://github.com/aws-amplify/amplify-category-api/commit/e131d06463745d448a699e0e75eedd040c167d9d)) - -## [2.2.43](https://github.com/aws-amplify/amplify-category-api/compare/amplify-graphql-migration-tests@2.2.42...amplify-graphql-migration-tests@2.2.43) (2022-06-10) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.42](https://github.com/aws-amplify/amplify-category-api/compare/amplify-graphql-migration-tests@2.2.39...amplify-graphql-migration-tests@2.2.42) (2022-06-07) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.41](https://github.com/aws-amplify/amplify-category-api/compare/amplify-graphql-migration-tests@2.2.39...amplify-graphql-migration-tests@2.2.41) (2022-05-31) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.40](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.39...amplify-graphql-migration-tests@2.2.40) (2022-05-02) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.39](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.38...amplify-graphql-migration-tests@2.2.39) (2022-04-29) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.38](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.37...amplify-graphql-migration-tests@2.2.38) (2022-04-27) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.37](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.36...amplify-graphql-migration-tests@2.2.37) (2022-04-18) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.36](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.35...amplify-graphql-migration-tests@2.2.36) (2022-04-11) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.35](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.34...amplify-graphql-migration-tests@2.2.35) (2022-04-07) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.34](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.33...amplify-graphql-migration-tests@2.2.34) (2022-03-23) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.33](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.32...amplify-graphql-migration-tests@2.2.33) (2022-03-17) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.32](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.31...amplify-graphql-migration-tests@2.2.32) (2022-03-14) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.31](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.30...amplify-graphql-migration-tests@2.2.31) (2022-03-07) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.30](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.29...amplify-graphql-migration-tests@2.2.30) (2022-02-25) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.29](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.28...amplify-graphql-migration-tests@2.2.29) (2022-02-15) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.28](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.24...amplify-graphql-migration-tests@2.2.28) (2022-02-10) - -## 7.6.19 (2022-02-08) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.24](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.23...amplify-graphql-migration-tests@2.2.24) (2022-02-03) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.23](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.22...amplify-graphql-migration-tests@2.2.23) (2022-01-31) - -## 7.6.14 (2022-01-28) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.22](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.21...amplify-graphql-migration-tests@2.2.22) (2022-01-27) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.21](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.20...amplify-graphql-migration-tests@2.2.21) (2022-01-23) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.20](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.19...amplify-graphql-migration-tests@2.2.20) (2022-01-20) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.19](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.18...amplify-graphql-migration-tests@2.2.19) (2022-01-20) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.18](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.17...amplify-graphql-migration-tests@2.2.18) (2022-01-13) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.17](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.15...amplify-graphql-migration-tests@2.2.17) (2022-01-10) - -## 7.6.7 (2022-01-10) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.15](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.14...amplify-graphql-migration-tests@2.2.15) (2021-12-21) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.14](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.13...amplify-graphql-migration-tests@2.2.14) (2021-12-17) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.13](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.12...amplify-graphql-migration-tests@2.2.13) (2021-12-03) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.12](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.11...amplify-graphql-migration-tests@2.2.12) (2021-12-02) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.11](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.10...amplify-graphql-migration-tests@2.2.11) (2021-12-01) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.10](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.9...amplify-graphql-migration-tests@2.2.10) (2021-11-29) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.9](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.8...amplify-graphql-migration-tests@2.2.9) (2021-11-26) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.8](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.7...amplify-graphql-migration-tests@2.2.8) (2021-11-24) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.6...amplify-graphql-migration-tests@2.2.7) (2021-11-23) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.5...amplify-graphql-migration-tests@2.2.6) (2021-11-21) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.4...amplify-graphql-migration-tests@2.2.5) (2021-11-20) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.2...amplify-graphql-migration-tests@2.2.4) (2021-11-19) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.2...amplify-graphql-migration-tests@2.2.3) (2021-11-19) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@2.2.1...amplify-graphql-migration-tests@2.2.2) (2021-11-17) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## [2.2.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@1.0.1...amplify-graphql-migration-tests@2.2.1) (2021-11-15) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -# [2.0.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-graphql-migration-tests@1.0.1...amplify-graphql-migration-tests@2.0.0) (2021-11-13) - -**Note:** Version bump only for package amplify-graphql-migration-tests - -## 1.0.1 (2021-11-11) - -### Bug Fixes - -- move [@model](https://github.com/model) params to root stack and fix ds logical id ([#8736](https://github.com/aws-amplify/amplify-cli/issues/8736)) ([df4408c](https://github.com/aws-amplify/amplify-cli/commit/df4408c4080949ddd638778df9ae20e763dd5824)) diff --git a/packages/amplify-graphql-migration-tests/package.json b/packages/amplify-graphql-migration-tests/package.json deleted file mode 100644 index 16a017deb6..0000000000 --- a/packages/amplify-graphql-migration-tests/package.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "name": "amplify-category-api-graphql-migration-tests", - "version": "2.4.38", - "description": "Tests migration from v1 to v2 of the Amplify GraphQL transformer", - "main": "lib/index.js", - "private": true, - "scripts": { - "test": "jest" - }, - "repository": { - "type": "git", - "url": "https://github.com/aws-amplify/amplify-category-api.git", - "directory": "packages/amplify-schema-migrator-tests" - }, - "keywords": [ - "graphql", - "transformer", - "migration", - "test" - ], - "author": "Amazon Web Services", - "license": "Apache-2.0", - "jest": { - "collectCoverage": true, - "coverageProvider": "v8", - "coverageThreshold": { - "global": { - "branches": 78, - "functions": 78, - "lines": 90 - } - }, - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, - "coverageReporters": [ - "clover", - "text" - ], - "testURL": "http://localhost", - "testRegex": "((\\.|/)(test|spec))\\.(jsx?|tsx?)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], - "testEnvironment": "../../FixJestEnvironment.js", - "collectCoverageFrom": [ - "src/**/*.ts" - ], - "coveragePathIgnorePatterns": [ - "/__tests__/" - ] - }, - "devDependencies": { - "@aws-amplify/graphql-auth-transformer": "3.6.5", - "@aws-amplify/graphql-default-value-transformer": "2.3.13", - "@aws-amplify/graphql-function-transformer": "2.1.26", - "@aws-amplify/graphql-http-transformer": "2.1.26", - "@aws-amplify/graphql-index-transformer": "2.4.9", - "@aws-amplify/graphql-model-transformer": "2.11.4", - "@aws-amplify/graphql-relational-transformer": "2.5.11", - "@aws-amplify/graphql-transformer-core": "2.9.3", - "@aws-amplify/graphql-transformer-interfaces": "3.10.1", - "@aws-amplify/graphql-transformer-migrator": "2.2.27", - "@aws-amplify/graphql-transformer-test-utils": "0.5.6", - "@aws-cdk/cloudformation-diff": "~2.80.0", - "aws-cdk-lib": "~2.129.0", - "fs-extra": "^8.1.0", - "graphql-auth-transformer": "7.2.82", - "graphql-connection-transformer": "5.2.80", - "graphql-dynamodb-transformer": "7.2.80", - "graphql-http-transformer": "5.2.80", - "graphql-key-transformer": "3.2.80", - "graphql-transformer-core": "8.2.13", - "graphql-versioned-transformer": "5.2.80" - }, - "peerDependencies": { - "@aws-amplify/amplify-prompts": "^2.8.6" - } -} diff --git a/packages/amplify-graphql-migration-tests/src/__tests__/graphql-version-migration.test.ts b/packages/amplify-graphql-migration-tests/src/__tests__/graphql-version-migration.test.ts deleted file mode 100644 index 0ead46bb51..0000000000 --- a/packages/amplify-graphql-migration-tests/src/__tests__/graphql-version-migration.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import * as cdkDiff from '@aws-cdk/cloudformation-diff'; -import { ResourceImpact } from '@aws-cdk/cloudformation-diff'; -import { getTestCaseRegistry } from '../test-case-registry'; -import { v1transformerProvider } from '../v1-transformer-provider'; -import { v2Transform } from '../v2-transformer-provider'; -import { migrateSchema } from '../migrate-schema-wrapper'; -import { getNestedStackDiffRules } from '../nested-stack-diff-rules'; - -describe('v1 to v2 migration', () => { - test.concurrent.each(getTestCaseRegistry())( - `validate %s schema migration`, - async (_, schema, v1TransformerConfig, v2TransformerConfig) => { - // run v1 transformer - const v1Transformer = v1transformerProvider(v1TransformerConfig); - const v1result = v1Transformer.transform(schema); - - // migrate schema from v1 to v2 - const migratedSchema = await migrateSchema(schema); - - // run v2 transformer - const v2result = v2Transform(migratedSchema, v2TransformerConfig); - - // get initial nested stack names - // TODO will probably have to update the logic a bit if we want to test @searchable migrations here as that will create a SearchableStack that we need to account for - const v1nestedStackNames = Object.keys(v1result.stacks).filter((stackName) => stackName !== 'ConnectionStack'); // The v1 transformer puts all connection resolvers in a 'ConnectionStack'. This stack does not define any data resources - - // verify root stack diff - const diff = cdkDiff.diffTemplate(v1result.rootStack, v2result.rootStack); - v1nestedStackNames.forEach((stackName) => { - try { - expect([ResourceImpact.WILL_UPDATE, ResourceImpact.NO_CHANGE]).toContain(diff.resources.changes[stackName].changeImpact); - } catch (err) { - console.log(`${stackName} not in correct state`); - throw err; - } - }); - - // verify nested stack diffs - const nestedStackDiffRules = getNestedStackDiffRules(); - v1nestedStackNames.forEach((stackName) => { - const nestedStackDiff = cdkDiff.diffTemplate(v1result.stacks[stackName], v2result.stacks[stackName]); - nestedStackDiffRules.forEach((rule) => rule(stackName, nestedStackDiff)); - }); - }, - ); -}); diff --git a/packages/amplify-graphql-migration-tests/src/feature-flag-stub.ts b/packages/amplify-graphql-migration-tests/src/feature-flag-stub.ts deleted file mode 100644 index 3f544b2f0a..0000000000 --- a/packages/amplify-graphql-migration-tests/src/feature-flag-stub.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const featureFlagProviderStub = { - getBoolean: () => true, - getNumber: () => 0, - getObject: () => ({}), -}; diff --git a/packages/amplify-graphql-migration-tests/src/migrate-schema-wrapper.ts b/packages/amplify-graphql-migration-tests/src/migrate-schema-wrapper.ts deleted file mode 100644 index e8e940d1de..0000000000 --- a/packages/amplify-graphql-migration-tests/src/migrate-schema-wrapper.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { runMigration } from '@aws-amplify/graphql-transformer-migrator'; -import * as fs from 'fs-extra'; -import { prompter } from '@aws-amplify/amplify-prompts'; - -jest.mock('fs-extra'); -jest.mock('@aws-amplify/amplify-prompts'); - -const fs_mock = fs as jest.Mocked; -const prompter_mock = prompter as jest.Mocked; - -export type AuthMode = 'apiKey' | 'iam' | 'userPools' | 'oidc'; - -export const migrateSchema = async (schema: string, authMode: AuthMode = 'apiKey'): Promise => { - const pathHash = Date.now().toLocaleString().replace(/,/g, ''); - fs_mock.writeFile.mockClear(); - prompter_mock.pick.mockResolvedValue('Yes'); - await runMigration([{ schema, filePath: pathHash }], authMode); - const transformedSchema = fs_mock.writeFile.mock.calls.find(([hash]) => hash === pathHash)?.[1]; - expect(typeof transformedSchema).toBe('string'); - return transformedSchema; -}; diff --git a/packages/amplify-graphql-migration-tests/src/nested-stack-diff-rules.ts b/packages/amplify-graphql-migration-tests/src/nested-stack-diff-rules.ts deleted file mode 100644 index f1facd7a29..0000000000 --- a/packages/amplify-graphql-migration-tests/src/nested-stack-diff-rules.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { ResourceImpact, TemplateDiff } from '@aws-cdk/cloudformation-diff'; - -export const getNestedStackDiffRules = (): NestedStackDiffRule[] => [ - onlyUpdatesTableNameProperty, - tableNameResolvesToSameName, - dataSourceLogicalIdsAreSame, -]; - -/** - * The table name is not actually updated but the way it's defined is changed (tableNameResolvesToSameName will check the table name) - * This check asserts that no other table properties were changed by the migration (GSIs, LSIs, etc) - * @param stackName The name of the nested stack - * @param diff The diff of the nested stack - */ -const onlyUpdatesTableNameProperty = (stackName: string, diff: TemplateDiff) => { - const propertyUpdates = diff.resources.changes[`${stackName}Table`].propertyUpdates; - try { - expect(Object.keys(propertyUpdates)).toEqual(['TableName']); // The table name should resolve to the same value but the way it's defined is different so it shows up here as a diff - } catch (err) { - console.error(`Expected only TableName update for table ${stackName}Table. Instead got updates:`); - console.log(JSON.stringify(propertyUpdates, undefined, 2)); - throw err; - } -}; - -const tableNameResolvesToSameName = (stackName: string, diff: TemplateDiff) => { - const propertyUpdates = diff.resources.changes[`${stackName}Table`].propertyUpdates; - const newTableName = propertyUpdates.TableName.newValue; - expect(newTableName['Fn::Join']).toBeDefined(); - const joinParams = newTableName['Fn::Join']; - const joinStr = joinParams[0] as string; - const joinElements = joinParams[1] as any[]; - - const apiId = 'testApiId'; - const env = 'testEnv'; - - const replacedElements = joinElements.map((el) => { - if (typeof el?.Ref === 'string') { - if (el.Ref.startsWith('referencetotransformerrootstackGraphQLAPI')) { - return apiId; - } - if (el.Ref.startsWith('referencetotransformerrootstackenv')) { - return env; - } - } - return el; - }); - const finalTableName = replacedElements.join(joinStr); - expect(finalTableName).toEqual(`${stackName}-${apiId}-${env}`); -}; - -const dataSourceLogicalIdsAreSame = (_: string, diff: TemplateDiff) => { - const areDataSourcesReplaced = Object.values(diff.resources.changes) - .filter((diff) => diff.resourceType === 'AWS::AppSync::DataSource') - .map((diff) => diff.changeImpact === ResourceImpact.WILL_REPLACE) - .reduce((acc, it) => acc && it, true); - expect(areDataSourcesReplaced).toBe(true); -}; - -export type NestedStackDiffRule = (stackName: string, diff: TemplateDiff) => void; diff --git a/packages/amplify-graphql-migration-tests/src/test-case-registry.ts b/packages/amplify-graphql-migration-tests/src/test-case-registry.ts deleted file mode 100644 index 8a1c884094..0000000000 --- a/packages/amplify-graphql-migration-tests/src/test-case-registry.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { TestEntry } from './test-case-types'; - -/* - REGISTER TEST CASES HERE! -*/ -export const getTestCaseRegistry = (): TestEntry[] => [ - ['bi-di connection', biDiConnectionSchema], - ['many to many', manyToManySchema], - ['recursive', recursiveSchema], - ['compound sort key', compoundSortKey], - ['custom primary key', customPrimaryKey], - ['connection on custom primary key', connectionOnCustomPrimaryKey], - ['support renaming timestamps', renameTimestampFields], - /* - [ - 'add additional tests with a descriptive name', - schemaObject // define the schema below and reference it here. If the schema is exceptionally large, consider importing it from another file - { - v1TransformerConfigObject // if the tests needs custom v1 transformer config, include it here (the framework currently has limited support for additional config so you may need to make updates) - }, - { - v2TransformerConfig: // same for v2 transformer - } - ] - */ -]; - -/* - DEFINE TEST SCHEMAS BELOW! -*/ - -const biDiConnectionSchema = /* GraphQL */ ` - type Blog @model { - id: ID! - name: String! - postID: ID - post: Post @connection(fields: ["postID"]) - } - - type Post @model { - id: ID! - title: String! - blogID: ID! - blog: Blog @connection(fields: ["blogID"]) - comments: [Comment] @connection(keyName: "byPost", fields: ["id"]) - } - - type Comment @model @key(name: "byPost", fields: ["postID"]) { - id: ID! - postID: ID! - post: Post @connection(fields: ["postID"]) - } -`; - -const manyToManySchema = /* GraphQL */ ` - type Post @model { - id: ID! - title: String! - editors: [PostEditor] @connection(keyName: "byPost", fields: ["id"]) - } - - type PostEditor - @model(queries: null) - @key(name: "byPost", fields: ["postId", "editorId"]) - @key(name: "byEditor", fields: ["editorId", "postId"]) { - id: ID! - postId: ID! - editorId: ID! - post: Post! @connection(fields: ["postId"]) - editor: User! @connection(fields: ["editorId"]) - } - - type User @model { - id: ID! - username: String! - posts: [PostEditor] @connection(keyName: "byEditor", fields: ["id"]) - } -`; - -const recursiveSchema = /* GraphQL */ ` - type Directory @model @key(name: "byParent", fields: ["parentId"]) { - id: ID! - parentId: ID! - parent: Directory @connection(fields: ["parentId"]) - children: [Directory] @connection(keyName: "byParent", fields: ["id"]) - } -`; - -const compoundSortKey = /* GraphQL */ ` - type Book @model @key(name: "byGenreAuthorPublishDate", fields: ["genre", "author", "publishDate"]) { - id: ID! - genre: String! - author: String! - publishDate: AWSDateTime! - } -`; - -const customPrimaryKey = /* GraphQL */ ` - type Book @model @key(fields: ["title", "author"]) { - title: String! - author: String! - genre: String - } -`; - -const connectionOnCustomPrimaryKey = /* GraphQL */ ` - type Member @model @key(fields: ["name", "signupTime"]) { - name: String! - signupTime: AWSDateTime! - activities: [Activity] @connection(keyName: "byMember", fields: ["name", "signupTime"]) - } - - type Activity @model @key(fields: ["type", "location", "duration"]) @key(name: "byMember", fields: ["memberName", "memberSignupTime"]) { - type: String! - location: String! - duration: Int! - memberName: String - memberSignupTime: AWSDateTime - member: Member @connection(fields: ["memberName", "memberSignupTime"]) - } -`; - -const namedHasManyBelongsToConnection = /* GraphQL */ ` - type PostConnection @model @auth(rules: [{ allow: public }]) { - id: ID! - title: String! - comments: [CommentConnection] @connection(name: "PostComments") - } - - type CommentConnection @model { - id: ID! - content: String! - post: PostConnection @connection(name: "PostComments") - } -`; - -const renameTimestampFields = /* GraphQL */ ` - type Post @model(timestamps: { createdAt: "made", updatedAt: "updated" }) { - id: ID! - title: String! - contents: String - } -`; diff --git a/packages/amplify-graphql-migration-tests/src/test-case-types.ts b/packages/amplify-graphql-migration-tests/src/test-case-types.ts deleted file mode 100644 index f0ff9c8334..0000000000 --- a/packages/amplify-graphql-migration-tests/src/test-case-types.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { TransformerPluginProvider } from '@aws-amplify/graphql-transformer-interfaces'; -import { ITransformer } from 'graphql-transformer-core'; - -// Defines a single test input -type TestName = string; -type Schema = string; -export type TestEntry = [TestName, Schema, V1TransformerTestConfig?, V2TransformerTestConfig?]; - -// If we need to vary other transformer config per test we can add additional parameters here -export type V1TransformerTestConfig = { - transformers: ITransformer[]; -}; - -// If we need to vary other transformer config per test we can add additional parameters here -export type V2TransformerTestConfig = { - transformers: TransformerPluginProvider[]; -}; diff --git a/packages/amplify-graphql-migration-tests/src/v1-transformer-provider.ts b/packages/amplify-graphql-migration-tests/src/v1-transformer-provider.ts deleted file mode 100644 index ade172b53d..0000000000 --- a/packages/amplify-graphql-migration-tests/src/v1-transformer-provider.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { VersionedModelTransformer } from 'graphql-versioned-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { HttpTransformer } from 'graphql-http-transformer'; -import { KeyTransformer } from 'graphql-key-transformer'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { featureFlagProviderStub } from './feature-flag-stub'; -import { V1TransformerTestConfig } from './test-case-types'; - -export const v1transformerProvider = (config: Partial = {}): GraphQLTransform => { - const subbedConfig: V1TransformerTestConfig = { ...getDefaultConfig(), ...config }; - - return new GraphQLTransform({ - transformers: subbedConfig.transformers, - transformConfig: { - Version: 5, - }, - featureFlags: featureFlagProviderStub, - }); -}; - -const getDefaultConfig = (): V1TransformerTestConfig => ({ - transformers: [ - new DynamoDBModelTransformer(), - new VersionedModelTransformer(), - new HttpTransformer(), - new KeyTransformer(), - new ModelConnectionTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - ], - }, - }), - ], -}); diff --git a/packages/amplify-graphql-migration-tests/src/v2-transformer-provider.ts b/packages/amplify-graphql-migration-tests/src/v2-transformer-provider.ts deleted file mode 100644 index 3760ff2493..0000000000 --- a/packages/amplify-graphql-migration-tests/src/v2-transformer-provider.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { DeploymentResources, testTransform } from '@aws-amplify/graphql-transformer-test-utils'; -import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; -import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer'; -import { FunctionTransformer } from '@aws-amplify/graphql-function-transformer'; -import { HttpTransformer } from '@aws-amplify/graphql-http-transformer'; -import { IndexTransformer, PrimaryKeyTransformer } from '@aws-amplify/graphql-index-transformer'; -import { - BelongsToTransformer, - HasManyTransformer, - HasOneTransformer, - ManyToManyTransformer, -} from '@aws-amplify/graphql-relational-transformer'; -import { DefaultValueTransformer } from '@aws-amplify/graphql-default-value-transformer'; -import { TransformerPluginProvider, AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; -import { V2TransformerTestConfig } from './test-case-types'; - -export const v2Transform = (schema: string, config: Partial = {}): DeploymentResources => - testTransform({ - schema, - transformers: config.transformers ?? getDefaultTransformers(), - authConfig: defaultAuthConfig, - transformParameters: { - sandboxModeEnabled: true, - }, - }); - -const getDefaultTransformers = () => { - const modelTransformer = new ModelTransformer(); - const indexTransformer = new IndexTransformer(); - const hasOneTransformer = new HasOneTransformer(); - - const authTransformer = new AuthTransformer(); - const transformers: TransformerPluginProvider[] = [ - modelTransformer, - new FunctionTransformer(), - new HttpTransformer(), - new PrimaryKeyTransformer(), - indexTransformer, - new BelongsToTransformer(), - new HasManyTransformer(), - hasOneTransformer, - new ManyToManyTransformer(modelTransformer, indexTransformer, hasOneTransformer, authTransformer), - new DefaultValueTransformer(), - authTransformer, - ]; - - return transformers; -}; - -const defaultAuthConfig: AppSyncAuthConfiguration = { - defaultAuthentication: { - authenticationType: 'API_KEY', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'AWS_IAM', - }, - { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - ], -}; diff --git a/packages/amplify-graphql-migration-tests/tsconfig.json b/packages/amplify-graphql-migration-tests/tsconfig.json deleted file mode 100644 index c59c141b71..0000000000 --- a/packages/amplify-graphql-migration-tests/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "./lib", - "rootDir": "./src" - }, - "references": [{ "path": "../amplify-function-plugin-interface" }, { "path": "../graphql-transformer-core" }] -} diff --git a/scripts/split-e2e-tests.ts b/scripts/split-e2e-tests.ts index 3d8406968e..3de2f1348b 100644 --- a/scripts/split-e2e-tests.ts +++ b/scripts/split-e2e-tests.ts @@ -79,13 +79,8 @@ const FORCE_REGION_MAP = { // some tests require additional time, the parent account can handle longer tests (up to 90 minutes) const USE_PARENT_ACCOUNT = [ - 'src/__tests__/transformer-migrations/searchable-migration', 'src/__tests__/graphql-v2/searchable-datastore', 'src/__tests__/schema-searchable', - 'src/__tests__/migration/api.key.migration2.test.ts', - 'src/__tests__/migration/api.key.migration3.test.ts', - 'src/__tests__/migration/api.key.migration4.test.ts', - 'src/__tests__/migration/api.key.migration5.test.ts', 'src/__tests__/FunctionTransformerTestsV2.e2e.test.ts', ]; const TEST_TIMINGS_PATH = join(REPO_ROOT, 'scripts', 'test-timings.data.json'); @@ -100,11 +95,6 @@ const RUN_SOLO: (string | RegExp)[] = [ 'src/__tests__/containers-api-1.test.ts', 'src/__tests__/containers-api-2.test.ts', 'src/__tests__/graphql-v2/searchable-datastore.test.ts', - 'src/__tests__/migration/api.key.migration1.test.ts', - 'src/__tests__/migration/api.key.migration2.test.ts', - 'src/__tests__/migration/api.key.migration3.test.ts', - 'src/__tests__/migration/api.key.migration4.test.ts', - 'src/__tests__/migration/api.key.migration5.test.ts', 'src/__tests__/schema-searchable.test.ts', 'src/__tests__/schema-auth-1.test.ts', 'src/__tests__/schema-auth-2.test.ts', @@ -128,9 +118,6 @@ const RUN_SOLO: (string | RegExp)[] = [ 'src/__tests__/schema-model.test.ts', 'src/__tests__/schema-key.test.ts', 'src/__tests__/schema-connection.test.ts', - 'src/__tests__/transformer-migrations/function-migration.test.ts', - 'src/__tests__/transformer-migrations/searchable-migration.test.ts', - 'src/__tests__/transformer-migrations/model-migration.test.ts', 'src/__tests__/graphql-v2/searchable-node-to-node-encryption/searchable-previous-deployment-no-node-to-node.test.ts', 'src/__tests__/graphql-v2/searchable-node-to-node-encryption/searchable-previous-deployment-had-node-to-node.test.ts', /src\/__tests__\/api_1.*\.test\.ts/, From d1387c96aeacae6383c3869a1a556092073e3d76 Mon Sep 17 00:00:00 2001 From: Doesnt Matter Date: Wed, 7 Aug 2024 12:40:14 -0700 Subject: [PATCH 16/23] chore: update yarn lock --- yarn.lock | 99 ------------------------------------------------------- 1 file changed, 99 deletions(-) diff --git a/yarn.lock b/yarn.lock index 9d0c925b51..187d2e3952 100644 --- a/yarn.lock +++ b/yarn.lock @@ -325,18 +325,6 @@ "@turf/boolean-clockwise" "6.5.0" camelcase-keys "6.2.2" -"@aws-amplify/graphql-transformer-migrator@2.2.27": - version "2.2.27" - resolved "https://registry.npmjs.org/@aws-amplify/graphql-transformer-migrator/-/graphql-transformer-migrator-2.2.27.tgz#7ddc98a1036b1364fdbe3c5360b63ee429bf1fec" - integrity sha512-4rzeSMcx0f5MWNEKP2x17uIQl9IZlAEZyGrMYC9t41FerKNv09Arp38jcZD2XhzINlu7MNkOVWb4veTCoqMptg== - dependencies: - "@aws-amplify/graphql-transformer-core" "2.9.3" - fs-extra "^8.1.0" - glob "^10.3.0" - graphql "^15.5.0" - graphql-transformer-common "4.31.1" - lodash "^4.17.21" - "@aws-amplify/interactions@4.1.12": version "4.1.12" resolved "https://registry.yarnpkg.com/@aws-amplify/interactions/-/interactions-4.1.12.tgz#b4e953c335b2638890459f66a58b8484f914186f" @@ -452,26 +440,6 @@ resolved "https://registry.npmjs.org/@aws-cdk/aws-cognito-identitypool-alpha/-/aws-cognito-identitypool-alpha-2.129.0-alpha.0.tgz#fce287c962f3ad93100dea5f4df3c5452d027fa8" integrity sha512-SXqbvgK4UnMVFKrQhlq9bN+fyh0LPojM+2BF7Xq8eqsEXi8CXeW0blfT45dvwu4b4TIRrWMxmXCDt50BA2b+xA== -"@aws-cdk/cfnspec@2.80.0-alpha.0": - version "2.80.0-alpha.0" - resolved "https://registry.npmjs.org/@aws-cdk/cfnspec/-/cfnspec-2.80.0-alpha.0.tgz#bb83ddadbb62d1905f6be17b0ec18eba22c9314d" - integrity sha512-5lDAtKK68x2rb+JP0LjH7q6Doc8oFqiNqKtAwYtHj56QbfpEFI//KxtTwvEliwArof2+fPLQgazaABcTki8k2g== - dependencies: - fs-extra "^9.1.0" - md5 "^2.3.0" - -"@aws-cdk/cloudformation-diff@~2.80.0": - version "2.80.0" - resolved "https://registry.npmjs.org/@aws-cdk/cloudformation-diff/-/cloudformation-diff-2.80.0.tgz#bdb413822782fbb55a0a63f9dc3607f10de6a282" - integrity sha512-EB0MpDJkLbpheVlgZxjWKLX8IvhzoOrHjMR3R+4+ceV3KPJfsqIkvkY6I/YxtlNxSsF7mDTKwu0YZtcUQA4NCQ== - dependencies: - "@aws-cdk/cfnspec" "2.80.0-alpha.0" - chalk "^4" - diff "^5.1.0" - fast-deep-equal "^3.1.3" - string-width "^4.2.3" - table "^6.8.1" - "@aws-crypto/crc32@2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-2.0.0.tgz#4ad432a3c03ec3087c5540ff6e41e6565d2dc153" @@ -11288,11 +11256,6 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -diff@^5.1.0: - version "5.2.0" - resolved "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" - integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== - dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -12874,17 +12837,6 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -graphql-auth-transformer@7.2.82: - version "7.2.82" - resolved "https://registry.npmjs.org/graphql-auth-transformer/-/graphql-auth-transformer-7.2.82.tgz#b2844fb002f33da77cd91e576b68d269ee733fae" - integrity sha512-64hOveNW1lB0Cn1jArl3tE34k+V4u/YZdImT/92PmCGwCsV5R+l77R58zeWr+7WGFbXmlWz4aAtmviyWoMUmVA== - dependencies: - graphql "^15.5.0" - graphql-connection-transformer "5.2.80" - graphql-mapping-template "4.20.16" - graphql-transformer-common "4.31.1" - graphql-transformer-core "8.2.13" - graphql-config@^2.2.1: version "2.2.2" resolved "https://registry.yarnpkg.com/graphql-config/-/graphql-config-2.2.2.tgz#a4b577826bba9b83e7b0f6cd617be43ca67da045" @@ -12896,44 +12848,6 @@ graphql-config@^2.2.1: lodash "^4.17.4" minimatch "^3.0.4" -graphql-connection-transformer@5.2.80: - version "5.2.80" - resolved "https://registry.npmjs.org/graphql-connection-transformer/-/graphql-connection-transformer-5.2.80.tgz#8f98c010af0485e6ebde4568a5e6178a30a499cd" - integrity sha512-TOc2wdezaUZZNTb9OKGH6G3+m03MkpXfyTx5yqq/M3LXYsqthhrRhRT51cswJvvDiL5SZzgubRLX5MNcZyaTQg== - dependencies: - cloudform-types "^4.2.0" - graphql "^15.5.0" - graphql-dynamodb-transformer "7.2.80" - graphql-key-transformer "3.2.80" - graphql-mapping-template "4.20.16" - graphql-transformer-common "4.31.1" - graphql-transformer-core "8.2.13" - -graphql-dynamodb-transformer@7.2.80: - version "7.2.80" - resolved "https://registry.npmjs.org/graphql-dynamodb-transformer/-/graphql-dynamodb-transformer-7.2.80.tgz#2938359c5a241009652dc30ee15dafe5ccc56063" - integrity sha512-TTcl2uuqRH7FaUX2sZaVhYIREABgT1gToV8GxMWTRRxr0MhdKs0VxtOAXa1AJ+ei9k1zTTA+ZZCHFEn8qaXwuA== - dependencies: - "@types/pluralize" "^0.0.29" - cloudform-types "^4.2.0" - graphql "^15.5.0" - graphql-mapping-template "4.20.16" - graphql-transformer-common "4.31.1" - graphql-transformer-core "8.2.13" - md5 "^2.2.1" - pluralize "^8.0.0" - -graphql-http-transformer@5.2.80: - version "5.2.80" - resolved "https://registry.npmjs.org/graphql-http-transformer/-/graphql-http-transformer-5.2.80.tgz#4b84b31a8bcfa4e7ff11ca72e5e99436d08eef72" - integrity sha512-a5Km3dRWi8EfEIXLNgEH2XnzBpFqRoUI6+/md+MAR0pXyO3mNTUjAT1OSfsmQuYESpqvVhxG8BmOZp35AErZ/A== - dependencies: - cloudform-types "^4.2.0" - graphql "^15.5.0" - graphql-mapping-template "4.20.16" - graphql-transformer-common "4.31.1" - graphql-transformer-core "8.2.13" - graphql-import@^0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/graphql-import/-/graphql-import-0.7.1.tgz#4add8d91a5f752d764b0a4a7a461fcd93136f223" @@ -12947,19 +12861,6 @@ graphql-iso-date@^3.6.1: resolved "https://registry.npmjs.org/graphql-iso-date/-/graphql-iso-date-3.6.1.tgz#bd2d0dc886e0f954cbbbc496bbf1d480b57ffa96" integrity sha512-AwFGIuYMJQXOEAgRlJlFL4H1ncFM8n8XmoVDTNypNOZyQ8LFDG2ppMFlsS862BSTCDcSUfHp8PD3/uJhv7t59Q== -graphql-key-transformer@3.2.80: - version "3.2.80" - resolved "https://registry.npmjs.org/graphql-key-transformer/-/graphql-key-transformer-3.2.80.tgz#918f8c440e7c51651b8d978e8857893d37e2b7b1" - integrity sha512-+refGi/BxpoWHs8xZ9SKyet+35hRFmpXtQM1HaYgDwzVep8Q6SYr5/5zs+2DFlYeuB19Bh23iKXu/2W6FZAGwQ== - dependencies: - cloudform-types "^4.2.0" - graphql "^15.5.0" - graphql-dynamodb-transformer "7.2.80" - graphql-mapping-template "4.20.16" - graphql-transformer-common "4.31.1" - graphql-transformer-core "8.2.13" - lodash "^4.17.21" - graphql-request@^1.5.0: version "1.8.2" resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-1.8.2.tgz#398d10ae15c585676741bde3fc01d5ca948f8fbe" From 61ff64d3d04f1c90f3c832e071efcdc9de53af98 Mon Sep 17 00:00:00 2001 From: Doesnt Matter Date: Thu, 8 Aug 2024 15:02:41 -0700 Subject: [PATCH 17/23] chore: remove more V1 transformer tests --- codebuild_specs/e2e_workflow.yml | 56 +- .../src/__tests__/CustomRoots.e2e.test.ts | 189 --- .../__tests__/MutationCondition.e2e.test.ts | 1452 ----------------- .../__tests__/PerFieldAuthTests.e2e.test.ts | 631 ------- 4 files changed, 23 insertions(+), 2305 deletions(-) delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/CustomRoots.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/MutationCondition.e2e.test.ts delete mode 100644 packages/graphql-transformers-e2e-tests/src/__tests__/PerFieldAuthTests.e2e.test.ts diff --git a/codebuild_specs/e2e_workflow.yml b/codebuild_specs/e2e_workflow.yml index 6698aebd04..21e9002352 100644 --- a/codebuild_specs/e2e_workflow.yml +++ b/codebuild_specs/e2e_workflow.yml @@ -1793,131 +1793,121 @@ batch: depend-on: - publish_to_local_registry - identifier: >- - CustomRoots_NonModelAuthV2Function_TransformerOptionsV2_PredictionsTransformerV2Tests + NonModelAuthV2Function_TransformerOptionsV2_PredictionsTransformerV2Tests_DefaultValueTransformer buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/CustomRoots.e2e.test.ts|src/__tests__/NonModelAuthV2Function.e2e.test.ts|src/__tests__/TransformerOptionsV2.e2e.test.ts|src/__tests__/PredictionsTransformerV2Tests.e2e.test.ts - CLI_REGION: ap-northeast-1 + src/__tests__/NonModelAuthV2Function.e2e.test.ts|src/__tests__/TransformerOptionsV2.e2e.test.ts|src/__tests__/PredictionsTransformerV2Tests.e2e.test.ts|src/__tests__/DefaultValueTransformer.e2e.test.ts + CLI_REGION: ap-northeast-2 depend-on: - publish_to_local_registry - identifier: >- - PerFieldAuthTests_MutationCondition_DefaultValueTransformer_PerFieldAuthV2TransformerWithFF + PerFieldAuthV2TransformerWithFF_PerFieldAuthV2Transformer_BelongsToTransformerV2_RelationalWithAuthV2WithFF buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/PerFieldAuthTests.e2e.test.ts|src/__tests__/MutationCondition.e2e.test.ts|src/__tests__/DefaultValueTransformer.e2e.test.ts|src/__tests__/PerFieldAuthV2TransformerWithFF.e2e.test.ts + src/__tests__/PerFieldAuthV2TransformerWithFF.e2e.test.ts|src/__tests__/PerFieldAuthV2Transformer.e2e.test.ts|src/__tests__/BelongsToTransformerV2.e2e.test.ts|src/__tests__/RelationalWithAuthV2WithFF.e2e.test.ts CLI_REGION: ap-southeast-1 depend-on: - publish_to_local_registry - identifier: >- - PerFieldAuthV2Transformer_BelongsToTransformerV2_RelationalWithAuthV2WithFF_IndexWithAuthV2 + IndexWithAuthV2_IndexWithAuthV2WithFF_SubscriptionsWithAuthV2WithFF_MultiAuthV2Transformer buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/PerFieldAuthV2Transformer.e2e.test.ts|src/__tests__/BelongsToTransformerV2.e2e.test.ts|src/__tests__/RelationalWithAuthV2WithFF.e2e.test.ts|src/__tests__/IndexWithAuthV2.e2e.test.ts + src/__tests__/IndexWithAuthV2.e2e.test.ts|src/__tests__/IndexWithAuthV2WithFF.e2e.test.ts|src/__tests__/SubscriptionsWithAuthV2WithFF.e2e.test.ts|src/__tests__/MultiAuthV2Transformer.e2e.test.ts CLI_REGION: ap-southeast-2 depend-on: - publish_to_local_registry - identifier: >- - IndexWithAuthV2WithFF_SubscriptionsWithAuthV2WithFF_MultiAuthV2Transformer_ModelTransformer + ModelTransformer_SubscriptionsWithAuthV2_RelationalWithAuthV2_MapsToTransformer buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/IndexWithAuthV2WithFF.e2e.test.ts|src/__tests__/SubscriptionsWithAuthV2WithFF.e2e.test.ts|src/__tests__/MultiAuthV2Transformer.e2e.test.ts|src/__tests__/ModelTransformer.e2e.test.ts + src/__tests__/ModelTransformer.e2e.test.ts|src/__tests__/SubscriptionsWithAuthV2.e2e.test.ts|src/__tests__/RelationalWithAuthV2.e2e.test.ts|src/__tests__/MapsToTransformer.e2e.test.ts CLI_REGION: ca-central-1 depend-on: - publish_to_local_registry - identifier: >- - SubscriptionsWithAuthV2_RelationalWithAuthV2_MapsToTransformer_MultiAuthV2TransformerWithFF + MultiAuthV2TransformerWithFF_AuthV2Transformer_AuthV2ExhaustiveT1B_AuthV2ExhaustiveT1A buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/SubscriptionsWithAuthV2.e2e.test.ts|src/__tests__/RelationalWithAuthV2.e2e.test.ts|src/__tests__/MapsToTransformer.e2e.test.ts|src/__tests__/MultiAuthV2TransformerWithFF.e2e.test.ts + src/__tests__/MultiAuthV2TransformerWithFF.e2e.test.ts|src/__tests__/AuthV2Transformer.e2e.test.ts|src/__tests__/AuthV2ExhaustiveT1B.test.ts|src/__tests__/AuthV2ExhaustiveT1A.test.ts CLI_REGION: eu-central-1 depend-on: - publish_to_local_registry - identifier: >- - AuthV2Transformer_AuthV2ExhaustiveT1B_AuthV2ExhaustiveT1A_AuthV2TransformerWithFF + AuthV2TransformerWithFF_SubscriptionsRuntimeFiltering_AuthV2ExhaustiveT2A_AuthV2ExhaustiveT1C buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/AuthV2Transformer.e2e.test.ts|src/__tests__/AuthV2ExhaustiveT1B.test.ts|src/__tests__/AuthV2ExhaustiveT1A.test.ts|src/__tests__/AuthV2TransformerWithFF.e2e.test.ts + src/__tests__/AuthV2TransformerWithFF.e2e.test.ts|src/__tests__/SubscriptionsRuntimeFiltering.e2e.test.ts|src/__tests__/AuthV2ExhaustiveT2A.test.ts|src/__tests__/AuthV2ExhaustiveT1C.test.ts CLI_REGION: eu-north-1 depend-on: - publish_to_local_registry - identifier: >- - SubscriptionsRuntimeFiltering_AuthV2ExhaustiveT2A_AuthV2ExhaustiveT1C_AuthV2ExhaustiveT1D + AuthV2ExhaustiveT1D_AuthV2ExhaustiveT2B_AuthV2ExhaustiveT2D_AuthV2ExhaustiveT2C buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/SubscriptionsRuntimeFiltering.e2e.test.ts|src/__tests__/AuthV2ExhaustiveT2A.test.ts|src/__tests__/AuthV2ExhaustiveT1C.test.ts|src/__tests__/AuthV2ExhaustiveT1D.test.ts + src/__tests__/AuthV2ExhaustiveT1D.test.ts|src/__tests__/AuthV2ExhaustiveT2B.test.ts|src/__tests__/AuthV2ExhaustiveT2D.test.ts|src/__tests__/AuthV2ExhaustiveT2C.test.ts CLI_REGION: eu-south-1 depend-on: - publish_to_local_registry - identifier: >- - AuthV2ExhaustiveT2B_AuthV2ExhaustiveT2D_AuthV2ExhaustiveT2C_RelationalWithAuthV2Redacted + RelationalWithAuthV2Redacted_RelationalWithAuthV2NonRedacted_AuthV2TransformerIAM_AuthV2ExhaustiveT3D buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/AuthV2ExhaustiveT2B.test.ts|src/__tests__/AuthV2ExhaustiveT2D.test.ts|src/__tests__/AuthV2ExhaustiveT2C.test.ts|src/__tests__/RelationalWithAuthV2Redacted.e2e.test.ts + src/__tests__/RelationalWithAuthV2Redacted.e2e.test.ts|src/__tests__/RelationalWithAuthV2NonRedacted.e2e.test.ts|src/__tests__/AuthV2TransformerIAM.test.ts|src/__tests__/AuthV2ExhaustiveT3D.test.ts CLI_REGION: eu-west-1 depend-on: - publish_to_local_registry - identifier: >- - RelationalWithAuthV2NonRedacted_AuthV2TransformerIAM_AuthV2ExhaustiveT3D_AuthV2ExhaustiveT3C + AuthV2ExhaustiveT3C_AuthV2ExhaustiveT3B_AuthV2ExhaustiveT3A_SearchableModelTransformerV2 buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/RelationalWithAuthV2NonRedacted.e2e.test.ts|src/__tests__/AuthV2TransformerIAM.test.ts|src/__tests__/AuthV2ExhaustiveT3D.test.ts|src/__tests__/AuthV2ExhaustiveT3C.test.ts - CLI_REGION: eu-west-2 + src/__tests__/AuthV2ExhaustiveT3C.test.ts|src/__tests__/AuthV2ExhaustiveT3B.test.ts|src/__tests__/AuthV2ExhaustiveT3A.test.ts|src/__tests__/SearchableModelTransformerV2.e2e.test.ts + CLI_REGION: sa-east-1 depend-on: - publish_to_local_registry - - identifier: >- - AuthV2ExhaustiveT3B_AuthV2ExhaustiveT3A_SearchableModelTransformerV2_SearchableWithAuthV2WithFF + - identifier: SearchableWithAuthV2WithFF_SearchableWithAuthV2 buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_MEDIUM variables: TEST_SUITE: >- - src/__tests__/AuthV2ExhaustiveT3B.test.ts|src/__tests__/AuthV2ExhaustiveT3A.test.ts|src/__tests__/SearchableModelTransformerV2.e2e.test.ts|src/__tests__/SearchableWithAuthV2WithFF.e2e.test.ts + src/__tests__/SearchableWithAuthV2WithFF.e2e.test.ts|src/__tests__/SearchableWithAuthV2.e2e.test.ts CLI_REGION: us-east-1 depend-on: - publish_to_local_registry - - identifier: SearchableWithAuthV2 - buildspec: codebuild_specs/graphql_e2e_tests.yml - env: - compute-type: BUILD_GENERAL1_MEDIUM - variables: - TEST_SUITE: src/__tests__/SearchableWithAuthV2.e2e.test.ts - CLI_REGION: us-east-2 - depend-on: - - publish_to_local_registry - identifier: FunctionTransformerTestsV2 buildspec: codebuild_specs/graphql_e2e_tests.yml env: compute-type: BUILD_GENERAL1_SMALL variables: TEST_SUITE: src/__tests__/FunctionTransformerTestsV2.e2e.test.ts - CLI_REGION: ap-southeast-1 + CLI_REGION: ap-south-1 USE_PARENT_ACCOUNT: 1 depend-on: - publish_to_local_registry diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/CustomRoots.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/CustomRoots.e2e.test.ts deleted file mode 100644 index a8c37907ba..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/CustomRoots.e2e.test.ts +++ /dev/null @@ -1,189 +0,0 @@ -import fs = require('fs'); -import path = require('path'); -import { - ObjectTypeDefinitionNode, - parse, - FieldDefinitionNode, - DocumentNode, - DefinitionNode, - Kind, - InputObjectTypeDefinitionNode, -} from 'graphql'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; - -jest.setTimeout(2000000); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; - -test('custom root types with additional fields.', () => { - const validSchema = ` - type Query { - additionalQueryField: String - } - type Mutation { - additionalMutationField: String - } - type Subscription { - additionalSubscriptionField: String - } - type Post @model { - id: ID! - title: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [new DynamoDBModelTransformer()], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - const queryType = getObjectType(parsed, 'Query'); - expectFields(queryType, ['getPost', 'listPosts', 'additionalQueryField']); - const mutationType = getObjectType(parsed, 'Mutation'); - expectFields(mutationType, ['createPost', 'updatePost', 'deletePost', 'additionalMutationField']); - const subscriptionType = getObjectType(parsed, 'Subscription'); - expectFields(subscriptionType, ['onCreatePost', 'onUpdatePost', 'onDeletePost', 'additionalSubscriptionField']); -}); - -test('custom root query, mutation, and subscriptions.', () => { - const validSchema = ` - # If I intentionally leave out mutation/subscription then no mutations/subscriptions - # will be created even if @model is used. - schema { - query: Query2 - mutation: Mutation2 - subscription: Subscription2 - } - type Query2 { - additionalQueryField: String - - authedField: String - @aws_auth(cognito_groups: ["Bloggers", "Readers"]) - } - type Mutation2 { - additionalMutationField: String - } - type Subscription2 { - onCreateOrUpdate: Post - @aws_subscribe(mutations: ["createPost", "updatePost"]) - } - type Post @model { - id: ID! - title: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [new DynamoDBModelTransformer()], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - const queryType = getObjectType(parsed, 'Query2'); - expectFields(queryType, ['getPost', 'listPosts', 'additionalQueryField', 'authedField']); - const authedField = queryType.fields.find((f) => f.name.value === 'authedField'); - expect(authedField.directives.length).toEqual(1); - expect(authedField.directives[0].name.value).toEqual('aws_auth'); - const mutationType = getObjectType(parsed, 'Mutation2'); - expectFields(mutationType, ['createPost', 'updatePost', 'deletePost', 'additionalMutationField']); - const subscriptionType = getObjectType(parsed, 'Subscription2'); - expectFields(subscriptionType, ['onCreatePost', 'onUpdatePost', 'onDeletePost', 'onCreateOrUpdate']); -}); - -test('custom roots without any directives. This should still be valid.', () => { - const validSchema = ` - schema { - query: Query2 - mutation: Mutation2 - subscription: Subscription2 - } - type Query2 { - getPost: String - } - type Mutation2 { - putPost: String - } - type Subscription2 { - onPutPost: Post - } - type Post { - id: ID! - title: String - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [new DynamoDBModelTransformer()], - }); - const out = transformer.transform(validSchema); - expect(out).toBeDefined(); - const definition = out.schema; - expect(definition).toBeDefined(); - const parsed = parse(definition); - const queryType = getObjectType(parsed, 'Query2'); - expectFields(queryType, ['getPost']); - const mutationType = getObjectType(parsed, 'Mutation2'); - expectFields(mutationType, ['putPost']); - const subscriptionType = getObjectType(parsed, 'Subscription2'); - expectFields(subscriptionType, ['onPutPost']); -}); - -function expectFields(type: ObjectTypeDefinitionNode, fields: string[]) { - for (const fieldName of fields) { - const foundField = type.fields.find((f: FieldDefinitionNode) => f.name.value === fieldName); - expect(foundField).toBeDefined(); - } -} - -function doNotExpectFields(type: ObjectTypeDefinitionNode, fields: string[]) { - for (const fieldName of fields) { - expect(type.fields.find((f: FieldDefinitionNode) => f.name.value === fieldName)).toBeUndefined(); - } -} - -function getObjectType(doc: DocumentNode, type: string): ObjectTypeDefinitionNode | undefined { - return doc.definitions.find((def: DefinitionNode) => def.kind === Kind.OBJECT_TYPE_DEFINITION && def.name.value === type) as - | ObjectTypeDefinitionNode - | undefined; -} - -function getInputType(doc: DocumentNode, type: string): InputObjectTypeDefinitionNode | undefined { - return doc.definitions.find((def: DefinitionNode) => def.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION && def.name.value === type) as - | InputObjectTypeDefinitionNode - | undefined; -} - -function verifyInputCount(doc: DocumentNode, type: string, count: number): boolean { - return doc.definitions.filter((def) => def.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION && def.name.value === type).length == count; -} - -function cleanUpFiles(directory: string) { - let files = fs.readdirSync(directory); - for (const file of files) { - const dir = path.join(directory, file); - if (!fs.lstatSync(dir).isDirectory()) { - fs.unlinkSync(dir); - } else { - cleanUpFiles(dir); - } - } - fs.rmdirSync(directory); -} - -function readFile(filePath: string) { - return fs.readFileSync(filePath, 'utf8'); -} diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/MutationCondition.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/MutationCondition.e2e.test.ts deleted file mode 100644 index 1d8029c333..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/MutationCondition.e2e.test.ts +++ /dev/null @@ -1,1452 +0,0 @@ -import { GraphQLTransform, TRANSFORM_CURRENT_VERSION, TRANSFORM_BASE_VERSION } from 'graphql-transformer-core'; -import { KeyTransformer } from 'graphql-key-transformer'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { parse } from 'graphql/language/parser'; -import { - DocumentNode, - InputObjectTypeDefinitionNode, - InputValueDefinitionNode, - DefinitionNode, - Kind, - ObjectTypeDefinitionNode, - FieldDefinitionNode, -} from 'graphql'; -import { VersionedModelTransformer } from 'graphql-versioned-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; - -import AWSAppSyncClient, { AUTH_TYPE } from 'aws-appsync'; -import gql from 'graphql-tag'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as CognitoClient } from 'aws-sdk/clients/cognitoidentityserviceprovider'; -import { default as S3 } from 'aws-sdk/clients/s3'; -import { default as moment } from 'moment'; -import Role from 'cloudform-types/types/iam/role'; -import UserPoolClient from 'cloudform-types/types/cognito/userPoolClient'; -import IdentityPool from 'cloudform-types/types/cognito/identityPool'; -import IdentityPoolRoleAttachment from 'cloudform-types/types/cognito/identityPoolRoleAttachment'; -import AWS = require('aws-sdk'); -import { createUserPool, createUserPoolClient, configureAmplify, signupUser, authenticateUser } from '../cognitoUtils'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { S3Client } from '../S3Client'; -import { CloudFormationClient } from '../CloudFormationClient'; -import 'isomorphic-fetch'; -import { resolveTestRegion } from '../testSetup'; - -const REGION = resolveTestRegion(); - -jest.setTimeout(2000000); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -const transformAndParseSchema = (schema: string, version: number = TRANSFORM_CURRENT_VERSION): DocumentNode => { - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new VersionedModelTransformer(), - new KeyTransformer(), - new ModelConnectionTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - transformConfig: { - Version: version, - }, - }); - - const out = transformer.transform(schema); - - return parse(out.schema); -}; - -const getInputType = (doc: DocumentNode, typeName: string): InputObjectTypeDefinitionNode => { - const type = doc.definitions.find((def: DefinitionNode) => def.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION && def.name.value === typeName); - - expect(type).toBeDefined(); - - return type; -}; - -const expectInputTypeDefined = (doc: DocumentNode, typeName: string) => { - const type = doc.definitions.find((def: DefinitionNode) => def.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION && def.name.value === typeName); - expect(type).toBeDefined(); -}; - -const expectInputTypeUndefined = (doc: DocumentNode, typeName: string) => { - const type = doc.definitions.find((def: DefinitionNode) => def.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION && def.name.value === typeName); - expect(type).toBeUndefined(); -}; - -const expectEnumTypeDefined = (doc: DocumentNode, typeName: string) => { - const type = doc.definitions.find((def: DefinitionNode) => def.kind === Kind.ENUM_TYPE_DEFINITION && def.name.value === typeName); - expect(type).toBeDefined(); -}; - -const expectEnumTypeUndefined = (doc: DocumentNode, typeName: string) => { - const type = doc.definitions.find((def: DefinitionNode) => def.kind === Kind.ENUM_TYPE_DEFINITION && def.name.value === typeName); - expect(type).toBeUndefined(); -}; - -const expectFieldsOnInputType = (type: InputObjectTypeDefinitionNode, fields: string[]) => { - expect(type.fields.length).toEqual(fields.length); - - for (const fieldName of fields) { - const foundField = type.fields.find((f: InputValueDefinitionNode) => f.name.value === fieldName); - expect(foundField).toBeDefined(); - } -}; - -const doNotExpectFieldsOnInputType = (type: InputObjectTypeDefinitionNode, fields: string[]) => { - for (const fieldName of fields) { - const foundField = type.fields.find((f: InputValueDefinitionNode) => f.name.value === fieldName); - expect(foundField).toBeUndefined(); - } -}; - -describe(`Local Mutation Condition tests`, () => { - it('Type without directives', () => { - const validSchema = ` - type Post - @model - { - id: ID! - content: String - type: String! - category: String - author: String - editors: [String!] - owner: String - groups: [String!] - slug: String! - likeCount: Int - rating: Int - } - `; - - const schema = transformAndParseSchema(validSchema); - - const type = getInputType(schema, 'ModelPostConditionInput'); - expectFieldsOnInputType(type, [ - 'content', - 'type', - 'category', - 'author', - 'editors', - 'owner', - 'groups', - 'slug', - 'likeCount', - 'rating', - 'and', - 'or', - 'not', - ]); - doNotExpectFieldsOnInputType(type, ['id']); - }); - - it('Type with primary @key - single field - directive', () => { - const validSchema = ` - type Post - @model - @key(fields: ["id"]) - { - id: ID! - content: String - type: String! - category: String - author: String - editors: [String!] - owner: String - groups: [String!] - slug: String! - likeCount: Int - rating: Int - } - `; - - const schema = transformAndParseSchema(validSchema); - - const type = getInputType(schema, 'ModelPostConditionInput'); - expectFieldsOnInputType(type, [ - 'content', - 'type', - 'category', - 'author', - 'editors', - 'owner', - 'groups', - 'slug', - 'likeCount', - 'rating', - 'and', - 'or', - 'not', - ]); - doNotExpectFieldsOnInputType(type, ['id']); - }); - - it('Type with primary @key - multiple field - directive', () => { - const validSchema = ` - type Post - @model - @key(fields: ["id", "type", "slug"]) - { - id: ID! - content: String - type: String! - category: String - author: String - editors: [String!] - owner: String - groups: [String!] - slug: String! - likeCount: Int - rating: Int - } - `; - - const schema = transformAndParseSchema(validSchema); - - const type = getInputType(schema, 'ModelPostConditionInput'); - expectFieldsOnInputType(type, [ - 'content', - 'category', - 'author', - 'editors', - 'owner', - 'groups', - 'likeCount', - 'rating', - 'and', - 'or', - 'not', - ]); - doNotExpectFieldsOnInputType(type, ['id', 'type', 'slug']); - }); - - it('Type with @auth directive - owner', () => { - const validSchema = ` - type Post - @model - @auth(rules: [ - { - allow: owner - } - ]) - { - id: ID! - content: String - type: String! - category: String - author: String - editors: [String!] - owner: String - groups: [String!] - slug: String! - likeCount: Int - rating: Int - } - `; - - const schema = transformAndParseSchema(validSchema); - - const type = getInputType(schema, 'ModelPostConditionInput'); - expectFieldsOnInputType(type, [ - 'content', - 'type', - 'category', - 'author', - 'editors', - 'groups', - 'slug', - 'likeCount', - 'rating', - 'and', - 'or', - 'not', - ]); - doNotExpectFieldsOnInputType(type, ['id', 'owner']); - }); - - it('Type with @auth directive - owner custom field name', () => { - const validSchema = ` - type Post - @model - @auth(rules: [ - { - allow: owner - ownerField: "author" - } - ]) - { - id: ID! - content: String - type: String! - category: String - author: String - editors: [String!] - owner: String - groups: [String!] - slug: String! - likeCount: Int - rating: Int - } - `; - - const schema = transformAndParseSchema(validSchema); - - const type = getInputType(schema, 'ModelPostConditionInput'); - expectFieldsOnInputType(type, [ - 'content', - 'type', - 'category', - 'editors', - 'owner', - 'groups', - 'slug', - 'likeCount', - 'rating', - 'and', - 'or', - 'not', - ]); - doNotExpectFieldsOnInputType(type, ['id', 'author']); - }); - - it('Type with @auth directive - groups', () => { - const validSchema = ` - type Post - @model - @auth(rules: [ - { - allow: groups - } - ]) - { - id: ID! - content: String - type: String! - category: String - author: String - editors: [String!] - owner: String - groups: [String!] - slug: String! - likeCount: Int - rating: Int - } - `; - - const schema = transformAndParseSchema(validSchema); - - const type = getInputType(schema, 'ModelPostConditionInput'); - expectFieldsOnInputType(type, [ - 'content', - 'type', - 'category', - 'author', - 'editors', - 'owner', - 'slug', - 'likeCount', - 'rating', - 'and', - 'or', - 'not', - ]); - doNotExpectFieldsOnInputType(type, ['id', 'groups']); - }); - - it('Type with @auth directive - groups custom field name', () => { - const validSchema = ` - type Post - @model - @auth(rules: [ - { - allow: groups - groupsField: "editors" - } - ]) - { - id: ID! - content: String - type: String! - category: String - author: String - editors: [String!] - owner: String - groups: [String!] - slug: String! - likeCount: Int - rating: Int - } - `; - - const schema = transformAndParseSchema(validSchema); - - const type = getInputType(schema, 'ModelPostConditionInput'); - expectFieldsOnInputType(type, [ - 'content', - 'type', - 'category', - 'author', - 'owner', - 'groups', - 'slug', - 'likeCount', - 'rating', - 'and', - 'or', - 'not', - ]); - doNotExpectFieldsOnInputType(type, ['id', 'editors']); - }); - - it('Type with @auth directive - multiple rules', () => { - const validSchema = ` - type Post - @model - @auth(rules: [ - { - allow: owner - } - { - allow: groups - } - { - allow: owner - ownerField: "author" - } - { - allow: groups - groupsField: "editors" - } - ]) - { - id: ID! - content: String - type: String! - category: String - author: String - editors: [String!] - owner: String - groups: [String!] - slug: String! - likeCount: Int - rating: Int - } - `; - - const schema = transformAndParseSchema(validSchema); - - const type = getInputType(schema, 'ModelPostConditionInput'); - expectFieldsOnInputType(type, ['content', 'type', 'category', 'slug', 'likeCount', 'rating', 'and', 'or', 'not']); - doNotExpectFieldsOnInputType(type, ['id', 'author', 'editors', 'owner', 'groups']); - }); - - it('Type with @versioned directive - no changes on condition', () => { - const validSchema = ` - type Post - @model - @versioned - # @versioned(versionField: "vv", versionInput: "ww") - { - id: ID! - content: String - type: String! - category: String - author: String - editors: [String!] - owner: String - groups: [String!] - slug: String! - likeCount: Int - rating: Int - } - `; - - const schema = transformAndParseSchema(validSchema); - - const type = getInputType(schema, 'ModelPostConditionInput'); - expectFieldsOnInputType(type, [ - 'content', - 'type', - 'category', - 'author', - 'editors', - 'owner', - 'groups', - 'slug', - 'likeCount', - 'rating', - 'and', - 'or', - 'not', - ]); - doNotExpectFieldsOnInputType(type, ['id']); - }); - - it('Type with @versioned directive - custom field, no changes on condition', () => { - const validSchema = ` - type Post - @model - @versioned(versionField: "version", versionInput: "requiredVersion") - { - id: ID! - content: String - type: String! - category: String - author: String - editors: [String!] - owner: String - groups: [String!] - slug: String! - likeCount: Int - rating: Int - } - `; - - const schema = transformAndParseSchema(validSchema); - - const type = getInputType(schema, 'ModelPostConditionInput'); - expectFieldsOnInputType(type, [ - 'content', - 'type', - 'category', - 'author', - 'editors', - 'owner', - 'groups', - 'slug', - 'likeCount', - 'rating', - 'and', - 'or', - 'not', - ]); - doNotExpectFieldsOnInputType(type, ['id']); - }); -}); - -// to deal with bug in cognito-identity-js -(global as any).fetch = require('node-fetch'); - -// To overcome of the way of how AmplifyJS picks up currentUserCredentials -const anyAWS = AWS as any; - -if (anyAWS && anyAWS.config && anyAWS.config.credentials) { - delete anyAWS.config.credentials; -} - -describe(`Deployed Mutation Condition tests`, () => { - const cf = new CloudFormationClient(REGION); - - const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); - const STACK_NAME = `MutationConditionTest-${BUILD_TIMESTAMP}`; - const BUCKET_NAME = `appsync-mutation-condition-test-bucket-${BUILD_TIMESTAMP}`; - const LOCAL_FS_BUILD_DIR = '/tmp/mutation_condition_tests/'; - const S3_ROOT_DIR_KEY = 'deployments'; - const AUTH_ROLE_NAME = `${STACK_NAME}-authRole`; - const UNAUTH_ROLE_NAME = `${STACK_NAME}-unauthRole`; - const IDENTITY_POOL_NAME = `MutationConditionTest_${BUILD_TIMESTAMP}_identity_pool`; - const USER_POOL_CLIENTWEB_NAME = `mutationcondition_${BUILD_TIMESTAMP}_clientweb`; - const USER_POOL_CLIENT_NAME = `mutationcondition_${BUILD_TIMESTAMP}_client`; - - let GRAPHQL_ENDPOINT = undefined; - - let APIKEY_CLIENT: AWSAppSyncClient = undefined; - let USER_POOL_AUTH_CLIENT_1: AWSAppSyncClient = undefined; - let USER_POOL_AUTH_CLIENT_2: AWSAppSyncClient = undefined; - - let USER_POOL_ID = undefined; - - const USERNAME1 = 'user1@test.com'; - const USERNAME2 = 'user2@test.com'; - - const TMP_PASSWORD = 'Password123!'; - const REAL_PASSWORD = 'Password1234!'; - - const cognitoClient = new CognitoClient({ apiVersion: '2016-04-19', region: REGION }); - const customS3Client = new S3Client(REGION); - const awsS3Client = new S3({ region: REGION }); - - const conditionRegexMatch = - /GraphQL error: The conditional request failed \(Service: \w*DynamoD\w*\,?\;? Status Code: 400\,?\;? [a-zA-Z0-9:;, ]*\)/gm; - - function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; - } - - beforeAll(async () => { - const validSchema = ` - type Post - @model - @versioned - @auth(rules: [ - { allow: owner } - { allow: public } - ]) - @key(fields: ["id", "type"]) - { - id: ID! - type: String! - owner: String - category: String - content: String - slug: String - rating: Int - } -`; - - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new VersionedModelTransformer(), - new ModelConnectionTransformer(), - new KeyTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [ - { - authenticationType: 'API_KEY', - apiKeyConfig: { - description: 'E2E Test API Key', - apiKeyExpirationDays: 300, - }, - }, - ], - }, - }), - ], - transformConfig: { - Version: TRANSFORM_CURRENT_VERSION, - }, - }); - - try { - await awsS3Client.createBucket({ Bucket: BUCKET_NAME }).promise(); - } catch (e) { - console.error(`Failed to create bucket: ${e}`); - } - const userPoolResponse = await createUserPool(cognitoClient, `UserPool${STACK_NAME}`); - USER_POOL_ID = userPoolResponse.UserPool.Id; - const userPoolClientResponse = await createUserPoolClient(cognitoClient, USER_POOL_ID, `UserPool${STACK_NAME}`); - const userPoolClientId = userPoolClientResponse.UserPoolClient.ClientId; - - try { - const out = transformer.transform(validSchema); - - const authRole = new Role({ - RoleName: AUTH_ROLE_NAME, - AssumeRolePolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Sid: '', - Effect: 'Allow', - Principal: { - Federated: 'cognito-identity.amazonaws.com', - }, - Action: 'sts:AssumeRoleWithWebIdentity', - Condition: { - StringEquals: { - 'cognito-identity.amazonaws.com:aud': { Ref: 'IdentityPool' }, - }, - 'ForAnyValue:StringLike': { - 'cognito-identity.amazonaws.com:amr': 'authenticated', - }, - }, - }, - ], - }, - }); - - const unauthRole = new Role({ - RoleName: UNAUTH_ROLE_NAME, - AssumeRolePolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Sid: '', - Effect: 'Allow', - Principal: { - Federated: 'cognito-identity.amazonaws.com', - }, - Action: 'sts:AssumeRoleWithWebIdentity', - Condition: { - StringEquals: { - 'cognito-identity.amazonaws.com:aud': { Ref: 'IdentityPool' }, - }, - 'ForAnyValue:StringLike': { - 'cognito-identity.amazonaws.com:amr': 'unauthenticated', - }, - }, - }, - ], - }, - Policies: [ - new Role.Policy({ - PolicyName: 'appsync-unauthrole-policy', - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Action: ['appsync:GraphQL'], - Resource: [ - { - 'Fn::Join': [ - '', - [ - 'arn:aws:appsync:', - { Ref: 'AWS::Region' }, - ':', - { Ref: 'AWS::AccountId' }, - ':apis/', - { - 'Fn::GetAtt': ['GraphQLAPI', 'ApiId'], - }, - '/*', - ], - ], - }, - ], - }, - ], - }, - }), - ], - }); - - const identityPool = new IdentityPool({ - IdentityPoolName: IDENTITY_POOL_NAME, - CognitoIdentityProviders: [ - { - ClientId: { - Ref: 'UserPoolClient', - }, - ProviderName: { - 'Fn::Sub': [ - 'cognito-idp.${region}.amazonaws.com/${client}', - { - region: { - Ref: 'AWS::Region', - }, - client: USER_POOL_ID, - }, - ], - }, - } as unknown, - { - ClientId: { - Ref: 'UserPoolClientWeb', - }, - ProviderName: { - 'Fn::Sub': [ - 'cognito-idp.${region}.amazonaws.com/${client}', - { - region: { - Ref: 'AWS::Region', - }, - client: USER_POOL_ID, - }, - ], - }, - } as unknown, - ], - AllowUnauthenticatedIdentities: true, - }); - - const identityPoolRoleMap = new IdentityPoolRoleAttachment({ - IdentityPoolId: { Ref: 'IdentityPool' } as unknown as string, - Roles: { - unauthenticated: { 'Fn::GetAtt': ['UnauthRole', 'Arn'] }, - authenticated: { 'Fn::GetAtt': ['AuthRole', 'Arn'] }, - }, - }); - - const userPoolClientWeb = new UserPoolClient({ - ClientName: USER_POOL_CLIENTWEB_NAME, - RefreshTokenValidity: 30, - UserPoolId: USER_POOL_ID, - }); - - const userPoolClient = new UserPoolClient({ - ClientName: USER_POOL_CLIENT_NAME, - GenerateSecret: true, - RefreshTokenValidity: 30, - UserPoolId: USER_POOL_ID, - }); - - out.rootStack.Resources.IdentityPool = identityPool; - out.rootStack.Resources.IdentityPoolRoleMap = identityPoolRoleMap; - out.rootStack.Resources.UserPoolClientWeb = userPoolClientWeb; - out.rootStack.Resources.UserPoolClient = userPoolClient; - out.rootStack.Outputs.IdentityPoolId = { Value: { Ref: 'IdentityPool' } }; - out.rootStack.Outputs.IdentityPoolName = { Value: { 'Fn::GetAtt': ['IdentityPool', 'Name'] } }; - - out.rootStack.Resources.AuthRole = authRole; - out.rootStack.Outputs.AuthRoleArn = { Value: { 'Fn::GetAtt': ['AuthRole', 'Arn'] } }; - out.rootStack.Resources.UnauthRole = unauthRole; - out.rootStack.Outputs.UnauthRoleArn = { Value: { 'Fn::GetAtt': ['UnauthRole', 'Arn'] } }; - - // Since we're doing the policy here we've to remove the transformer generated artifacts from - // the generated stack. - const maxPolicyCount = 10; - for (let i = 0; i < maxPolicyCount; i++) { - const paddedIndex = `${i + 1}`.padStart(2, '0'); - const authResourceName = `${ResourceConstants.RESOURCES.AuthRolePolicy}${paddedIndex}`; - const unauthResourceName = `${ResourceConstants.RESOURCES.UnauthRolePolicy}${paddedIndex}`; - - if (out.rootStack.Resources[authResourceName]) { - delete out.rootStack.Resources[authResourceName]; - } - - if (out.rootStack.Resources[unauthResourceName]) { - delete out.rootStack.Resources[unauthResourceName]; - } - } - - delete out.rootStack.Parameters.authRoleName; - delete out.rootStack.Parameters.unauthRoleName; - - for (const key of Object.keys(out.rootStack.Resources)) { - if ( - out.rootStack.Resources[key].Properties && - out.rootStack.Resources[key].Properties.Parameters && - out.rootStack.Resources[key].Properties.Parameters.unauthRoleName - ) { - delete out.rootStack.Resources[key].Properties.Parameters.unauthRoleName; - } - - if ( - out.rootStack.Resources[key].Properties && - out.rootStack.Resources[key].Properties.Parameters && - out.rootStack.Resources[key].Properties.Parameters.authRoleName - ) { - delete out.rootStack.Resources[key].Properties.Parameters.authRoleName; - } - } - - for (const stackKey of Object.keys(out.stacks)) { - const stack = out.stacks[stackKey]; - - for (const key of Object.keys(stack.Resources)) { - if (stack.Parameters && stack.Parameters.unauthRoleName) { - delete stack.Parameters.unauthRoleName; - } - if (stack.Parameters && stack.Parameters.authRoleName) { - delete stack.Parameters.authRoleName; - } - if ( - stack.Resources[key].Properties && - stack.Resources[key].Properties.Parameters && - stack.Resources[key].Properties.Parameters.unauthRoleName - ) { - delete stack.Resources[key].Properties.Parameters.unauthRoleName; - } - if ( - stack.Resources[key].Properties && - stack.Resources[key].Properties.Parameters && - stack.Resources[key].Properties.Parameters.authRoleName - ) { - delete stack.Resources[key].Properties.Parameters.authRoleName; - } - } - } - - const params = { - CreateAPIKey: '1', - AuthCognitoUserPoolId: USER_POOL_ID, - }; - - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - params, - LOCAL_FS_BUILD_DIR, - BUCKET_NAME, - S3_ROOT_DIR_KEY, - BUILD_TIMESTAMP, - ); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); - GRAPHQL_ENDPOINT = getApiEndpoint(finishedStack.Outputs); - - const apiKey = getApiKey(finishedStack.Outputs); - expect(apiKey).toBeTruthy(); - - const getIdentityPoolId = outputValueSelector('IdentityPoolId'); - const identityPoolId = getIdentityPoolId(finishedStack.Outputs); - expect(identityPoolId).toBeTruthy(); - - // Verify we have all the details - expect(GRAPHQL_ENDPOINT).toBeTruthy(); - expect(USER_POOL_ID).toBeTruthy(); - expect(userPoolClientId).toBeTruthy(); - - // Configure Amplify, create users, and sign in. - configureAmplify(USER_POOL_ID, userPoolClientId, identityPoolId); - - await signupUser(USER_POOL_ID, USERNAME1, TMP_PASSWORD); - const authRes1 = await authenticateUser(USERNAME1, TMP_PASSWORD, REAL_PASSWORD); - const idToken1 = authRes1.getIdToken().getJwtToken(); - - await signupUser(USER_POOL_ID, USERNAME2, TMP_PASSWORD); - const authRes2 = await authenticateUser(USERNAME2, TMP_PASSWORD, REAL_PASSWORD); - const idToken2 = authRes2.getIdToken().getJwtToken(); - - USER_POOL_AUTH_CLIENT_1 = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: REGION, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: () => idToken1, - }, - offlineConfig: { - keyPrefix: 'userPools', - }, - disableOffline: true, - }); - - USER_POOL_AUTH_CLIENT_2 = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: REGION, - auth: { - type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS, - jwtToken: () => idToken2, - }, - offlineConfig: { - keyPrefix: 'userPools', - }, - disableOffline: true, - }); - - APIKEY_CLIENT = new AWSAppSyncClient({ - url: GRAPHQL_ENDPOINT, - region: REGION, - auth: { - type: AUTH_TYPE.API_KEY, - apiKey, - }, - offlineConfig: { - keyPrefix: 'apikey', - }, - disableOffline: true, - }); - - // Wait for any propagation to avoid random - // "The security token included in the request is invalid" errors - await new Promise((res) => setTimeout(() => res(), 5000)); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } - }); - - afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf, { cognitoClient, userPoolId: USER_POOL_ID }); - }); - - it('Create Mutation with failing condition', async () => { - const createMutation = gql` - mutation { - createPost( - input: { id: "P1", type: "Post", category: "T1", content: "Content #1", slug: "content-1", rating: 4 } - condition: { category: { eq: "T" } } - ) { - id - } - } - `; - - try { - await APIKEY_CLIENT.mutate({ - mutation: createMutation, - fetchPolicy: 'no-cache', - }); - } catch (e) { - expect(e.message).toMatch(conditionRegexMatch); - } - }); - - it('Update Mutation with failing and succeeding condition', async () => { - const createMutation = gql` - mutation { - createPost(input: { id: "P1", type: "Post", category: "T1", content: "Content #1", slug: "content-1", rating: 4 }) { - id - } - } - `; - - const createResponse = await APIKEY_CLIENT.mutate({ - mutation: createMutation, - fetchPolicy: 'no-cache', - }); - expect(createResponse.data.createPost.id).toBeDefined(); - - // Update P1 if rating === 5 (but it is 4) - const updateMutationFailure = gql` - mutation { - updatePost( - input: { id: "P1", type: "Post", content: "Content #1 - Update", expectedVersion: 1 } - condition: { rating: { eq: 5 } } - ) { - id - } - } - `; - - try { - await APIKEY_CLIENT.mutate({ - mutation: updateMutationFailure, - fetchPolicy: 'no-cache', - }); - } catch (e) { - expect(e.message).toMatch(conditionRegexMatch); - } - - // Update P1 if rating === 4 - const updateMutationSuccess = gql` - mutation { - updatePost( - input: { id: "P1", type: "Post", content: "Content #1 - Update", expectedVersion: 1 } - condition: { rating: { eq: 4 } } - ) { - id - content - } - } - `; - - const updateResponse = await APIKEY_CLIENT.mutate({ - mutation: updateMutationSuccess, - fetchPolicy: 'no-cache', - }); - - expect(updateResponse.data.updatePost.id).toBeDefined(); - expect(updateResponse.data.updatePost.content).toEqual('Content #1 - Update'); - }); - - it('Update Mutation with failing and succeeding complex conditions', async () => { - const createMutation = gql` - mutation { - createPost(input: { id: "P2", type: "Post", category: "T1", content: "Content #2", slug: "content-2", rating: 4 }) { - id - } - } - `; - - const createResponse = await APIKEY_CLIENT.mutate({ - mutation: createMutation, - fetchPolicy: 'no-cache', - }); - - expect(createResponse.data.createPost.id).toBeDefined(); - - // Update P2 if (content beginsWith "Content #2" AND rating === [4-5]) OR content is null - const updateMutation = gql` - mutation { - updatePost( - input: { id: "P2", type: "Post", content: "Content #2 - UpdateComplex", expectedVersion: 1 } - condition: { - or: [{ and: [{ content: { beginsWith: "Content #2" } }, { rating: { between: [4, 5] } }] }, { content: { eq: null } }] - } - ) { - id - content - } - } - `; - - const updateResponse = await APIKEY_CLIENT.mutate({ - mutation: updateMutation, - fetchPolicy: 'no-cache', - }); - - expect(updateResponse.data.updatePost.id).toBeDefined(); - expect(updateResponse.data.updatePost.content).toEqual('Content #2 - UpdateComplex'); - }); - - it('Delete Mutation with failing and succeeding complex conditions', async () => { - const createMutation = gql` - mutation { - createPost(input: { id: "P3", type: "Post", category: "T1", content: "Content #3", slug: "content-3", rating: 4 }) { - id - } - } - `; - - const createResponse = await APIKEY_CLIENT.mutate({ - mutation: createMutation, - fetchPolicy: 'no-cache', - }); - - expect(createResponse.data.createPost.id).toBeDefined(); - - // Delete P3 if (content equals "Content #3" AND rating === [4-5]) OR content is null - const deleteMutation = gql` - mutation { - deletePost( - input: { id: "P3", type: "Post", expectedVersion: 1 } - condition: { or: [{ and: [{ content: { eq: "Content #3" } }, { rating: { between: [4, 5] } }] }, { content: { eq: null } }] } - ) { - id - content - } - } - `; - - const deleteResponse = await APIKEY_CLIENT.mutate({ - mutation: deleteMutation, - fetchPolicy: 'no-cache', - }); - - expect(deleteResponse.data.deletePost.id).toBeDefined(); - expect(deleteResponse.data.deletePost.content).toEqual('Content #3'); - }); - - it('Update Mutation with different owners and same condition', async () => { - const createMutation = gql` - mutation { - createPost(input: { id: "P4", type: "Post", category: "T1", content: "Content #4", slug: "content-4", rating: 4 }) { - id - } - } - `; - - const createResponse = await USER_POOL_AUTH_CLIENT_1.mutate({ - mutation: createMutation, - fetchPolicy: 'no-cache', - }); - - expect(createResponse.data.createPost.id).toBeDefined(); - - // Update P4 if rating === 4, different user (non-owner) - const updateMutation = gql` - mutation { - updatePost( - input: { id: "P4", type: "Post", content: "Content #4 - Update", expectedVersion: 1 } - condition: { rating: { eq: 4 } } - ) { - id - } - } - `; - - try { - await USER_POOL_AUTH_CLIENT_2.mutate({ - mutation: updateMutation, - fetchPolicy: 'no-cache', - }); - } catch (e) { - expect(e.message).toMatch(conditionRegexMatch); - } - - // Update P4 if rating === 5, owner user, wrong condition - const updateMutation2 = gql` - mutation { - updatePost( - input: { id: "P4", type: "Post", content: "Content #4 - Update", expectedVersion: 1 } - condition: { rating: { eq: 5 } } - ) { - id - } - } - `; - - try { - await USER_POOL_AUTH_CLIENT_1.mutate({ - mutation: updateMutation2, - fetchPolicy: 'no-cache', - }); - } catch (e) { - expect(e.message).toMatch(conditionRegexMatch); - } - - // Update P4 if rating === 4, owner user, right condition - const updateMutation3 = gql` - mutation { - updatePost( - input: { id: "P4", type: "Post", content: "Content #4 - Update", expectedVersion: 1 } - condition: { rating: { eq: 4 } } - ) { - id - content - version - } - } - `; - - const updateResponse = await USER_POOL_AUTH_CLIENT_1.mutate({ - mutation: updateMutation3, - fetchPolicy: 'no-cache', - }); - - expect(updateResponse.data.updatePost.id).toBeDefined(); - expect(updateResponse.data.updatePost.content).toEqual('Content #4 - Update'); - expect(updateResponse.data.updatePost.version).toEqual(2); - }); - - it('Delete Mutation with different owners and same condition', async () => { - const createMutation = gql` - mutation { - createPost(input: { id: "P5", type: "Post", category: "T1", content: "Content #5", slug: "content-5", rating: 4 }) { - id - } - } - `; - - const createResponse = await USER_POOL_AUTH_CLIENT_1.mutate({ - mutation: createMutation, - fetchPolicy: 'no-cache', - }); - - expect(createResponse.data.createPost.id).toBeDefined(); - - // Delete P5 if rating === 4, different user (non-owner) - const deleteMutation = gql` - mutation { - deletePost(input: { id: "P5", type: "Post", expectedVersion: 1 }, condition: { rating: { eq: 4 } }) { - id - } - } - `; - - try { - await USER_POOL_AUTH_CLIENT_2.mutate({ - mutation: deleteMutation, - fetchPolicy: 'no-cache', - }); - } catch (e) { - expect(e.message).toMatch(conditionRegexMatch); - } - - // Delete P5 if rating === 5, owner user, wrong condition - const deleteMutation2 = gql` - mutation { - deletePost(input: { id: "P5", type: "Post", expectedVersion: 1 }, condition: { rating: { eq: 5 } }) { - id - } - } - `; - - try { - await USER_POOL_AUTH_CLIENT_1.mutate({ - mutation: deleteMutation2, - fetchPolicy: 'no-cache', - }); - } catch (e) { - expect(e.message).toMatch(conditionRegexMatch); - } - - // Delete P5 if rating === 4, owner user, right condition - const deleteMutation3 = gql` - mutation { - deletePost(input: { id: "P5", type: "Post", expectedVersion: 1 }, condition: { rating: { eq: 4 } }) { - id - content - version - } - } - `; - - const deleteResponse = await USER_POOL_AUTH_CLIENT_1.mutate({ - mutation: deleteMutation3, - fetchPolicy: 'no-cache', - }); - - expect(deleteResponse.data.deletePost.id).toBeDefined(); - expect(deleteResponse.data.deletePost.content).toEqual('Content #5'); - expect(deleteResponse.data.deletePost.version).toEqual(1); - }); -}); - -describe(`Local V4-V5 Transformer tests`, () => { - it('V4 transform result', () => { - const validSchema = ` - type Post - @model - { - id: ID! - content: String - rating: Int - state: State - stateList: [State] - } - - enum State { - DRAFT, - PUBLISHED - } - `; - - const schema = transformAndParseSchema(validSchema, TRANSFORM_BASE_VERSION); - - const filterType = getInputType(schema, 'ModelPostFilterInput'); - expectFieldsOnInputType(filterType, ['id', 'content', 'rating', 'state', 'stateList', 'and', 'or', 'not']); - doNotExpectFieldsOnInputType(filterType, ['attributeExists']); - doNotExpectFieldsOnInputType(filterType, ['attributeType']); - - expectInputTypeUndefined(schema, 'ModelPostConditionInput'); - - expectInputTypeDefined(schema, 'ModelStringFilterInput'); - expectInputTypeDefined(schema, 'ModelIDFilterInput'); - expectInputTypeDefined(schema, 'ModelIntFilterInput'); - expectInputTypeDefined(schema, 'ModelFloatFilterInput'); - expectInputTypeDefined(schema, 'ModelBooleanFilterInput'); - expectInputTypeDefined(schema, 'ModelStateFilterInput'); - expectInputTypeDefined(schema, 'ModelStateListFilterInput'); - - expectInputTypeUndefined(schema, 'ModelSizeInput'); - expectEnumTypeUndefined(schema, 'ModelAttributeTypes'); - - const mutation = ( - schema.definitions.find((def: DefinitionNode) => def.kind === Kind.OBJECT_TYPE_DEFINITION && def.name.value === 'Mutation') - ); - expect(mutation).toBeDefined(); - - const checkMutation = (name: string) => { - const field = mutation.fields.find((f) => f.name.value === `${name}Post`); - expect(field).toBeDefined(); - const conditionArg = field.arguments.find((a) => a.name.value === 'condition'); - expect(conditionArg).toBeUndefined(); - }; - - checkMutation('create'); - checkMutation('update'); - checkMutation('delete'); - }); - - it(`V5 transform result`, () => { - const validSchema = ` - type Post - @model - { - id: ID! - content: String - rating: Int - state: State - stateList: [State] - } - - enum State { - DRAFT, - PUBLISHED - } - `; - - const conditionFeatureVersion = 5; - const schema = transformAndParseSchema(validSchema, conditionFeatureVersion); - - const filterType = getInputType(schema, 'ModelPostFilterInput'); - expectFieldsOnInputType(filterType, ['id', 'content', 'rating', 'state', 'stateList', 'and', 'or', 'not']); - - const conditionType = getInputType(schema, 'ModelPostConditionInput'); - expectFieldsOnInputType(conditionType, ['content', 'rating', 'state', 'stateList', 'and', 'or', 'not']); - - expectInputTypeDefined(schema, 'ModelStringInput'); - expectInputTypeDefined(schema, 'ModelIDInput'); - expectInputTypeDefined(schema, 'ModelIntInput'); - expectInputTypeDefined(schema, 'ModelFloatInput'); - expectInputTypeDefined(schema, 'ModelBooleanInput'); - expectInputTypeDefined(schema, 'ModelStateInput'); - expectInputTypeDefined(schema, 'ModelStateListInput'); - expectInputTypeDefined(schema, 'ModelSizeInput'); - expectEnumTypeDefined(schema, 'ModelAttributeTypes'); - - const mutation = ( - schema.definitions.find((def: DefinitionNode) => def.kind === Kind.OBJECT_TYPE_DEFINITION && def.name.value === 'Mutation') - ); - expect(mutation).toBeDefined(); - - const checkMutation = (name: string) => { - const field = mutation.fields.find((f) => f.name.value === `${name}Post`); - expect(field).toBeDefined(); - const conditionArg = field.arguments.find((a) => a.name.value === 'condition'); - expect(conditionArg).toBeDefined(); - }; - - checkMutation('create'); - checkMutation('update'); - checkMutation('delete'); - }); - - it(`Current version transform result`, () => { - const validSchema = ` - type Post - @model - { - id: ID! - content: String - rating: Int - state: State - stateList: [State] - } - - enum State { - DRAFT, - PUBLISHED - } - `; - - const schema = transformAndParseSchema(validSchema, TRANSFORM_CURRENT_VERSION); - - const filterType = getInputType(schema, 'ModelPostFilterInput'); - expectFieldsOnInputType(filterType, ['id', 'content', 'rating', 'state', 'stateList', 'and', 'or', 'not']); - - const conditionType = getInputType(schema, 'ModelPostConditionInput'); - expectFieldsOnInputType(conditionType, ['content', 'rating', 'state', 'stateList', 'and', 'or', 'not']); - - expectInputTypeDefined(schema, 'ModelStringInput'); - expectInputTypeDefined(schema, 'ModelIDInput'); - expectInputTypeDefined(schema, 'ModelIntInput'); - expectInputTypeDefined(schema, 'ModelFloatInput'); - expectInputTypeDefined(schema, 'ModelBooleanInput'); - expectInputTypeDefined(schema, 'ModelStateInput'); - expectInputTypeDefined(schema, 'ModelStateListInput'); - expectInputTypeDefined(schema, 'ModelSizeInput'); - expectEnumTypeDefined(schema, 'ModelAttributeTypes'); - - const mutation = ( - schema.definitions.find((def: DefinitionNode) => def.kind === Kind.OBJECT_TYPE_DEFINITION && def.name.value === 'Mutation') - ); - expect(mutation).toBeDefined(); - - const checkMutation = (name: string) => { - const field = mutation.fields.find((f) => f.name.value === `${name}Post`); - expect(field).toBeDefined(); - const conditionArg = field.arguments.find((a) => a.name.value === 'condition'); - expect(conditionArg).toBeDefined(); - }; - - checkMutation('create'); - checkMutation('update'); - checkMutation('delete'); - }); -}); diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/PerFieldAuthTests.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/PerFieldAuthTests.e2e.test.ts deleted file mode 100644 index d9b1f6d6bc..0000000000 --- a/packages/graphql-transformers-e2e-tests/src/__tests__/PerFieldAuthTests.e2e.test.ts +++ /dev/null @@ -1,631 +0,0 @@ -import * as fs from 'fs'; -import { ResourceConstants } from 'graphql-transformer-common'; -import { GraphQLTransform } from 'graphql-transformer-core'; -import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; -import { ModelAuthTransformer } from 'graphql-auth-transformer'; -import { ModelConnectionTransformer } from 'graphql-connection-transformer'; -import { Output } from 'aws-sdk/clients/cloudformation'; -import { default as S3, CreateBucketRequest } from 'aws-sdk/clients/s3'; -import { default as CognitoClient } from 'aws-sdk/clients/cognitoidentityserviceprovider'; -import { default as moment } from 'moment'; -import { GraphQLClient } from '../GraphQLClient'; -import { S3Client } from '../S3Client'; -import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; -import { CloudFormationClient } from '../CloudFormationClient'; -import { - createUserPool, - createUserPoolClient, - createGroup, - addUserToGroup, - configureAmplify, - signupUser, - authenticateUser, -} from '../cognitoUtils'; -import 'isomorphic-fetch'; - -// to deal with bug in cognito-identity-js -(global as any).fetch = require('node-fetch'); - -import { resolveTestRegion } from '../testSetup'; - -const region = resolveTestRegion(); - -jest.setTimeout(2000000); - -const cf = new CloudFormationClient(region); -const featureFlags = { - getBoolean: jest.fn().mockImplementation((name, defaultValue) => { - if (name === 'improvePluralization') { - return true; - } - return; - }), - getNumber: jest.fn(), - getObject: jest.fn(), -}; -const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); -const STACK_NAME = `PerFieldAuthTests-${BUILD_TIMESTAMP}`; -const BUCKET_NAME = `per-field-auth-tests-bucket-${BUILD_TIMESTAMP}`; -const LOCAL_BUILD_ROOT = '/tmp/per_field_auth_tests/'; -const DEPLOYMENT_ROOT_KEY = 'deployments'; - -let GRAPHQL_ENDPOINT = undefined; - -/** - * Client 1 is logged in and is a member of the Admin group. - */ -let GRAPHQL_CLIENT_1 = undefined; - -/** - * Client 2 is logged in and is a member of the Devs group. - */ -let GRAPHQL_CLIENT_2 = undefined; - -/** - * Client 3 is logged in and has no group memberships. - */ -let GRAPHQL_CLIENT_3 = undefined; - -let USER_POOL_ID = undefined; - -const USERNAME1 = 'user1@test.com'; -const USERNAME2 = 'user2@test.com'; -const USERNAME3 = 'user3@test.com'; -const TMP_PASSWORD = 'Password123!'; -const REAL_PASSWORD = 'Password1234!'; - -const ADMIN_GROUP_NAME = 'Admin'; -const DEVS_GROUP_NAME = 'Devs'; -const PARTICIPANT_GROUP_NAME = 'Participant'; -const WATCHER_GROUP_NAME = 'Watcher'; -const INSTRUCTOR_GROUP_NAME = 'Instructor'; - -const cognitoClient = new CognitoClient({ apiVersion: '2016-04-19', region: region }); -const customS3Client = new S3Client(region); -const awsS3Client = new S3({ region: region }); - -function outputValueSelector(key: string) { - return (outputs: Output[]) => { - const output = outputs.find((o: Output) => o.OutputKey === key); - return output ? output.OutputValue : null; - }; -} - -async function createBucket(name: string) { - return new Promise((res, rej) => { - const params: CreateBucketRequest = { - Bucket: name, - }; - awsS3Client.createBucket(params, (err, data) => (err ? rej(err) : res(data))); - }); -} - -async function deleteBucket(name: string) { - return new Promise((res, rej) => { - const params: CreateBucketRequest = { - Bucket: name, - }; - awsS3Client.deleteBucket(params, (err, data) => (err ? rej(err) : res(data))); - }); -} - -beforeAll(async () => { - // Create a stack for the post model with auth enabled. - if (!fs.existsSync(LOCAL_BUILD_ROOT)) { - fs.mkdirSync(LOCAL_BUILD_ROOT); - } - await createBucket(BUCKET_NAME); - const validSchema = ` - # Owners may update their owned records. - # Admins may create Employee records. - # Any authenticated user may view Employee ids & e_mails. - # Owners and members of "Admin" group may see employee salaries. - # Owners of "Admin" group may create and update employee salaries. - type Employee @model ( - subscriptions: { - level: public - } - ) @auth(rules: [ - { allow: owner, ownerField: "e_mail", operations: [update] }, - { allow: groups, groups: ["Admin"], operations: [create,update,delete]} - ]) { - id: ID! - - # The only field that can be updated by the owner. - bio: String - - # Fields with ownership conditions take precendence to the Object @auth. - # That means that both the @auth on Object AND the @auth on the field must - # be satisfied. - - # Owners & "Admin"s may view employee e_mail addresses. Only "Admin"s may create/update. - # TODO: { allow: authenticated } would be useful here so that any employee could view. - # Should also allow creation of underscore fields - e_mail: String @auth(rules: [ - { allow: groups, groups: ["Admin"], operations: [create, update, read]} - { allow: owner, ownerField: "e_mail", operations: [read]} - ]) - - # The owner & "Admin"s may view the salary. Only "Admins" may create/update. - salary: Int @auth(rules: [ - { allow: groups, groups: ["Admin"], operations: [create, update, read]} - { allow: owner, ownerField: "e_mail", operations: [read]} - ]) - - # The delete operation means you cannot update the value to "null" or "undefined". - # Since delete operations are at the object level, this actually adds auth rules to the update mutation. - notes: String @auth(rules: [{ allow: owner, ownerField: "e_mail", operations: [delete] }]) - } - - type Student @model - @auth(rules: [ - {allow: owner} - {allow: groups, groups: ["Instructor"]} - ]) { - id: String, - name: String, - bio: String, - notes: String @auth(rules: [{allow: owner}]) - } - - type Post @model - @auth(rules: [{ allow: groups, groups: ["Admin"] }, - { allow: owner, ownerField: "owner1", operations: [read, create] }]) - { - id: ID! - owner1: String! @auth(rules: [{allow: owner, ownerField: "notAllowed", operations: [update]}]) - text: String @auth(rules: [{ allow: owner, ownerField: "owner1", operations : [update]}]) - } - `; - const transformer = new GraphQLTransform({ - featureFlags, - transformers: [ - new DynamoDBModelTransformer(), - new ModelConnectionTransformer(), - new ModelAuthTransformer({ - authConfig: { - defaultAuthentication: { - authenticationType: 'AMAZON_COGNITO_USER_POOLS', - }, - additionalAuthenticationProviders: [], - }, - }), - ], - }); - const userPoolResponse = await createUserPool(cognitoClient, `UserPool${STACK_NAME}`); - USER_POOL_ID = userPoolResponse.UserPool.Id; - const userPoolClientResponse = await createUserPoolClient(cognitoClient, USER_POOL_ID, `UserPool${STACK_NAME}`); - const userPoolClientId = userPoolClientResponse.UserPoolClient.ClientId; - try { - // Clean the bucket - const out = transformer.transform(validSchema); - - const finishedStack = await deploy( - customS3Client, - cf, - STACK_NAME, - out, - { AuthCognitoUserPoolId: USER_POOL_ID }, - LOCAL_BUILD_ROOT, - BUCKET_NAME, - DEPLOYMENT_ROOT_KEY, - BUILD_TIMESTAMP, - ); - expect(finishedStack).toBeDefined(); - const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); - GRAPHQL_ENDPOINT = getApiEndpoint(finishedStack.Outputs); - - // Verify we have all the details - expect(GRAPHQL_ENDPOINT).toBeTruthy(); - expect(USER_POOL_ID).toBeTruthy(); - expect(userPoolClientId).toBeTruthy(); - - // Configure Amplify, create users, and sign in. - configureAmplify(USER_POOL_ID, userPoolClientId); - - await signupUser(USER_POOL_ID, USERNAME1, TMP_PASSWORD); - await signupUser(USER_POOL_ID, USERNAME2, TMP_PASSWORD); - await signupUser(USER_POOL_ID, USERNAME3, TMP_PASSWORD); - await createGroup(USER_POOL_ID, ADMIN_GROUP_NAME); - await createGroup(USER_POOL_ID, PARTICIPANT_GROUP_NAME); - await createGroup(USER_POOL_ID, WATCHER_GROUP_NAME); - await createGroup(USER_POOL_ID, DEVS_GROUP_NAME); - await createGroup(USER_POOL_ID, INSTRUCTOR_GROUP_NAME); - await addUserToGroup(ADMIN_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(PARTICIPANT_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(WATCHER_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(DEVS_GROUP_NAME, USERNAME2, USER_POOL_ID); - await addUserToGroup(INSTRUCTOR_GROUP_NAME, USERNAME1, USER_POOL_ID); - await addUserToGroup(INSTRUCTOR_GROUP_NAME, USERNAME2, USER_POOL_ID); - - const authResAfterGroup: any = await authenticateUser(USERNAME1, TMP_PASSWORD, REAL_PASSWORD); - const idToken = authResAfterGroup.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_1 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken }); - - const authRes2AfterGroup: any = await authenticateUser(USERNAME2, TMP_PASSWORD, REAL_PASSWORD); - const idToken2 = authRes2AfterGroup.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_2 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken2 }); - - const authRes3: any = await authenticateUser(USERNAME3, TMP_PASSWORD, REAL_PASSWORD); - const idToken3 = authRes3.getIdToken().getJwtToken(); - GRAPHQL_CLIENT_3 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken3 }); - - // Wait for any propagation to avoid random - // "The security token included in the request is invalid" errors - await new Promise((res) => setTimeout(() => res(), 5000)); - } catch (e) { - console.error(e); - expect(true).toEqual(false); - } -}); - -afterAll(async () => { - await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf, { cognitoClient, userPoolId: USER_POOL_ID }); -}); - -/** - * Tests - */ -test('that only Admins can create Employee records.', async () => { - const createUser1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createEmployee(input: { e_mail: "user2@test.com", salary: 100 }) { - id - e_mail - salary - } - }`, - {}, - ); - expect(createUser1.data.createEmployee.e_mail).toEqual('user2@test.com'); - expect(createUser1.data.createEmployee.salary).toEqual(100); - - const tryToCreateAsNonAdmin = await GRAPHQL_CLIENT_2.query( - `mutation { - createEmployee(input: { e_mail: "user2@test.com", salary: 101 }) { - id - e_mail - salary - } - }`, - {}, - ); - expect(tryToCreateAsNonAdmin.data.createEmployee).toBeNull(); - expect(tryToCreateAsNonAdmin.errors).toHaveLength(1); - - const tryToCreateAsNonAdmin2 = await GRAPHQL_CLIENT_3.query( - `mutation { - createEmployee(input: { e_mail: "user2@test.com", salary: 101 }) { - id - e_mail - salary - } - }`, - {}, - ); - expect(tryToCreateAsNonAdmin2.data.createEmployee).toBeNull(); - expect(tryToCreateAsNonAdmin2.errors).toHaveLength(1); -}); - -test('that only Admins may update salary & e_mail.', async () => { - const createUser1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createEmployee(input: { e_mail: "user2@test.com", salary: 100 }) { - id - e_mail - salary - } - }`, - {}, - ); - const employeeId = createUser1.data.createEmployee.id; - expect(employeeId).not.toBeNull(); - expect(createUser1.data.createEmployee.e_mail).toEqual('user2@test.com'); - expect(createUser1.data.createEmployee.salary).toEqual(100); - - const tryToUpdateAsNonAdmin = await GRAPHQL_CLIENT_2.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", salary: 101 }) { - id - e_mail - salary - } - }`, - {}, - ); - expect(tryToUpdateAsNonAdmin.data.updateEmployee).toBeNull(); - expect(tryToUpdateAsNonAdmin.errors).toHaveLength(1); - - const tryToUpdateAsNonAdmin2 = await GRAPHQL_CLIENT_2.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", e_mail: "someonelese@gmail.com" }) { - id - e_mail - salary - } - }`, - {}, - ); - expect(tryToUpdateAsNonAdmin2.data.updateEmployee).toBeNull(); - expect(tryToUpdateAsNonAdmin2.errors).toHaveLength(1); - - const tryToUpdateAsNonAdmin3 = await GRAPHQL_CLIENT_3.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", e_mail: "someonelese@gmail.com" }) { - id - e_mail - salary - } - }`, - {}, - ); - expect(tryToUpdateAsNonAdmin3.data.updateEmployee).toBeNull(); - expect(tryToUpdateAsNonAdmin3.errors).toHaveLength(1); - - const updateAsAdmin = await GRAPHQL_CLIENT_1.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", e_mail: "someonelese@gmail.com" }) { - id - e_mail - salary - } - }`, - {}, - ); - expect(updateAsAdmin.data.updateEmployee.e_mail).toEqual('someonelese@gmail.com'); - expect(updateAsAdmin.data.updateEmployee.salary).toEqual(100); - - const updateAsAdmin2 = await GRAPHQL_CLIENT_1.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", salary: 99 }) { - id - e_mail - salary - } - }`, - {}, - ); - expect(updateAsAdmin2.data.updateEmployee.e_mail).toEqual('someonelese@gmail.com'); - expect(updateAsAdmin2.data.updateEmployee.salary).toEqual(99); -}); - -test('that owners may update their bio.', async () => { - const createUser1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createEmployee(input: { e_mail: "user2@test.com", salary: 100 }) { - id - e_mail - salary - } - }`, - {}, - ); - const employeeId = createUser1.data.createEmployee.id; - expect(employeeId).not.toBeNull(); - expect(createUser1.data.createEmployee.e_mail).toEqual('user2@test.com'); - expect(createUser1.data.createEmployee.salary).toEqual(100); - - const tryToUpdateAsNonAdmin = await GRAPHQL_CLIENT_2.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", bio: "Does cool stuff." }) { - id - e_mail - salary - bio - } - }`, - {}, - ); - expect(tryToUpdateAsNonAdmin.data.updateEmployee.bio).toEqual('Does cool stuff.'); - expect(tryToUpdateAsNonAdmin.data.updateEmployee.e_mail).toEqual('user2@test.com'); - expect(tryToUpdateAsNonAdmin.data.updateEmployee.salary).toEqual(100); -}); - -test('that everyone may view employee bios.', async () => { - const createUser1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createEmployee(input: { e_mail: "user3@test.com", salary: 100, bio: "Likes long walks on the beach" }) { - id - e_mail - salary - bio - } - }`, - {}, - ); - const employeeId = createUser1.data.createEmployee.id; - expect(employeeId).not.toBeNull(); - expect(createUser1.data.createEmployee.e_mail).toEqual('user3@test.com'); - expect(createUser1.data.createEmployee.salary).toEqual(100); - expect(createUser1.data.createEmployee.bio).toEqual('Likes long walks on the beach'); - - const getAsNonAdmin = await GRAPHQL_CLIENT_2.query( - `query { - getEmployee(id: "${employeeId}") { - id - e_mail - bio - } - }`, - {}, - ); - // Should not be able to view the e_mail as the non owner - expect(getAsNonAdmin.data.getEmployee.e_mail).toBeNull(); - // Should be able to view the bio. - expect(getAsNonAdmin.data.getEmployee.bio).toEqual('Likes long walks on the beach'); - expect(getAsNonAdmin.errors).toHaveLength(1); - - const listAsNonAdmin = await GRAPHQL_CLIENT_2.query( - `query { - listEmployees { - items { - id - bio - } - } - }`, - {}, - ); - expect(listAsNonAdmin.data.listEmployees.items.length).toBeGreaterThan(1); - let seenId = false; - for (const item of listAsNonAdmin.data.listEmployees.items) { - if (item.id === employeeId) { - seenId = true; - expect(item.bio).toEqual('Likes long walks on the beach'); - } - } - expect(seenId).toEqual(true); -}); - -test('that only owners may "delete" i.e. update the field to null.', async () => { - const createUser1 = await GRAPHQL_CLIENT_1.query( - `mutation { - createEmployee(input: { e_mail: "user3@test.com", salary: 200, notes: "note1" }) { - id - e_mail - salary - notes - } - }`, - {}, - ); - const employeeId = createUser1.data.createEmployee.id; - expect(employeeId).not.toBeNull(); - expect(createUser1.data.createEmployee.e_mail).toEqual('user3@test.com'); - expect(createUser1.data.createEmployee.salary).toEqual(200); - expect(createUser1.data.createEmployee.notes).toEqual('note1'); - - const tryToDeleteUserNotes = await GRAPHQL_CLIENT_2.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", notes: null }) { - id - notes - } - }`, - {}, - ); - expect(tryToDeleteUserNotes.data.updateEmployee).toBeNull(); - expect(tryToDeleteUserNotes.errors).toHaveLength(1); - - const updateNewsWithNotes = await GRAPHQL_CLIENT_3.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", notes: "something else" }) { - id - notes - } - }`, - {}, - ); - expect(updateNewsWithNotes.data.updateEmployee.notes).toEqual('something else'); - - const updateAsAdmin = await GRAPHQL_CLIENT_1.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", notes: null }) { - id - notes - } - }`, - {}, - ); - expect(updateAsAdmin.data.updateEmployee).toBeNull(); - expect(updateAsAdmin.errors).toHaveLength(1); - - const deleteNotes = await GRAPHQL_CLIENT_3.query( - `mutation { - updateEmployee(input: { id: "${employeeId}", notes: null }) { - id - notes - } - }`, - {}, - ); - expect(deleteNotes.data.updateEmployee.notes).toBeNull(); -}); - -test('with auth with subscriptions on default behavior', async () => { - /** - * client 1 and 2 are in the same user pool though client 1 should - * not be able to see notes if they are created by client 2 - * */ - const secureNote1 = 'secureNote1'; - const createStudent2 = await GRAPHQL_CLIENT_2.query( - `mutation { - createStudent(input: {bio: "bio1", name: "student1", notes: "${secureNote1}"}) { - id - bio - name - notes - owner - } - }`, - {}, - ); - expect(createStudent2.data.createStudent.id).toBeDefined(); - const createStudent1queryID = createStudent2.data.createStudent.id; - expect(createStudent2.data.createStudent.bio).toEqual('bio1'); - expect(createStudent2.data.createStudent.notes).toBeNull(); - // running query as username2 should return value - const queryForStudent2 = await GRAPHQL_CLIENT_2.query( - `query { - getStudent(id: "${createStudent1queryID}") { - bio - id - name - notes - owner - } - }`, - {}, - ); - expect(queryForStudent2.data.getStudent.notes).toEqual(secureNote1); - - // running query as username3 should return the type though return notes as null - const queryAsStudent1 = await GRAPHQL_CLIENT_1.query( - `query { - getStudent(id: "${createStudent1queryID}") { - bio - id - name - notes - owner - } - }`, - {}, - ); - expect(queryAsStudent1.data.getStudent.notes).toBeNull(); -}); - -test('AND per-field dynamic auth rule test', async () => { - const createPostResponse = await GRAPHQL_CLIENT_1.query(`mutation CreatePost { - createPost(input: {owner1: "${USERNAME1}", text: "mytext"}) { - id - text - owner1 - } - }`); - const postID1 = createPostResponse.data.createPost.id; - expect(postID1).toBeDefined(); - expect(createPostResponse.data.createPost.text).toEqual('mytext'); - expect(createPostResponse.data.createPost.owner1).toEqual(USERNAME1); - - const badUpdatePostResponse = await GRAPHQL_CLIENT_1.query(`mutation UpdatePost { - updatePost(input: {id: "${postID1}", text: "newText", owner1: "${USERNAME1}"}) { - id - owner1 - text - } - } - `); - expect(badUpdatePostResponse.errors[0].data).toBeNull(); - expect(badUpdatePostResponse.errors[0].errorType).toEqual('DynamoDB:ConditionalCheckFailedException'); - - const correctUpdatePostResponse = await GRAPHQL_CLIENT_1.query(`mutation UpdatePost { - updatePost(input: {id: "${postID1}", text: "newText"}) { - id - owner1 - text - } - }`); - expect(correctUpdatePostResponse.data.updatePost.owner1).toEqual(USERNAME1); - expect(correctUpdatePostResponse.data.updatePost.text).toEqual('newText'); -}); From eb9dbb8de191e6dfb0618e3b8e6582bab5443644 Mon Sep 17 00:00:00 2001 From: Doesnt Matter Date: Wed, 14 Aug 2024 18:05:48 -0700 Subject: [PATCH 18/23] chore: move amplify schema validator --- dependency_licenses.txt | 1754 ++---------- packages/amplify-category-api/CHANGELOG.md | 2408 ----------------- packages/amplify-category-api/package.json | 126 - .../express/package.json | 18 - .../dockerfile-rest-express/package.json | 17 - .../graphql-express/package.json | 16 - packages/amplify-schema-validator/API.md | 17 - .../amplify-schema-validator/CHANGELOG.md | 88 - packages/amplify-schema-validator/README.md | 17 - .../api-extractor.json | 44 - .../amplify-schema-validator/jest.config.js | 17 - .../amplify-schema-validator/package.json | 42 - .../src/__tests__/helpers/readSchema.ts | 8 - ...-auth-must-be-annotated-with-model.graphql | 7 - ...ds-match-related-type-primary-key1.graphql | 13 - ...ds-match-related-type-primary-key2.graphql | 13 - ...ds-match-related-type-primary-key3.graphql | 13 - ...ds-match-related-type-primary-key4.graphql | 14 - .../invalid-belongs-to-wrong-field.graphql | 11 - .../schemas/invalid-belongs-to.graphql | 11 - ...rect-type-in-many-to-many-relation.graphql | 13 - .../invalid-default-directive1.graphql | 4 - .../invalid-default-directive2.graphql | 8 - .../invalid-default-directive3.graphql | 4 - .../invalid-default-directive4.graphql | 4 - .../schemas/invalid-empty-schema.graphql | 0 .../invalid-enum-is-defined-once.graphql | 15 - .../invalid-field-is-not-defined-once.graphql | 5 - ...-field-not-in-parent-model-hasMany.graphql | 11 - .../invalid-field-not-in-parent-model.graphql | 11 - ...id-hasMany-must-be-used-with-lists.graphql | 9 - ...d-hasOne-cannot-be-used-with-lists.graphql | 9 - .../invalid-index-directive-schema.graphql | 24 - ...alid-index-exists-in-related-model.graphql | 11 - ...lid-index-is-defined-once-in-model.graphql | 5 - ...nvalid-key-exists-in-related-model.graphql | 15 - .../invalid-many-to-many-count.graphql | 18 - ...y-to-many-has-a-relationname-test1.graphql | 4 - ...y-to-many-has-a-relationname-test2.graphql | 4 - ...bject-must-be-annotated-with-model.graphql | 9 - .../invalid-owner-field-type-string.graphql | 7 - ...ame-doesnot-conflict-with-typename.graphql | 13 - ...hipname-not-inverseof-relationname.graphql | 9 - .../invalid-reserved-field-name.graphql | 5 - .../invalid-reserved-type-name.graphql | 4 - .../invalid-sort-key-field-exists.graphql | 5 - .../invalid-type-is-not-defined-once.graphql | 11 - ...d-unique-field-names-with-relation.graphql | 17 - ...use-belongsto-when-datastore-inuse.graphql | 9 - ...ves-from-newer-transformer-version.graphql | 5 - ...ves-from-older-transformer-version.graphql | 11 - .../schemas/schema-with-nonnulltype.graphql | 135 - ...-auth-must-be-annotated-with-model.graphql | 7 - ...lds-match-related-type-primary-key.graphql | 12 - .../schemas/valid-belongs-to-has-many.graphql | 11 - .../schemas/valid-belongs-to-has-one.graphql | 11 - .../schemas/valid-blank-schema.graphql | 5 - .../schemas/valid-blog-schema.graphql | 18 - ...rect-type-in-many-to-many-relation.graphql | 13 - .../schemas/valid-default-directive.graphql | 4 - .../valid-enum-is-defined-once.graphql | 14 - .../valid-field-in-parent-model.graphql | 10 - .../valid-field-is-defined-once.graphql | 5 - ...id-hasMany-must-be-used-with-lists.graphql | 9 - ...d-hasOne-cannot-be-used-with-lists.graphql | 9 - .../valid-index-directive-schema.graphql | 11 - ...alid-index-exists-in-related-model.graphql | 11 - ...lid-index-is-defined-once-in-model.graphql | 5 - .../valid-key-exists-in-related-model.graphql | 12 - ...id-many-to-many-has-a-relationname.graphql | 9 - ...bject-must-be-annotated-with-model.graphql | 9 - .../valid-owner-field-type-string.graphql | 7 - ...hipname-not-inverseof-relationname.graphql | 9 - .../schemas/valid-reserved-type-name.graphql | 4 - .../valid-sort-key-field-exists.graphql | 6 - .../schemas/valid-todo-schema.graphql | 18 - .../valid-type-is-defined-once.graphql | 5 - ...d-unique-field-names-with-relation.graphql | 17 - .../utils/resolve-field-type-name.test.ts | 155 -- ...-auth-must-be-annotated-with-model.test.ts | 15 - ...lds-match-related-type-primary-key.test.ts | 33 - ...lidates-belongs-to-relation-exists.test.ts | 21 - .../validates-cli-generated-schemas.test.ts | 19 - ...rect-type-in-many-to-many-relation.test.ts | 15 - .../validates-default-directive.test.ts | 33 - .../validates-enum-is-defined-once.test.ts | 15 - .../validates-field-is-defined-once.test.ts | 15 - ...dates-fields-match-in-parent-model.test.ts | 21 - .../validates-graphql-syntax.test.ts | 16 - ...lidates-hasMany-is-used-with-lists.test.ts | 15 - ...ates-hasOne-is-not-used-with-lists.test.ts | 15 - ...ates-index-exists-in-related-model.test.ts | 15 - ...tes-index-is-defined-once-in-model.test.ts | 15 - ...idates-key-exists-in-related-model.test.ts | 15 - ...es-many-to-many-has-a-relationname.test.ts | 21 - ...dates-many-to-many-relations-match.test.ts | 10 - ...bject-must-be-annotated-with-model.test.ts | 15 - .../validates-owner-field-type-string.test.ts | 15 - ...ame-doesnot-conflict-with-typename.test.ts | 10 - ...hipname-not-inverseof-relationname.test.ts | 15 - .../validates-reserved-field-name.test.ts | 10 - .../validates-reserved-type-name.test.ts | 15 - .../__tests__/validates-scalar-index.test.ts | 15 - ...validates-schemas-with-nonnulltype.test.ts | 9 - .../validates-sort-key-field-exists.test.ts | 15 - .../validates-type-is-defined-once.test.ts | 15 - ...s-unique-field-names-with-relation.test.ts | 15 - ...use-belongsto-when-datastore-inuse.test.ts | 25 - ...ves-from-newer-transformer-version.test.ts | 17 - ...ves-from-older-transformer-version.test.ts | 17 - .../src/exceptions/invalid-directive-error.ts | 10 - .../src/exceptions/validation-error.ts | 10 - .../src/helpers/get-object-with-name.ts | 15 - .../helpers/get-type-definitions-of-kind.ts | 13 - .../src/helpers/is-scalar-or-enum.ts | 58 - .../src/helpers/resolve-field-type-name.ts | 40 - .../src/helpers/resolve-field-type.ts | 17 - .../src/helpers/schema-validator-props.ts | 4 - .../src/helpers/transformer-validation.ts | 15 - .../src/helpers/util.ts | 16 - .../amplify-schema-validator/src/index.ts | 101 - .../auth-must-be-annotated-with-model.ts | 23 - ...o-fields-match-related-type-primary-key.ts | 106 - .../correct-type-in-many-to-many-relation.ts | 80 - .../default-directive-validation.ts | 66 - .../src/validators/enum-is-defined-once.ts | 36 - .../src/validators/field-is-defined-once.ts | 35 - .../fields-match-in-parent-model.ts | 55 - .../hasMany-must-be-used-with-lists.ts | 35 - .../hasOne-cannot-be-used-with-lists.ts | 35 - .../index-exists-in-related-model.ts | 65 - .../index-is-defined-once-in-model.ts | 46 - .../src/validators/index-scalar-types.ts | 34 - .../validators/key-exists-in-related-model.ts | 51 - .../many-to-many-has-a-relationname.ts | 35 - .../object-must-be-annotated-with-model.ts | 38 - .../src/validators/owner-field-type-string.ts | 37 - .../relation-required-with-belongs-to.ts | 38 - ...tionname-doesnot-conflict-with-typename.ts | 45 - ...tionshipname-not-inverseof-relationname.ts | 45 - .../src/validators/reserved-field-name.ts | 28 - .../src/validators/reserved-type-name.ts | 25 - .../src/validators/sort-key-field-exists.ts | 48 - .../validators/two-many-to-many-locations.ts | 43 - .../src/validators/type-is-defined-once.ts | 27 - .../unique-field-names-with-relation.ts | 34 - .../use-belongsto-when-datastore-inuse.ts | 67 - ...rectives-from-newer-transformer-version.ts | 41 - ...rectives-from-older-transformer-version.ts | 38 - .../amplify-schema-validator/tsconfig.json | 15 - packages/amplify-util-mock/CHANGELOG.md | 1661 ------------ packages/amplify-util-mock/package.json | 135 - yarn.lock | 1501 +--------- 153 files changed, 257 insertions(+), 10601 deletions(-) delete mode 100644 packages/amplify-category-api/CHANGELOG.md delete mode 100644 packages/amplify-category-api/package.json delete mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/package.json delete mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/package.json delete mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/package.json delete mode 100644 packages/amplify-schema-validator/API.md delete mode 100644 packages/amplify-schema-validator/CHANGELOG.md delete mode 100644 packages/amplify-schema-validator/README.md delete mode 100644 packages/amplify-schema-validator/api-extractor.json delete mode 100644 packages/amplify-schema-validator/jest.config.js delete mode 100644 packages/amplify-schema-validator/package.json delete mode 100644 packages/amplify-schema-validator/src/__tests__/helpers/readSchema.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-auth-must-be-annotated-with-model.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-fields-match-related-type-primary-key1.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-fields-match-related-type-primary-key2.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-fields-match-related-type-primary-key3.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-fields-match-related-type-primary-key4.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-wrong-field.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-correct-type-in-many-to-many-relation.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-default-directive1.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-default-directive2.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-default-directive3.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-default-directive4.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-empty-schema.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-enum-is-defined-once.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-field-is-not-defined-once.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-field-not-in-parent-model-hasMany.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-field-not-in-parent-model.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-hasMany-must-be-used-with-lists.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-hasOne-cannot-be-used-with-lists.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-index-directive-schema.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-index-exists-in-related-model.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-index-is-defined-once-in-model.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-key-exists-in-related-model.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-many-to-many-count.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-many-to-many-has-a-relationname-test1.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-many-to-many-has-a-relationname-test2.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-object-must-be-annotated-with-model.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-owner-field-type-string.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-relationname-doesnot-conflict-with-typename.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-relationshipname-not-inverseof-relationname.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-reserved-field-name.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-reserved-type-name.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-sort-key-field-exists.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-type-is-not-defined-once.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-unique-field-names-with-relation.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-use-belongsto-when-datastore-inuse.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-use-directives-from-newer-transformer-version.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/invalid-use-directives-from-older-transformer-version.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/schema-with-nonnulltype.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-auth-must-be-annotated-with-model.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-belongs-to-fields-match-related-type-primary-key.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-belongs-to-has-many.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-belongs-to-has-one.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-blank-schema.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-blog-schema.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-correct-type-in-many-to-many-relation.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-default-directive.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-enum-is-defined-once.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-field-in-parent-model.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-field-is-defined-once.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-hasMany-must-be-used-with-lists.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-hasOne-cannot-be-used-with-lists.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-index-directive-schema.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-index-exists-in-related-model.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-index-is-defined-once-in-model.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-key-exists-in-related-model.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-many-to-many-has-a-relationname.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-object-must-be-annotated-with-model.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-owner-field-type-string.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-relationshipname-not-inverseof-relationname.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-reserved-type-name.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-sort-key-field-exists.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-todo-schema.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-type-is-defined-once.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/schemas/valid-unique-field-names-with-relation.graphql delete mode 100644 packages/amplify-schema-validator/src/__tests__/utils/resolve-field-type-name.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-auth-must-be-annotated-with-model.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-belongs-to-fields-match-related-type-primary-key.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-belongs-to-relation-exists.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-cli-generated-schemas.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-correct-type-in-many-to-many-relation.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-default-directive.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-enum-is-defined-once.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-field-is-defined-once.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-fields-match-in-parent-model.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-graphql-syntax.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-hasMany-is-used-with-lists.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-hasOne-is-not-used-with-lists.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-index-exists-in-related-model.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-index-is-defined-once-in-model.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-key-exists-in-related-model.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-many-to-many-has-a-relationname.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-many-to-many-relations-match.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-object-must-be-annotated-with-model.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-owner-field-type-string.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-relationname-doesnot-conflict-with-typename.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-relationshipname-not-inverseof-relationname.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-reserved-field-name.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-reserved-type-name.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-scalar-index.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-schemas-with-nonnulltype.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-sort-key-field-exists.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-type-is-defined-once.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-unique-field-names-with-relation.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-use-belongsto-when-datastore-inuse.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-use-directives-from-newer-transformer-version.test.ts delete mode 100644 packages/amplify-schema-validator/src/__tests__/validates-use-directives-from-older-transformer-version.test.ts delete mode 100644 packages/amplify-schema-validator/src/exceptions/invalid-directive-error.ts delete mode 100644 packages/amplify-schema-validator/src/exceptions/validation-error.ts delete mode 100644 packages/amplify-schema-validator/src/helpers/get-object-with-name.ts delete mode 100644 packages/amplify-schema-validator/src/helpers/get-type-definitions-of-kind.ts delete mode 100644 packages/amplify-schema-validator/src/helpers/is-scalar-or-enum.ts delete mode 100644 packages/amplify-schema-validator/src/helpers/resolve-field-type-name.ts delete mode 100644 packages/amplify-schema-validator/src/helpers/resolve-field-type.ts delete mode 100644 packages/amplify-schema-validator/src/helpers/schema-validator-props.ts delete mode 100644 packages/amplify-schema-validator/src/helpers/transformer-validation.ts delete mode 100644 packages/amplify-schema-validator/src/helpers/util.ts delete mode 100644 packages/amplify-schema-validator/src/index.ts delete mode 100644 packages/amplify-schema-validator/src/validators/auth-must-be-annotated-with-model.ts delete mode 100644 packages/amplify-schema-validator/src/validators/belongs-to-fields-match-related-type-primary-key.ts delete mode 100644 packages/amplify-schema-validator/src/validators/correct-type-in-many-to-many-relation.ts delete mode 100644 packages/amplify-schema-validator/src/validators/default-directive-validation.ts delete mode 100644 packages/amplify-schema-validator/src/validators/enum-is-defined-once.ts delete mode 100644 packages/amplify-schema-validator/src/validators/field-is-defined-once.ts delete mode 100644 packages/amplify-schema-validator/src/validators/fields-match-in-parent-model.ts delete mode 100644 packages/amplify-schema-validator/src/validators/hasMany-must-be-used-with-lists.ts delete mode 100644 packages/amplify-schema-validator/src/validators/hasOne-cannot-be-used-with-lists.ts delete mode 100644 packages/amplify-schema-validator/src/validators/index-exists-in-related-model.ts delete mode 100644 packages/amplify-schema-validator/src/validators/index-is-defined-once-in-model.ts delete mode 100644 packages/amplify-schema-validator/src/validators/index-scalar-types.ts delete mode 100644 packages/amplify-schema-validator/src/validators/key-exists-in-related-model.ts delete mode 100644 packages/amplify-schema-validator/src/validators/many-to-many-has-a-relationname.ts delete mode 100644 packages/amplify-schema-validator/src/validators/object-must-be-annotated-with-model.ts delete mode 100644 packages/amplify-schema-validator/src/validators/owner-field-type-string.ts delete mode 100644 packages/amplify-schema-validator/src/validators/relation-required-with-belongs-to.ts delete mode 100644 packages/amplify-schema-validator/src/validators/relationname-doesnot-conflict-with-typename.ts delete mode 100644 packages/amplify-schema-validator/src/validators/relationshipname-not-inverseof-relationname.ts delete mode 100644 packages/amplify-schema-validator/src/validators/reserved-field-name.ts delete mode 100644 packages/amplify-schema-validator/src/validators/reserved-type-name.ts delete mode 100644 packages/amplify-schema-validator/src/validators/sort-key-field-exists.ts delete mode 100644 packages/amplify-schema-validator/src/validators/two-many-to-many-locations.ts delete mode 100644 packages/amplify-schema-validator/src/validators/type-is-defined-once.ts delete mode 100644 packages/amplify-schema-validator/src/validators/unique-field-names-with-relation.ts delete mode 100644 packages/amplify-schema-validator/src/validators/use-belongsto-when-datastore-inuse.ts delete mode 100644 packages/amplify-schema-validator/src/validators/use-directives-from-newer-transformer-version.ts delete mode 100644 packages/amplify-schema-validator/src/validators/use-directives-from-older-transformer-version.ts delete mode 100644 packages/amplify-schema-validator/tsconfig.json delete mode 100644 packages/amplify-util-mock/CHANGELOG.md delete mode 100644 packages/amplify-util-mock/package.json diff --git a/dependency_licenses.txt b/dependency_licenses.txt index 5f86cb0572..dd7bc91eaa 100644 --- a/dependency_licenses.txt +++ b/dependency_licenses.txt @@ -27,7 +27,7 @@ THE SOFTWARE. ----- -The following software may be included in this product: @ampproject/remapping, @aws-crypto/ie11-detection, @aws-crypto/sha1-browser, @aws-crypto/sha256-browser, @aws-crypto/sha256-universal, @aws-crypto/supports-web-crypto, @hutson/parse-repository-url, @xtuc/long, ejs, jsii-docgen, long, spdx-correct, teeny-request, validate-npm-package-license, xcode. A copy of the source code may be downloaded from git+https://github.com/ampproject/remapping.git (@ampproject/remapping), git@github.com:aws/aws-sdk-js-crypto-helpers.git (@aws-crypto/ie11-detection), git@github.com:aws/aws-sdk-js-crypto-helpers.git (@aws-crypto/sha1-browser), git@github.com:aws/aws-sdk-js-crypto-helpers.git (@aws-crypto/sha256-browser), git@github.com:aws/aws-sdk-js-crypto-helpers.git (@aws-crypto/sha256-universal), git@github.com:aws/aws-sdk-js-crypto-helpers.git (@aws-crypto/supports-web-crypto), https://gitlab.com/hyper-expanse/open-source/parse-repository-url.git (@hutson/parse-repository-url), https://github.com/dcodeIO/long.js.git (@xtuc/long), git://github.com/mde/ejs.git (ejs), https://github.com/cdklabs/jsii-docgen (jsii-docgen), https://github.com/dcodeIO/long.js.git (long), https://github.com/jslicense/spdx-correct.js.git (spdx-correct), https://github.com/googleapis/teeny-request.git (teeny-request), https://github.com/kemitchell/validate-npm-package-license.js.git (validate-npm-package-license), https://github.com/apache/cordova-node-xcode.git (xcode). This software contains the following license and notice below: +The following software may be included in this product: @ampproject/remapping, @aws-crypto/ie11-detection, @aws-crypto/sha1-browser, @aws-crypto/sha256-browser, @aws-crypto/sha256-universal, @aws-crypto/supports-web-crypto, @hutson/parse-repository-url, ejs, jsii-docgen, long, spdx-correct, teeny-request, validate-npm-package-license, xcode. A copy of the source code may be downloaded from git+https://github.com/ampproject/remapping.git (@ampproject/remapping), git@github.com:aws/aws-sdk-js-crypto-helpers.git (@aws-crypto/ie11-detection), git@github.com:aws/aws-sdk-js-crypto-helpers.git (@aws-crypto/sha1-browser), git@github.com:aws/aws-sdk-js-crypto-helpers.git (@aws-crypto/sha256-browser), git@github.com:aws/aws-sdk-js-crypto-helpers.git (@aws-crypto/sha256-universal), git@github.com:aws/aws-sdk-js-crypto-helpers.git (@aws-crypto/supports-web-crypto), https://gitlab.com/hyper-expanse/open-source/parse-repository-url.git (@hutson/parse-repository-url), git://github.com/mde/ejs.git (ejs), https://github.com/cdklabs/jsii-docgen (jsii-docgen), https://github.com/dcodeIO/long.js.git (long), https://github.com/jslicense/spdx-correct.js.git (spdx-correct), https://github.com/googleapis/teeny-request.git (teeny-request), https://github.com/kemitchell/validate-npm-package-license.js.git (validate-npm-package-license), https://github.com/apache/cordova-node-xcode.git (xcode). This software contains the following license and notice below: Apache License Version 2.0, January 2004 @@ -3607,56 +3607,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: @discoveryjs/json-ext. A copy of the source code may be downloaded from https://github.com/discoveryjs/json-ext.git. This software contains the following license and notice below: - -MIT License - -Copyright (c) 2020 Roman Dvornov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: @discoveryjs/natural-compare. A copy of the source code may be downloaded from https://github.com/discoveryjs/natural-compare.git. This software contains the following license and notice below: - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: @eslint-community/eslint-utils, @eslint-community/regexpp. A copy of the source code may be downloaded from https://github.com/eslint-community/eslint-utils (@eslint-community/eslint-utils), https://github.com/eslint-community/regexpp (@eslint-community/regexpp). This software contains the following license and notice below: MIT License @@ -4163,7 +4113,7 @@ SOFTWARE. ----- -The following software may be included in this product: @jridgewell/resolve-uri, @jridgewell/source-map. A copy of the source code may be downloaded from https://github.com/jridgewell/resolve-uri (@jridgewell/resolve-uri), https://github.com/jridgewell/source-map (@jridgewell/source-map). This software contains the following license and notice below: +The following software may be included in this product: @jridgewell/resolve-uri. A copy of the source code may be downloaded from https://github.com/jridgewell/resolve-uri. This software contains the following license and notice below: Copyright 2019 Justin Ridgewell @@ -4987,20 +4937,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: @samverschueren/stream-to-observable. A copy of the source code may be downloaded from https://github.com/SamVerschueren/stream-to-observable.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) James Talmage (github.com/jamestalmage), Sam Verschueren (github.com/SamVerschueren) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: @sigstore/bundle, @sigstore/protobuf-specs, @sigstore/sign, @sigstore/tuf, sigstore. A copy of the source code may be downloaded from git+https://github.com/sigstore/sigstore-js.git (@sigstore/bundle), git+https://github.com/sigstore/protobuf-specs.git (@sigstore/protobuf-specs), git+https://github.com/sigstore/sigstore-js.git (@sigstore/sign), git+https://github.com/sigstore/sigstore-js.git (@sigstore/tuf), git+https://github.com/sigstore/sigstore-js.git (sigstore). This software contains the following license and notice below: Apache License @@ -5207,7 +5143,7 @@ Apache License ----- -The following software may be included in this product: @sindresorhus/is, ansi-escapes, ansi-regex, ansi-styles, boxen, camelcase, chalk, cli-boxes, cli-cursor, cli-spinners, cli-truncate, crypto-random-string, decompress-response, dot-prop, emittery, escape-goat, escape-string-regexp, execa, figures, find-cache-dir, find-up, get-stdin, get-stream, global-dirs, globals, gzip-size, has-yarn, import-fresh, import-from, into-stream, is-docker, is-fullwidth-code-point, is-installed-globally, is-npm, is-stream, is-unicode-supported, latest-version, locate-path, log-symbols, log-update, lowercase-keys, make-dir, map-obj, meow, mimic-fn, mimic-response, multimatch, normalize-url, npm-run-path, onetime, open, ora, p-cancelable, p-each-series, p-limit, p-locate, p-map, p-pipe, p-queue, p-waterfall, package-json, parse-json, path-key, pify, pupa, registry-url, restore-cursor, semver-diff, sort-keys, string-length, string-width, strip-ansi, strip-final-newline, strip-json-comments, supports-color, type-fest, unique-string, widest-line, wrap-ansi, wrap-ansi-cjs, xdg-basedir, yocto-queue. A copy of the source code may be downloaded from https://github.com/sindresorhus/is.git (@sindresorhus/is), https://github.com/sindresorhus/ansi-escapes.git (ansi-escapes), https://github.com/chalk/ansi-regex.git (ansi-regex), https://github.com/chalk/ansi-styles.git (ansi-styles), https://github.com/sindresorhus/boxen.git (boxen), https://github.com/sindresorhus/camelcase.git (camelcase), https://github.com/chalk/chalk.git (chalk), https://github.com/sindresorhus/cli-boxes.git (cli-boxes), https://github.com/sindresorhus/cli-cursor.git (cli-cursor), https://github.com/sindresorhus/cli-spinners.git (cli-spinners), https://github.com/sindresorhus/cli-truncate.git (cli-truncate), https://github.com/sindresorhus/crypto-random-string.git (crypto-random-string), https://github.com/sindresorhus/decompress-response.git (decompress-response), https://github.com/sindresorhus/dot-prop.git (dot-prop), https://github.com/sindresorhus/emittery.git (emittery), https://github.com/sindresorhus/escape-goat.git (escape-goat), https://github.com/sindresorhus/escape-string-regexp.git (escape-string-regexp), https://github.com/sindresorhus/execa.git (execa), https://github.com/sindresorhus/figures.git (figures), https://github.com/avajs/find-cache-dir.git (find-cache-dir), https://github.com/sindresorhus/find-up.git (find-up), https://github.com/sindresorhus/get-stdin.git (get-stdin), https://github.com/sindresorhus/get-stream.git (get-stream), https://github.com/sindresorhus/global-dirs.git (global-dirs), https://github.com/sindresorhus/globals.git (globals), https://github.com/sindresorhus/gzip-size.git (gzip-size), https://github.com/sindresorhus/has-yarn.git (has-yarn), https://github.com/sindresorhus/import-fresh.git (import-fresh), https://github.com/sindresorhus/import-from.git (import-from), https://github.com/sindresorhus/into-stream.git (into-stream), https://github.com/sindresorhus/is-docker.git (is-docker), https://github.com/sindresorhus/is-fullwidth-code-point.git (is-fullwidth-code-point), https://github.com/sindresorhus/is-installed-globally.git (is-installed-globally), https://github.com/sindresorhus/is-npm.git (is-npm), https://github.com/sindresorhus/is-stream.git (is-stream), https://github.com/sindresorhus/is-unicode-supported.git (is-unicode-supported), https://github.com/sindresorhus/latest-version.git (latest-version), https://github.com/sindresorhus/locate-path.git (locate-path), https://github.com/sindresorhus/log-symbols.git (log-symbols), https://github.com/sindresorhus/log-update.git (log-update), https://github.com/sindresorhus/lowercase-keys.git (lowercase-keys), https://github.com/sindresorhus/make-dir.git (make-dir), https://github.com/sindresorhus/map-obj.git (map-obj), https://github.com/sindresorhus/meow.git (meow), https://github.com/sindresorhus/mimic-fn.git (mimic-fn), https://github.com/sindresorhus/mimic-response.git (mimic-response), https://github.com/sindresorhus/multimatch.git (multimatch), https://github.com/sindresorhus/normalize-url.git (normalize-url), https://github.com/sindresorhus/npm-run-path.git (npm-run-path), https://github.com/sindresorhus/onetime.git (onetime), https://github.com/sindresorhus/open.git (open), https://github.com/sindresorhus/ora.git (ora), https://github.com/sindresorhus/p-cancelable.git (p-cancelable), https://github.com/sindresorhus/p-each-series.git (p-each-series), https://github.com/sindresorhus/p-limit.git (p-limit), https://github.com/sindresorhus/p-locate.git (p-locate), https://github.com/sindresorhus/p-map.git (p-map), https://github.com/sindresorhus/p-pipe.git (p-pipe), https://github.com/sindresorhus/p-queue.git (p-queue), https://github.com/sindresorhus/p-waterfall.git (p-waterfall), https://github.com/sindresorhus/package-json.git (package-json), https://github.com/sindresorhus/parse-json.git (parse-json), https://github.com/sindresorhus/path-key.git (path-key), https://github.com/sindresorhus/pify.git (pify), https://github.com/sindresorhus/pupa.git (pupa), https://github.com/sindresorhus/registry-url.git (registry-url), https://github.com/sindresorhus/restore-cursor.git (restore-cursor), https://github.com/sindresorhus/semver-diff.git (semver-diff), https://github.com/sindresorhus/sort-keys.git (sort-keys), https://github.com/sindresorhus/string-length.git (string-length), https://github.com/sindresorhus/string-width.git (string-width), https://github.com/chalk/strip-ansi.git (strip-ansi), https://github.com/sindresorhus/strip-final-newline.git (strip-final-newline), https://github.com/sindresorhus/strip-json-comments.git (strip-json-comments), https://github.com/chalk/supports-color.git (supports-color), https://github.com/sindresorhus/type-fest.git (type-fest), https://github.com/sindresorhus/unique-string.git (unique-string), https://github.com/sindresorhus/widest-line.git (widest-line), https://github.com/chalk/wrap-ansi.git (wrap-ansi), https://github.com/chalk/wrap-ansi.git (wrap-ansi-cjs), https://github.com/sindresorhus/xdg-basedir.git (xdg-basedir), https://github.com/sindresorhus/yocto-queue.git (yocto-queue). This software contains the following license and notice below: +The following software may be included in this product: @sindresorhus/is, ansi-escapes, ansi-regex, ansi-styles, boxen, camelcase, chalk, cli-boxes, cli-cursor, cli-spinners, cli-truncate, crypto-random-string, decompress-response, dot-prop, emittery, escape-goat, escape-string-regexp, execa, figures, find-cache-dir, find-up, get-stdin, get-stream, global-dirs, globals, has-yarn, import-fresh, import-from, into-stream, is-docker, is-fullwidth-code-point, is-installed-globally, is-npm, is-stream, is-unicode-supported, latest-version, locate-path, log-symbols, log-update, lowercase-keys, make-dir, map-obj, meow, mimic-fn, mimic-response, multimatch, normalize-url, npm-run-path, onetime, open, ora, p-cancelable, p-each-series, p-limit, p-locate, p-map, p-pipe, p-queue, p-waterfall, package-json, parse-json, path-key, pify, pupa, registry-url, restore-cursor, semver-diff, sort-keys, string-length, string-width, strip-ansi, strip-final-newline, strip-json-comments, type-fest, unique-string, widest-line, wrap-ansi, wrap-ansi-cjs, xdg-basedir, yocto-queue. A copy of the source code may be downloaded from https://github.com/sindresorhus/is.git (@sindresorhus/is), https://github.com/sindresorhus/ansi-escapes.git (ansi-escapes), https://github.com/chalk/ansi-regex.git (ansi-regex), https://github.com/chalk/ansi-styles.git (ansi-styles), https://github.com/sindresorhus/boxen.git (boxen), https://github.com/sindresorhus/camelcase.git (camelcase), https://github.com/chalk/chalk.git (chalk), https://github.com/sindresorhus/cli-boxes.git (cli-boxes), https://github.com/sindresorhus/cli-cursor.git (cli-cursor), https://github.com/sindresorhus/cli-spinners.git (cli-spinners), https://github.com/sindresorhus/cli-truncate.git (cli-truncate), https://github.com/sindresorhus/crypto-random-string.git (crypto-random-string), https://github.com/sindresorhus/decompress-response.git (decompress-response), https://github.com/sindresorhus/dot-prop.git (dot-prop), https://github.com/sindresorhus/emittery.git (emittery), https://github.com/sindresorhus/escape-goat.git (escape-goat), https://github.com/sindresorhus/escape-string-regexp.git (escape-string-regexp), https://github.com/sindresorhus/execa.git (execa), https://github.com/sindresorhus/figures.git (figures), https://github.com/avajs/find-cache-dir.git (find-cache-dir), https://github.com/sindresorhus/find-up.git (find-up), https://github.com/sindresorhus/get-stdin.git (get-stdin), https://github.com/sindresorhus/get-stream.git (get-stream), https://github.com/sindresorhus/global-dirs.git (global-dirs), https://github.com/sindresorhus/globals.git (globals), https://github.com/sindresorhus/has-yarn.git (has-yarn), https://github.com/sindresorhus/import-fresh.git (import-fresh), https://github.com/sindresorhus/import-from.git (import-from), https://github.com/sindresorhus/into-stream.git (into-stream), https://github.com/sindresorhus/is-docker.git (is-docker), https://github.com/sindresorhus/is-fullwidth-code-point.git (is-fullwidth-code-point), https://github.com/sindresorhus/is-installed-globally.git (is-installed-globally), https://github.com/sindresorhus/is-npm.git (is-npm), https://github.com/sindresorhus/is-stream.git (is-stream), https://github.com/sindresorhus/is-unicode-supported.git (is-unicode-supported), https://github.com/sindresorhus/latest-version.git (latest-version), https://github.com/sindresorhus/locate-path.git (locate-path), https://github.com/sindresorhus/log-symbols.git (log-symbols), https://github.com/sindresorhus/log-update.git (log-update), https://github.com/sindresorhus/lowercase-keys.git (lowercase-keys), https://github.com/sindresorhus/make-dir.git (make-dir), https://github.com/sindresorhus/map-obj.git (map-obj), https://github.com/sindresorhus/meow.git (meow), https://github.com/sindresorhus/mimic-fn.git (mimic-fn), https://github.com/sindresorhus/mimic-response.git (mimic-response), https://github.com/sindresorhus/multimatch.git (multimatch), https://github.com/sindresorhus/normalize-url.git (normalize-url), https://github.com/sindresorhus/npm-run-path.git (npm-run-path), https://github.com/sindresorhus/onetime.git (onetime), https://github.com/sindresorhus/open.git (open), https://github.com/sindresorhus/ora.git (ora), https://github.com/sindresorhus/p-cancelable.git (p-cancelable), https://github.com/sindresorhus/p-each-series.git (p-each-series), https://github.com/sindresorhus/p-limit.git (p-limit), https://github.com/sindresorhus/p-locate.git (p-locate), https://github.com/sindresorhus/p-map.git (p-map), https://github.com/sindresorhus/p-pipe.git (p-pipe), https://github.com/sindresorhus/p-queue.git (p-queue), https://github.com/sindresorhus/p-waterfall.git (p-waterfall), https://github.com/sindresorhus/package-json.git (package-json), https://github.com/sindresorhus/parse-json.git (parse-json), https://github.com/sindresorhus/path-key.git (path-key), https://github.com/sindresorhus/pify.git (pify), https://github.com/sindresorhus/pupa.git (pupa), https://github.com/sindresorhus/registry-url.git (registry-url), https://github.com/sindresorhus/restore-cursor.git (restore-cursor), https://github.com/sindresorhus/semver-diff.git (semver-diff), https://github.com/sindresorhus/sort-keys.git (sort-keys), https://github.com/sindresorhus/string-length.git (string-length), https://github.com/sindresorhus/string-width.git (string-width), https://github.com/chalk/strip-ansi.git (strip-ansi), https://github.com/sindresorhus/strip-final-newline.git (strip-final-newline), https://github.com/sindresorhus/strip-json-comments.git (strip-json-comments), https://github.com/sindresorhus/type-fest.git (type-fest), https://github.com/sindresorhus/unique-string.git (unique-string), https://github.com/sindresorhus/widest-line.git (widest-line), https://github.com/chalk/wrap-ansi.git (wrap-ansi), https://github.com/chalk/wrap-ansi.git (wrap-ansi-cjs), https://github.com/sindresorhus/xdg-basedir.git (xdg-basedir), https://github.com/sindresorhus/yocto-queue.git (yocto-queue). This software contains the following license and notice below: MIT License @@ -5271,57 +5207,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ----- -The following software may be included in this product: @size-limit/file, @size-limit/preset-small-lib, @size-limit/webpack, ci-job-number, nanoid, size-limit. A copy of the source code may be downloaded from https://github.com/ai/size-limit.git (@size-limit/file), https://github.com/ai/size-limit.git (@size-limit/preset-small-lib), https://github.com/ai/size-limit.git (@size-limit/webpack), https://github.com/ai/ci-job-number.git (ci-job-number), https://github.com/ai/nanoid.git (nanoid), https://github.com/ai/size-limit.git (size-limit). This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright 2017 Andrey Sitnik - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - -The following software may be included in this product: @statoscope/extensions, @statoscope/helpers, @statoscope/report-writer, @statoscope/stats, @statoscope/stats-extension-compressed, @statoscope/stats-extension-custom-reports, @statoscope/stats-extension-package-info, @statoscope/stats-extension-stats-validation-result, @statoscope/types, @statoscope/webpack-model, @statoscope/webpack-plugin, @statoscope/webpack-stats-extension-compressed, @statoscope/webpack-stats-extension-package-info, @statoscope/webpack-ui. A copy of the source code may be downloaded from https://github.com/statoscope/statoscope.git (@statoscope/extensions), https://github.com/statoscope/statoscope.git (@statoscope/helpers), https://github.com/statoscope/statoscope.git (@statoscope/report-writer), https://github.com/statoscope/statoscope/ (@statoscope/stats), https://github.com/statoscope/statoscope.git (@statoscope/stats-extension-compressed), https://github.com/statoscope/statoscope.git (@statoscope/stats-extension-custom-reports), https://github.com/statoscope/statoscope.git (@statoscope/stats-extension-package-info), https://github.com/statoscope/statoscope.git (@statoscope/stats-extension-stats-validation-result), https://github.com/statoscope/statoscope/ (@statoscope/types), https://github.com/statoscope/statoscope.git (@statoscope/webpack-model), https://github.com/statoscope/statoscope.git (@statoscope/webpack-plugin), https://github.com/statoscope/statoscope.git (@statoscope/webpack-stats-extension-compressed), https://github.com/statoscope/statoscope.git (@statoscope/webpack-stats-extension-package-info), https://github.com/statoscope/statoscope.git (@statoscope/webpack-ui). This software contains the following license and notice below: - -MIT License - -Copyright (c) 2020 Sergey Melyukov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: @szmarczak/http-timer, defer-to-connect, http2-wrapper. A copy of the source code may be downloaded from git+https://github.com/szmarczak/http-timer.git (@szmarczak/http-timer), git+https://github.com/szmarczak/defer-to-connect.git (defer-to-connect), git+https://github.com/szmarczak/http2-wrapper.git (http2-wrapper). This software contains the following license and notice below: MIT License @@ -5400,26 +5285,6 @@ SOFTWARE. ----- -The following software may be included in this product: @trysound/sax, chownr, color-support, dezalgo, fs-minipass, ignore-walk, ini, isexe, json-stringify-nice, json-stringify-safe, lru-cache, minimatch, minipass-collect, minipass-flush, minipass-pipeline, minipass-sized, mute-stream, nopt, npm-packlist, once, proto-list, read, readdir-scoped-modules, rimraf, semver, tar, which, wrappy, yallist. A copy of the source code may be downloaded from git://github.com/svg/sax.git (@trysound/sax), git://github.com/isaacs/chownr.git (chownr), git+https://github.com/isaacs/color-support.git (color-support), https://github.com/npm/dezalgo (dezalgo), https://github.com/npm/fs-minipass.git (fs-minipass), git+https://github.com/isaacs/ignore-walk.git (ignore-walk), https://github.com/npm/ini.git (ini), git+https://github.com/isaacs/isexe.git (isexe), https://github.com/isaacs/json-stringify-nice (json-stringify-nice), git://github.com/isaacs/json-stringify-safe (json-stringify-safe), git://github.com/isaacs/node-lru-cache.git (lru-cache), git://github.com/isaacs/minimatch.git (minimatch), git+https://github.com/isaacs/minipass-flush.git (minipass-flush), git+https://github.com/isaacs/minipass-sized.git (minipass-sized), git://github.com/isaacs/mute-stream (mute-stream), https://github.com/npm/nopt.git (nopt), https://github.com/npm/npm-packlist.git (npm-packlist), git://github.com/isaacs/once (once), https://github.com/isaacs/proto-list (proto-list), git://github.com/isaacs/read.git (read), https://github.com/npm/readdir-scoped-modules (readdir-scoped-modules), git://github.com/isaacs/rimraf.git (rimraf), https://github.com/npm/node-semver.git (semver), https://github.com/isaacs/node-tar.git (tar), https://github.com/npm/node-which.git (which), https://github.com/npm/wrappy (wrappy), git+https://github.com/isaacs/yallist.git (yallist). This software contains the following license and notice below: - -The ISC License - -Copyright (c) Isaac Z. Schlueter and Contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ------ - The following software may be included in this product: @tsconfig/node10, @tsconfig/node12, @tsconfig/node14, @tsconfig/node16. A copy of the source code may be downloaded from https://github.com/tsconfig/bases.git (@tsconfig/node10), https://github.com/tsconfig/bases.git (@tsconfig/node12), https://github.com/tsconfig/bases.git (@tsconfig/node14), https://github.com/tsconfig/bases.git (@tsconfig/node16). This software contains the following license and notice below: MIT License @@ -5497,11 +5362,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: @types/archy, @types/aws-lambda, @types/babel__core, @types/babel__generator, @types/babel__template, @types/babel__traverse, @types/eslint, @types/eslint-scope, @types/estree, @types/fs-extra, @types/glob, @types/graceful-fs, @types/hjson, @types/http-cache-semantics, @types/ini, @types/istanbul-lib-coverage, @types/istanbul-lib-report, @types/istanbul-reports, @types/jest, @types/js-yaml, @types/json-schema, @types/lodash, @types/md5, @types/minimatch, @types/minimist, @types/mock-fs, @types/node, @types/normalize-package-data, @types/object-hash, @types/pako, @types/prettier, @types/semver, @types/stack-utils, @types/triple-beam, @types/uuid, @types/ws, @types/yargs, @types/yargs-parser, @types/zen-observable. A copy of the source code may be downloaded from https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/archy), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/aws-lambda), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/babel__core), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/babel__generator), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/babel__template), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/babel__traverse), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/eslint), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/eslint-scope), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/estree), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/fs-extra), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/glob), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/graceful-fs), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/hjson), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/http-cache-semantics), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/ini), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/istanbul-lib-coverage), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/istanbul-lib-report), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/istanbul-reports), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/jest), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/js-yaml), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/json-schema), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/lodash), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/md5), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/minimatch), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/minimist), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/mock-fs), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/node), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/normalize-package-data), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/object-hash), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/pako), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/prettier), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/semver), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/stack-utils), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/triple-beam), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/uuid), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/ws), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/yargs), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/yargs-parser), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/zen-observable). This software contains the following license and notice below: +The following software may be included in this product: @types/argparse, @types/async, @types/cookie, @types/parse-json, @types/pluralize, @types/zen-observable. A copy of the source code may be downloaded from https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/argparse), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/async), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/cookie), https://www.github.com/DefinitelyTyped/DefinitelyTyped.git (@types/parse-json), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/pluralize), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/zen-observable). This software contains the following license and notice below: MIT License - Copyright (c) Microsoft Corporation. + Copyright (c) Microsoft Corporation. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -5523,11 +5388,11 @@ MIT License ----- -The following software may be included in this product: @types/argparse, @types/async, @types/cookie, @types/jest, @types/parse-json, @types/pluralize, @types/zen-observable. A copy of the source code may be downloaded from https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/argparse), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/async), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/cookie), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/jest), https://www.github.com/DefinitelyTyped/DefinitelyTyped.git (@types/parse-json), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/pluralize), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/zen-observable). This software contains the following license and notice below: +The following software may be included in this product: @types/aws-lambda, @types/babel__core, @types/babel__generator, @types/babel__template, @types/babel__traverse, @types/fs-extra, @types/glob, @types/graceful-fs, @types/hjson, @types/http-cache-semantics, @types/ini, @types/istanbul-lib-coverage, @types/istanbul-lib-report, @types/istanbul-reports, @types/jest, @types/js-yaml, @types/json-schema, @types/lodash, @types/md5, @types/minimatch, @types/minimist, @types/mock-fs, @types/node, @types/normalize-package-data, @types/object-hash, @types/prettier, @types/semver, @types/stack-utils, @types/triple-beam, @types/uuid, @types/ws, @types/yargs, @types/yargs-parser, @types/zen-observable. A copy of the source code may be downloaded from https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/aws-lambda), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/babel__core), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/babel__generator), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/babel__template), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/babel__traverse), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/fs-extra), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/glob), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/graceful-fs), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/hjson), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/http-cache-semantics), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/ini), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/istanbul-lib-coverage), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/istanbul-lib-report), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/istanbul-reports), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/jest), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/js-yaml), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/json-schema), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/lodash), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/md5), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/minimatch), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/minimist), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/mock-fs), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/node), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/normalize-package-data), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/object-hash), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/prettier), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/semver), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/stack-utils), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/triple-beam), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/uuid), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/ws), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/yargs), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/yargs-parser), https://github.com/DefinitelyTyped/DefinitelyTyped.git (@types/zen-observable). This software contains the following license and notice below: MIT License - Copyright (c) Microsoft Corporation. All rights reserved. + Copyright (c) Microsoft Corporation. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -5659,231 +5524,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----- -The following software may be included in this product: @webassemblyjs/floating-point-hex-parser. A copy of the source code may be downloaded from https://github.com/xtuc/webassemblyjs.git. This software contains the following license and notice below: - -MIT License - -Copyright (c) 2017 Mauro Bringolf - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: @webassemblyjs/leb128. A copy of the source code may be downloaded from https://github.com/xtuc/webassemblyjs.git. This software contains the following license and notice below: - -Copyright 2012 The Obvious Corporation. -http://obvious.com/ - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - - -------------------------------------------------------------------------- - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - ------ - The following software may be included in this product: @wry/equality. A copy of the source code may be downloaded from git+https://github.com/benjamn/wryware.git. This software contains the following license and notice below: MIT License @@ -5923,39 +5563,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI ----- -The following software may be included in this product: @xtuc/ieee754. A copy of the source code may be downloaded from git://github.com/feross/ieee754.git. This software contains the following license and notice below: - -Copyright (c) 2008, Fair Oaks Labs, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of Fair Oaks Labs, Inc. nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - ------ - The following software may be included in this product: @zkochan/cmd-shim. A copy of the source code may be downloaded from https://github.com/pnpm/cmd-shim.git. This software contains the following license and notice below: Copyright (c) Isaac Z. Schlueter ("Author") @@ -6163,7 +5770,7 @@ THE SOFTWARE. ----- -The following software may be included in this product: acorn-globals, is-promise. A copy of the source code may be downloaded from https://github.com/ForbesLindesay/acorn-globals.git (acorn-globals), https://github.com/then/is-promise.git (is-promise). This software contains the following license and notice below: +The following software may be included in this product: acorn-globals. A copy of the source code may be downloaded from https://github.com/ForbesLindesay/acorn-globals.git. This software contains the following license and notice below: Copyright (c) 2014 Forbes Lindesay @@ -6289,7 +5896,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: aggregate-error, ansi-escapes, ansi-regex, ansi-styles, any-observable, array-differ, array-union, arrify, callsites, camelcase, camelcase-keys, chalk, clean-stack, cli-cursor, dargs, decamelize, define-lazy-prop, del, detect-indent, detect-newline, dot-prop, env-paths, escape-string-regexp, execa, find-up, get-port, get-stdin, get-stream, global-dirs, globals, globby, got, hard-rejection, has-flag, import-lazy, import-local, indent-string, is-fullwidth-code-point, is-generator-fn, is-interactive, is-obj, is-observable, is-path-cwd, is-path-inside, is-plain-obj, is-wsl, leven, load-json-file, locate-path, log-symbols, log-update, make-dir, mimic-fn, normalize-url, npm-run-path, p-finally, p-is-promise, p-limit, p-locate, p-map, p-map-series, p-reduce, p-timeout, p-try, parent-module, parse-json, path-exists, path-key, path-type, pify, pkg-dir, quick-lru, read-pkg, read-pkg-up, redent, remote-git-tags, resolve-cwd, resolve-from, resolve-global, resolve-pkg, restore-cursor, run-node, shebang-regex, slash, sort-keys, string-width, string-width-cjs, strip-ansi, strip-ansi-cjs, strip-bom, strip-final-newline, strip-indent, supports-color, terminal-link, text-extensions, tildify, trim-newlines, type-fest, untildify, wrap-ansi, write-json-file, write-pkg, yn. A copy of the source code may be downloaded from https://github.com/sindresorhus/aggregate-error.git (aggregate-error), https://github.com/sindresorhus/ansi-escapes.git (ansi-escapes), https://github.com/chalk/ansi-regex.git (ansi-regex), https://github.com/chalk/ansi-styles.git (ansi-styles), https://github.com/sindresorhus/any-observable.git (any-observable), https://github.com/sindresorhus/array-differ.git (array-differ), https://github.com/sindresorhus/array-union.git (array-union), https://github.com/sindresorhus/arrify.git (arrify), https://github.com/sindresorhus/callsites.git (callsites), https://github.com/sindresorhus/camelcase.git (camelcase), https://github.com/sindresorhus/camelcase-keys.git (camelcase-keys), https://github.com/chalk/chalk.git (chalk), https://github.com/sindresorhus/clean-stack.git (clean-stack), https://github.com/sindresorhus/cli-cursor.git (cli-cursor), https://github.com/sindresorhus/dargs.git (dargs), https://github.com/sindresorhus/decamelize.git (decamelize), https://github.com/sindresorhus/define-lazy-prop.git (define-lazy-prop), https://github.com/sindresorhus/del.git (del), https://github.com/sindresorhus/detect-indent.git (detect-indent), https://github.com/sindresorhus/detect-newline.git (detect-newline), https://github.com/sindresorhus/dot-prop.git (dot-prop), https://github.com/sindresorhus/env-paths.git (env-paths), https://github.com/sindresorhus/escape-string-regexp.git (escape-string-regexp), https://github.com/sindresorhus/execa.git (execa), https://github.com/sindresorhus/find-up.git (find-up), https://github.com/sindresorhus/get-port.git (get-port), https://github.com/sindresorhus/get-stdin.git (get-stdin), https://github.com/sindresorhus/get-stream.git (get-stream), https://github.com/sindresorhus/global-dirs.git (global-dirs), https://github.com/sindresorhus/globals.git (globals), https://github.com/sindresorhus/globby.git (globby), https://github.com/sindresorhus/got.git (got), https://github.com/sindresorhus/hard-rejection.git (hard-rejection), https://github.com/sindresorhus/has-flag.git (has-flag), https://github.com/sindresorhus/import-lazy.git (import-lazy), https://github.com/sindresorhus/import-local.git (import-local), https://github.com/sindresorhus/indent-string.git (indent-string), https://github.com/sindresorhus/is-fullwidth-code-point.git (is-fullwidth-code-point), https://github.com/sindresorhus/is-generator-fn.git (is-generator-fn), https://github.com/sindresorhus/is-interactive.git (is-interactive), https://github.com/sindresorhus/is-obj.git (is-obj), https://github.com/sindresorhus/is-observable.git (is-observable), https://github.com/sindresorhus/is-path-cwd.git (is-path-cwd), https://github.com/sindresorhus/is-path-inside.git (is-path-inside), https://github.com/sindresorhus/is-plain-obj.git (is-plain-obj), https://github.com/sindresorhus/is-wsl.git (is-wsl), https://github.com/sindresorhus/leven.git (leven), https://github.com/sindresorhus/load-json-file.git (load-json-file), https://github.com/sindresorhus/locate-path.git (locate-path), https://github.com/sindresorhus/log-symbols.git (log-symbols), https://github.com/sindresorhus/log-update.git (log-update), https://github.com/sindresorhus/make-dir.git (make-dir), https://github.com/sindresorhus/mimic-fn.git (mimic-fn), https://github.com/sindresorhus/normalize-url.git (normalize-url), https://github.com/sindresorhus/npm-run-path.git (npm-run-path), https://github.com/sindresorhus/p-finally.git (p-finally), https://github.com/sindresorhus/p-is-promise.git (p-is-promise), https://github.com/sindresorhus/p-limit.git (p-limit), https://github.com/sindresorhus/p-locate.git (p-locate), https://github.com/sindresorhus/p-map.git (p-map), https://github.com/sindresorhus/p-map-series.git (p-map-series), https://github.com/sindresorhus/p-reduce.git (p-reduce), https://github.com/sindresorhus/p-timeout.git (p-timeout), https://github.com/sindresorhus/p-try.git (p-try), https://github.com/sindresorhus/parent-module.git (parent-module), https://github.com/sindresorhus/parse-json.git (parse-json), https://github.com/sindresorhus/path-exists.git (path-exists), https://github.com/sindresorhus/path-key.git (path-key), https://github.com/sindresorhus/path-type.git (path-type), https://github.com/sindresorhus/pify.git (pify), https://github.com/sindresorhus/pkg-dir.git (pkg-dir), https://github.com/sindresorhus/quick-lru.git (quick-lru), https://github.com/sindresorhus/read-pkg.git (read-pkg), https://github.com/sindresorhus/read-pkg-up.git (read-pkg-up), https://github.com/sindresorhus/redent.git (redent), https://github.com/sindresorhus/remote-git-tags.git (remote-git-tags), https://github.com/sindresorhus/resolve-cwd.git (resolve-cwd), https://github.com/sindresorhus/resolve-from.git (resolve-from), https://github.com/sindresorhus/resolve-global.git (resolve-global), https://github.com/sindresorhus/resolve-pkg.git (resolve-pkg), https://github.com/sindresorhus/restore-cursor.git (restore-cursor), https://github.com/sindresorhus/run-node.git (run-node), https://github.com/sindresorhus/shebang-regex.git (shebang-regex), https://github.com/sindresorhus/slash.git (slash), https://github.com/sindresorhus/sort-keys.git (sort-keys), https://github.com/sindresorhus/string-width.git (string-width), https://github.com/sindresorhus/string-width.git (string-width-cjs), https://github.com/chalk/strip-ansi.git (strip-ansi), https://github.com/chalk/strip-ansi.git (strip-ansi-cjs), https://github.com/sindresorhus/strip-bom.git (strip-bom), https://github.com/sindresorhus/strip-final-newline.git (strip-final-newline), https://github.com/sindresorhus/strip-indent.git (strip-indent), https://github.com/chalk/supports-color.git (supports-color), https://github.com/sindresorhus/terminal-link.git (terminal-link), https://github.com/sindresorhus/text-extensions.git (text-extensions), https://github.com/sindresorhus/tildify.git (tildify), https://github.com/sindresorhus/trim-newlines.git (trim-newlines), https://github.com/sindresorhus/type-fest.git (type-fest), https://github.com/sindresorhus/untildify.git (untildify), https://github.com/chalk/wrap-ansi.git (wrap-ansi), https://github.com/sindresorhus/write-json-file.git (write-json-file), https://github.com/sindresorhus/write-pkg.git (write-pkg), https://github.com/sindresorhus/yn.git (yn). This software contains the following license and notice below: +The following software may be included in this product: aggregate-error, ansi-escapes, ansi-regex, ansi-styles, array-differ, array-union, arrify, callsites, camelcase, camelcase-keys, chalk, clean-stack, cli-cursor, dargs, decamelize, define-lazy-prop, detect-indent, detect-newline, dot-prop, env-paths, escape-string-regexp, execa, find-up, get-port, get-stdin, get-stream, global-dirs, globals, globby, got, hard-rejection, has-flag, import-lazy, import-local, indent-string, is-fullwidth-code-point, is-generator-fn, is-interactive, is-obj, is-path-inside, is-plain-obj, is-wsl, leven, load-json-file, locate-path, log-symbols, make-dir, mimic-fn, npm-run-path, p-is-promise, p-limit, p-locate, p-map-series, p-reduce, p-timeout, p-try, parent-module, parse-json, path-exists, path-key, path-type, pify, pkg-dir, quick-lru, read-pkg, read-pkg-up, redent, remote-git-tags, resolve-cwd, resolve-from, resolve-global, resolve-pkg, restore-cursor, run-node, shebang-regex, slash, sort-keys, string-width, string-width-cjs, strip-ansi, strip-ansi-cjs, strip-bom, strip-final-newline, strip-indent, supports-color, terminal-link, text-extensions, tildify, trim-newlines, type-fest, untildify, wrap-ansi, write-json-file, write-pkg, yn. A copy of the source code may be downloaded from https://github.com/sindresorhus/aggregate-error.git (aggregate-error), https://github.com/sindresorhus/ansi-escapes.git (ansi-escapes), https://github.com/chalk/ansi-regex.git (ansi-regex), https://github.com/chalk/ansi-styles.git (ansi-styles), https://github.com/sindresorhus/array-differ.git (array-differ), https://github.com/sindresorhus/array-union.git (array-union), https://github.com/sindresorhus/arrify.git (arrify), https://github.com/sindresorhus/callsites.git (callsites), https://github.com/sindresorhus/camelcase.git (camelcase), https://github.com/sindresorhus/camelcase-keys.git (camelcase-keys), https://github.com/chalk/chalk.git (chalk), https://github.com/sindresorhus/clean-stack.git (clean-stack), https://github.com/sindresorhus/cli-cursor.git (cli-cursor), https://github.com/sindresorhus/dargs.git (dargs), https://github.com/sindresorhus/decamelize.git (decamelize), https://github.com/sindresorhus/define-lazy-prop.git (define-lazy-prop), https://github.com/sindresorhus/detect-indent.git (detect-indent), https://github.com/sindresorhus/detect-newline.git (detect-newline), https://github.com/sindresorhus/dot-prop.git (dot-prop), https://github.com/sindresorhus/env-paths.git (env-paths), https://github.com/sindresorhus/escape-string-regexp.git (escape-string-regexp), https://github.com/sindresorhus/execa.git (execa), https://github.com/sindresorhus/find-up.git (find-up), https://github.com/sindresorhus/get-port.git (get-port), https://github.com/sindresorhus/get-stdin.git (get-stdin), https://github.com/sindresorhus/get-stream.git (get-stream), https://github.com/sindresorhus/global-dirs.git (global-dirs), https://github.com/sindresorhus/globals.git (globals), https://github.com/sindresorhus/globby.git (globby), https://github.com/sindresorhus/got.git (got), https://github.com/sindresorhus/hard-rejection.git (hard-rejection), https://github.com/sindresorhus/has-flag.git (has-flag), https://github.com/sindresorhus/import-lazy.git (import-lazy), https://github.com/sindresorhus/import-local.git (import-local), https://github.com/sindresorhus/indent-string.git (indent-string), https://github.com/sindresorhus/is-fullwidth-code-point.git (is-fullwidth-code-point), https://github.com/sindresorhus/is-generator-fn.git (is-generator-fn), https://github.com/sindresorhus/is-interactive.git (is-interactive), https://github.com/sindresorhus/is-obj.git (is-obj), https://github.com/sindresorhus/is-path-inside.git (is-path-inside), https://github.com/sindresorhus/is-plain-obj.git (is-plain-obj), https://github.com/sindresorhus/is-wsl.git (is-wsl), https://github.com/sindresorhus/leven.git (leven), https://github.com/sindresorhus/load-json-file.git (load-json-file), https://github.com/sindresorhus/locate-path.git (locate-path), https://github.com/sindresorhus/log-symbols.git (log-symbols), https://github.com/sindresorhus/make-dir.git (make-dir), https://github.com/sindresorhus/mimic-fn.git (mimic-fn), https://github.com/sindresorhus/npm-run-path.git (npm-run-path), https://github.com/sindresorhus/p-is-promise.git (p-is-promise), https://github.com/sindresorhus/p-limit.git (p-limit), https://github.com/sindresorhus/p-locate.git (p-locate), https://github.com/sindresorhus/p-map-series.git (p-map-series), https://github.com/sindresorhus/p-reduce.git (p-reduce), https://github.com/sindresorhus/p-timeout.git (p-timeout), https://github.com/sindresorhus/p-try.git (p-try), https://github.com/sindresorhus/parent-module.git (parent-module), https://github.com/sindresorhus/parse-json.git (parse-json), https://github.com/sindresorhus/path-exists.git (path-exists), https://github.com/sindresorhus/path-key.git (path-key), https://github.com/sindresorhus/path-type.git (path-type), https://github.com/sindresorhus/pify.git (pify), https://github.com/sindresorhus/pkg-dir.git (pkg-dir), https://github.com/sindresorhus/quick-lru.git (quick-lru), https://github.com/sindresorhus/read-pkg.git (read-pkg), https://github.com/sindresorhus/read-pkg-up.git (read-pkg-up), https://github.com/sindresorhus/redent.git (redent), https://github.com/sindresorhus/remote-git-tags.git (remote-git-tags), https://github.com/sindresorhus/resolve-cwd.git (resolve-cwd), https://github.com/sindresorhus/resolve-from.git (resolve-from), https://github.com/sindresorhus/resolve-global.git (resolve-global), https://github.com/sindresorhus/resolve-pkg.git (resolve-pkg), https://github.com/sindresorhus/restore-cursor.git (restore-cursor), https://github.com/sindresorhus/run-node.git (run-node), https://github.com/sindresorhus/shebang-regex.git (shebang-regex), https://github.com/sindresorhus/slash.git (slash), https://github.com/sindresorhus/sort-keys.git (sort-keys), https://github.com/sindresorhus/string-width.git (string-width), https://github.com/sindresorhus/string-width.git (string-width-cjs), https://github.com/chalk/strip-ansi.git (strip-ansi), https://github.com/chalk/strip-ansi.git (strip-ansi-cjs), https://github.com/sindresorhus/strip-bom.git (strip-bom), https://github.com/sindresorhus/strip-final-newline.git (strip-final-newline), https://github.com/sindresorhus/strip-indent.git (strip-indent), https://github.com/chalk/supports-color.git (supports-color), https://github.com/sindresorhus/terminal-link.git (terminal-link), https://github.com/sindresorhus/text-extensions.git (text-extensions), https://github.com/sindresorhus/tildify.git (tildify), https://github.com/sindresorhus/trim-newlines.git (trim-newlines), https://github.com/sindresorhus/type-fest.git (type-fest), https://github.com/sindresorhus/untildify.git (untildify), https://github.com/chalk/wrap-ansi.git (wrap-ansi), https://github.com/sindresorhus/write-json-file.git (write-json-file), https://github.com/sindresorhus/write-pkg.git (write-pkg), https://github.com/sindresorhus/yn.git (yn). This software contains the following license and notice below: MIT License @@ -6355,32 +5962,6 @@ SOFTWARE. ----- -The following software may be included in this product: ajv-formats. A copy of the source code may be downloaded from git+https://github.com/ajv-validator/ajv-formats.git. This software contains the following license and notice below: - -MIT License - -Copyright (c) 2020 Evgeny Poberezkin - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: ajv-keywords. A copy of the source code may be downloaded from git+https://github.com/epoberezkin/ajv-keywords.git. This software contains the following license and notice below: The MIT License (MIT) @@ -6621,32 +6202,6 @@ THE SOFTWARE. ----- -The following software may be included in this product: ansi-regex, ansi-styles, arrify, caller-callsite, caller-path, callsites, chalk, cli-cursor, cli-truncate, code-point-at, decamelize, detect-indent, detect-newline, elegant-spinner, escape-string-regexp, figures, find-up, git-remote-origin-url, has-ansi, import-fresh, is-fullwidth-code-point, is-obj, is-plain-obj, is-stream, is-text-path, load-json-file, locate-path, log-symbols, map-obj, modify-values, npm-run-path, number-is-nan, object-assign, onetime, os-tmpdir, p-finally, p-locate, p-try, path-exists, path-is-absolute, path-key, pify, resolve-from, restore-cursor, shebang-regex, string-width, strip-ansi, strip-bom, strip-eof, strip-json-comments, supports-color, temp-dir. A copy of the source code may be downloaded from https://github.com/chalk/ansi-regex.git (ansi-regex), https://github.com/chalk/ansi-styles.git (ansi-styles), https://github.com/sindresorhus/arrify.git (arrify), https://github.com/sindresorhus/caller-callsite.git (caller-callsite), https://github.com/sindresorhus/caller-path.git (caller-path), https://github.com/sindresorhus/callsites.git (callsites), https://github.com/chalk/chalk.git (chalk), https://github.com/sindresorhus/cli-cursor.git (cli-cursor), https://github.com/sindresorhus/cli-truncate.git (cli-truncate), https://github.com/sindresorhus/code-point-at.git (code-point-at), https://github.com/sindresorhus/decamelize.git (decamelize), https://github.com/sindresorhus/detect-indent.git (detect-indent), https://github.com/sindresorhus/detect-newline.git (detect-newline), https://github.com/sindresorhus/elegant-spinner.git (elegant-spinner), https://github.com/sindresorhus/escape-string-regexp.git (escape-string-regexp), https://github.com/sindresorhus/figures.git (figures), https://github.com/sindresorhus/find-up.git (find-up), https://github.com/sindresorhus/git-remote-origin-url.git (git-remote-origin-url), https://github.com/sindresorhus/has-ansi.git (has-ansi), https://github.com/sindresorhus/import-fresh.git (import-fresh), https://github.com/sindresorhus/is-fullwidth-code-point.git (is-fullwidth-code-point), https://github.com/sindresorhus/is-obj.git (is-obj), https://github.com/sindresorhus/is-plain-obj.git (is-plain-obj), https://github.com/sindresorhus/is-stream.git (is-stream), https://github.com/sindresorhus/is-text-path.git (is-text-path), https://github.com/sindresorhus/load-json-file.git (load-json-file), https://github.com/sindresorhus/locate-path.git (locate-path), https://github.com/sindresorhus/log-symbols.git (log-symbols), https://github.com/sindresorhus/map-obj.git (map-obj), https://github.com/sindresorhus/modify-values.git (modify-values), https://github.com/sindresorhus/npm-run-path.git (npm-run-path), https://github.com/sindresorhus/number-is-nan.git (number-is-nan), https://github.com/sindresorhus/object-assign.git (object-assign), https://github.com/sindresorhus/onetime.git (onetime), https://github.com/sindresorhus/os-tmpdir.git (os-tmpdir), https://github.com/sindresorhus/p-finally.git (p-finally), https://github.com/sindresorhus/p-locate.git (p-locate), https://github.com/sindresorhus/p-try.git (p-try), https://github.com/sindresorhus/path-exists.git (path-exists), https://github.com/sindresorhus/path-is-absolute.git (path-is-absolute), https://github.com/sindresorhus/path-key.git (path-key), https://github.com/sindresorhus/pify.git (pify), https://github.com/sindresorhus/resolve-from.git (resolve-from), https://github.com/sindresorhus/restore-cursor.git (restore-cursor), https://github.com/sindresorhus/shebang-regex.git (shebang-regex), https://github.com/sindresorhus/string-width.git (string-width), https://github.com/chalk/strip-ansi.git (strip-ansi), https://github.com/sindresorhus/strip-bom.git (strip-bom), https://github.com/sindresorhus/strip-eof.git (strip-eof), https://github.com/sindresorhus/strip-json-comments.git (strip-json-comments), https://github.com/chalk/supports-color.git (supports-color), https://github.com/sindresorhus/temp-dir.git (temp-dir). This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) Sindre Sorhus (sindresorhus.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - The following software may be included in this product: anymatch. A copy of the source code may be downloaded from https://github.com/micromatch/anymatch. This software contains the following license and notice below: The ISC License @@ -6811,29 +6366,6 @@ OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: archy, concat-map, github-from-package, is-typedarray, json-stable-stringify-without-jsonify, minimist, safe-regex, semver-compare, text-table, wordwrap. A copy of the source code may be downloaded from http://github.com/substack/node-archy.git (archy), git://github.com/substack/node-concat-map.git (concat-map), git://github.com/substack/github-from-package.git (github-from-package), git://github.com/hughsk/is-typedarray.git (is-typedarray), git://github.com/samn/json-stable-stringify.git (json-stable-stringify-without-jsonify), git://github.com/minimistjs/minimist.git (minimist), git://github.com/substack/safe-regex.git (safe-regex), git://github.com/substack/semver-compare.git (semver-compare), git://github.com/substack/text-table.git (text-table), git://github.com/substack/node-wordwrap.git (wordwrap). This software contains the following license and notice below: - -This software is released under the MIT license: - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: are-we-there-yet, init-package-json. A copy of the source code may be downloaded from https://github.com/npm/are-we-there-yet.git (are-we-there-yet), https://github.com/npm/init-package-json.git (init-package-json). This software contains the following license and notice below: ISC License @@ -7608,6 +7140,32 @@ SOFTWARE. ----- +The following software may be included in this product: arrify, caller-callsite, caller-path, callsites, cli-cursor, decamelize, detect-indent, detect-newline, escape-string-regexp, figures, find-up, git-remote-origin-url, import-fresh, is-fullwidth-code-point, is-plain-obj, is-stream, is-text-path, load-json-file, locate-path, map-obj, modify-values, npm-run-path, object-assign, onetime, os-tmpdir, p-finally, p-locate, p-try, path-exists, path-is-absolute, path-key, pify, resolve-from, restore-cursor, shebang-regex, strip-bom, strip-eof, strip-json-comments, temp-dir. A copy of the source code may be downloaded from https://github.com/sindresorhus/arrify.git (arrify), https://github.com/sindresorhus/caller-callsite.git (caller-callsite), https://github.com/sindresorhus/caller-path.git (caller-path), https://github.com/sindresorhus/callsites.git (callsites), https://github.com/sindresorhus/cli-cursor.git (cli-cursor), https://github.com/sindresorhus/decamelize.git (decamelize), https://github.com/sindresorhus/detect-indent.git (detect-indent), https://github.com/sindresorhus/detect-newline.git (detect-newline), https://github.com/sindresorhus/escape-string-regexp.git (escape-string-regexp), https://github.com/sindresorhus/figures.git (figures), https://github.com/sindresorhus/find-up.git (find-up), https://github.com/sindresorhus/git-remote-origin-url.git (git-remote-origin-url), https://github.com/sindresorhus/import-fresh.git (import-fresh), https://github.com/sindresorhus/is-fullwidth-code-point.git (is-fullwidth-code-point), https://github.com/sindresorhus/is-plain-obj.git (is-plain-obj), https://github.com/sindresorhus/is-stream.git (is-stream), https://github.com/sindresorhus/is-text-path.git (is-text-path), https://github.com/sindresorhus/load-json-file.git (load-json-file), https://github.com/sindresorhus/locate-path.git (locate-path), https://github.com/sindresorhus/map-obj.git (map-obj), https://github.com/sindresorhus/modify-values.git (modify-values), https://github.com/sindresorhus/npm-run-path.git (npm-run-path), https://github.com/sindresorhus/object-assign.git (object-assign), https://github.com/sindresorhus/onetime.git (onetime), https://github.com/sindresorhus/os-tmpdir.git (os-tmpdir), https://github.com/sindresorhus/p-finally.git (p-finally), https://github.com/sindresorhus/p-locate.git (p-locate), https://github.com/sindresorhus/p-try.git (p-try), https://github.com/sindresorhus/path-exists.git (path-exists), https://github.com/sindresorhus/path-is-absolute.git (path-is-absolute), https://github.com/sindresorhus/path-key.git (path-key), https://github.com/sindresorhus/pify.git (pify), https://github.com/sindresorhus/resolve-from.git (resolve-from), https://github.com/sindresorhus/restore-cursor.git (restore-cursor), https://github.com/sindresorhus/shebang-regex.git (shebang-regex), https://github.com/sindresorhus/strip-bom.git (strip-bom), https://github.com/sindresorhus/strip-eof.git (strip-eof), https://github.com/sindresorhus/strip-json-comments.git (strip-json-comments), https://github.com/sindresorhus/temp-dir.git (temp-dir). This software contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +----- + The following software may be included in this product: asap. A copy of the source code may be downloaded from https://github.com/kriskowal/asap.git. This software contains the following license and notice below: Copyright 2009–2014 Contributors. All rights reserved. @@ -10857,54 +10415,25 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: bytes. A copy of the source code may be downloaded from https://github.com/visionmedia/bytes.js.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2012-2014 TJ Holowaychuk -Copyright (c) 2015 Jed Watson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. ----- -The following software may be included in this product: bytes-iec. A copy of the source code may be downloaded from https://github.com/Saevon/bytes.js.git. This software contains the following license and notice below: +The following software may be included in this product: bytes. A copy of the source code may be downloaded from https://github.com/visionmedia/bytes.js.git. This software contains the following license and notice below: (The MIT License) Copyright (c) 2012-2014 TJ Holowaychuk Copyright (c) 2015 Jed Watson -Copyright (c) 2018 Saevon Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -11026,32 +10555,6 @@ SOFTWARE. ----- -The following software may be included in this product: caniuse-api. A copy of the source code may be downloaded from https://github.com/nyalab/caniuse-api.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2014 Sébastien Balayn - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: caniuse-lite. A copy of the source code may be downloaded from https://github.com/browserslist/caniuse-lite.git. This software contains the following license and notice below: Attribution 4.0 International @@ -11587,30 +11090,23 @@ THE SOFTWARE. ----- -The following software may be included in this product: chrome-trace-event. A copy of the source code may be downloaded from https://github.com/samccone/chrome-trace-event.git. This software contains the following license and notice below: - -# This is the MIT license +The following software may be included in this product: chownr, color-support, dezalgo, fs-minipass, ignore-walk, ini, isexe, json-stringify-nice, json-stringify-safe, lru-cache, minimatch, minipass-collect, minipass-flush, minipass-pipeline, minipass-sized, mute-stream, nopt, npm-packlist, once, proto-list, read, readdir-scoped-modules, rimraf, semver, tar, which, wrappy, yallist. A copy of the source code may be downloaded from git://github.com/isaacs/chownr.git (chownr), git+https://github.com/isaacs/color-support.git (color-support), https://github.com/npm/dezalgo (dezalgo), https://github.com/npm/fs-minipass.git (fs-minipass), git+https://github.com/isaacs/ignore-walk.git (ignore-walk), https://github.com/npm/ini.git (ini), git+https://github.com/isaacs/isexe.git (isexe), https://github.com/isaacs/json-stringify-nice (json-stringify-nice), git://github.com/isaacs/json-stringify-safe (json-stringify-safe), git://github.com/isaacs/node-lru-cache.git (lru-cache), git://github.com/isaacs/minimatch.git (minimatch), git+https://github.com/isaacs/minipass-flush.git (minipass-flush), git+https://github.com/isaacs/minipass-sized.git (minipass-sized), git://github.com/isaacs/mute-stream (mute-stream), https://github.com/npm/nopt.git (nopt), https://github.com/npm/npm-packlist.git (npm-packlist), git://github.com/isaacs/once (once), https://github.com/isaacs/proto-list (proto-list), git://github.com/isaacs/read.git (read), https://github.com/npm/readdir-scoped-modules (readdir-scoped-modules), git://github.com/isaacs/rimraf.git (rimraf), https://github.com/npm/node-semver.git (semver), https://github.com/isaacs/node-tar.git (tar), https://github.com/npm/node-which.git (which), https://github.com/npm/wrappy (wrappy), git+https://github.com/isaacs/yallist.git (yallist). This software contains the following license and notice below: -Copyright (c) 2015 Joyent Inc. All rights reserved. +The ISC License -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: +Copyright (c) Isaac Z. Schlueter and Contributors -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ----- @@ -12092,32 +11588,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: colord. A copy of the source code may be downloaded from https://github.com/omgovich/colord.git. This software contains the following license and notice below: - -MIT License - -Copyright (c) 2020 Vlad Shilov omgovich@ya.ru - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: colorette, getopts. A copy of the source code may be downloaded from https://github.com/jorgebucaran/colorette.git (colorette), https://github.com/jorgebucaran/getopts.git (getopts). This software contains the following license and notice below: Copyright © Jorge Bucaran <> @@ -12468,6 +11938,29 @@ OTHER DEALINGS IN THE SOFTWARE. ----- +The following software may be included in this product: concat-map, github-from-package, is-typedarray, json-stable-stringify-without-jsonify, minimist, safe-regex, semver-compare, text-table, wordwrap. A copy of the source code may be downloaded from git://github.com/substack/node-concat-map.git (concat-map), git://github.com/substack/github-from-package.git (github-from-package), git://github.com/hughsk/is-typedarray.git (is-typedarray), git://github.com/samn/json-stable-stringify.git (json-stable-stringify-without-jsonify), git://github.com/minimistjs/minimist.git (minimist), git://github.com/substack/safe-regex.git (safe-regex), git://github.com/substack/semver-compare.git (semver-compare), git://github.com/substack/text-table.git (text-table), git://github.com/substack/node-wordwrap.git (wordwrap). This software contains the following license and notice below: + +This software is released under the MIT license: + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + The following software may be included in this product: concat-stream. A copy of the source code may be downloaded from http://github.com/maxogden/concat-stream.git. This software contains the following license and notice below: The MIT License @@ -13261,216 +12754,77 @@ Apache License you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ------ - -The following software may be included in this product: create-require. A copy of the source code may be downloaded from https://github.com/nuxt-contrib/create-require.git. This software contains the following license and notice below: - -MIT License - -Copyright (c) 2020 - -Maël Nison -Paul Soporan -Pooya Parsa - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: cross-fetch. A copy of the source code may be downloaded from https://github.com/lquixada/cross-fetch.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2017 Leonardo Quixadá - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: cross-spawn. A copy of the source code may be downloaded from git@github.com:moxystudio/node-cross-spawn.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2018 Made With MOXY Lda - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - -The following software may be included in this product: crypto-js. A copy of the source code may be downloaded from http://github.com/brix/crypto-js.git. This software contains the following license and notice below: - -# License - -[The MIT License (MIT)](http://opensource.org/licenses/MIT) - -Copyright (c) 2009-2013 Jeff Mott -Copyright (c) 2013-2016 Evan Vosberg - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - -The following software may be included in this product: css-declaration-sorter. A copy of the source code may be downloaded from https://github.com/Siilwyn/css-declaration-sorter.git. This software contains the following license and notice below: - -ISC License - -Copyright (c) - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ------ - -The following software may be included in this product: css-loader, enhanced-resolve, loader-utils, schema-utils, style-loader, terser-webpack-plugin, watchpack, webpack. A copy of the source code may be downloaded from https://github.com/webpack-contrib/css-loader.git (css-loader), git://github.com/webpack/enhanced-resolve.git (enhanced-resolve), https://github.com/webpack/loader-utils.git (loader-utils), https://github.com/webpack/schema-utils.git (schema-utils), https://github.com/webpack-contrib/style-loader.git (style-loader), https://github.com/webpack-contrib/terser-webpack-plugin.git (terser-webpack-plugin), https://github.com/webpack/watchpack.git (watchpack), https://github.com/webpack/webpack.git (webpack). This software contains the following license and notice below: - -Copyright JS Foundation and other contributors + http://www.apache.org/licenses/LICENSE-2.0 -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. +----- -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +The following software may be included in this product: create-require. A copy of the source code may be downloaded from https://github.com/nuxt-contrib/create-require.git. This software contains the following license and notice below: ------ +MIT License -The following software may be included in this product: css-minimizer-webpack-plugin. A copy of the source code may be downloaded from https://github.com/webpack-contrib/css-minimizer-webpack-plugin.git. This software contains the following license and notice below: +Copyright (c) 2020 -Copyright JS Foundation and other contributors +Maël Nison +Paul Soporan +Pooya Parsa -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. ----- -The following software may be included in this product: css-select, css-what, domelementtype, domhandler, domutils, entities, nth-check. A copy of the source code may be downloaded from git://github.com/fb55/css-select.git (css-select), https://github.com/fb55/css-what (css-what), git://github.com/fb55/domelementtype.git (domelementtype), git://github.com/fb55/domhandler.git (domhandler), git://github.com/fb55/domutils.git (domutils), git://github.com/fb55/entities.git (entities), https://github.com/fb55/nth-check (nth-check). This software contains the following license and notice below: +The following software may be included in this product: cross-fetch. A copy of the source code may be downloaded from https://github.com/lquixada/cross-fetch.git. This software contains the following license and notice below: -Copyright (c) Felix Böhm -All rights reserved. +The MIT License (MIT) -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Copyright (c) 2017 Leonardo Quixadá -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. ----- -The following software may be included in this product: css-tree. A copy of the source code may be downloaded from https://github.com/csstree/csstree.git. This software contains the following license and notice below: +The following software may be included in this product: cross-spawn. A copy of the source code may be downloaded from git@github.com:moxystudio/node-cross-spawn.git. This software contains the following license and notice below: + +The MIT License (MIT) -Copyright (C) 2016-2019 by Roman Dvornov +Copyright (c) 2018 Made With MOXY Lda Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -13492,37 +12846,14 @@ THE SOFTWARE. ----- -The following software may be included in this product: cssnano-utils. A copy of the source code may be downloaded from https://github.com/cssnano/cssnano.git. This software contains the following license and notice below: - -Copyright (c) Ben Briggs (http://beneb.info) - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. +The following software may be included in this product: crypto-js. A copy of the source code may be downloaded from http://github.com/brix/crypto-js.git. This software contains the following license and notice below: ------ +# License -The following software may be included in this product: csso. A copy of the source code may be downloaded from https://github.com/css/csso.git. This software contains the following license and notice below: +[The MIT License (MIT)](http://opensource.org/licenses/MIT) -Copyright (C) 2015-2019 by Roman Dvornov -Copyright (C) 2011-2015 by Sergey Kryzhanovsky +Copyright (c) 2009-2013 Jeff Mott +Copyright (c) 2013-2016 Evan Vosberg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -13715,15 +13046,6 @@ SOFTWARE. ----- -The following software may be included in this product: date-fns. A copy of the source code may be downloaded from https://github.com/date-fns/date-fns. This software contains the following license and notice below: - -# License - -date-fns is licensed under the [MIT license](http://kossnocorp.mit-license.org). -Read more about MIT at [TLDRLegal](https://tldrlegal.com/license/mit-license). - ------ - The following software may be included in this product: date-format, streamroller. A copy of the source code may be downloaded from https://github.com/nomiddlename/date-format.git (date-format), https://github.com/log4js-node/streamroller.git (streamroller). This software contains the following license and notice below: The MIT License (MIT) @@ -14628,22 +13950,6 @@ END OF TERMS AND CONDITIONS ----- -The following software may be included in this product: dom-serializer. A copy of the source code may be downloaded from git://github.com/cheeriojs/dom-renderer.git. This software contains the following license and notice below: - -License - -(The MIT License) - -Copyright (c) 2014 The cheeriojs contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: domexception. A copy of the source code may be downloaded from https://github.com/jsdom/domexception.git. This software contains the following license and notice below: MIT License @@ -14874,6 +14180,22 @@ THE SOFTWARE. ----- +The following software may be included in this product: entities, nth-check. A copy of the source code may be downloaded from git://github.com/fb55/entities.git (entities), https://github.com/fb55/nth-check (nth-check). This software contains the following license and notice below: + +Copyright (c) Felix Böhm +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----- + The following software may be included in this product: envinfo. A copy of the source code may be downloaded from https://github.com/tabrindle/envinfo. This software contains the following license and notice below: MIT License @@ -14978,21 +14300,6 @@ SOFTWARE. ----- -The following software may be included in this product: es-module-lexer. A copy of the source code may be downloaded from git+https://github.com/guybedford/es-module-lexer.git. This software contains the following license and notice below: - -MIT License ------------ - -Copyright (C) 2018-2022 Guy Bedford - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: es-to-primitive, is-boolean-object, is-callable, is-date-object, is-number-object, is-string, is-symbol, is-typed-array, object.entries, object.values, string.prototype.matchall, which-typed-array. A copy of the source code may be downloaded from git://github.com/ljharb/es-to-primitive.git (es-to-primitive), git://github.com/inspect-js/is-boolean-object.git (is-boolean-object), git://github.com/inspect-js/is-callable.git (is-callable), git://github.com/inspect-js/is-date-object.git (is-date-object), git://github.com/inspect-js/is-number-object.git (is-number-object), git://github.com/ljharb/is-string.git (is-string), git://github.com/inspect-js/is-symbol.git (is-symbol), git://github.com/inspect-js/is-typed-array.git (is-typed-array), git://github.com/es-shims/Object.entries.git (object.entries), git://github.com/es-shims/Object.values.git (object.values), git+https://github.com/es-shims/String.prototype.matchAll.git (string.prototype.matchall), git://github.com/inspect-js/which-typed-array.git (which-typed-array). This software contains the following license and notice below: The MIT License (MIT) @@ -16947,24 +16254,6 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH RE ----- -The following software may be included in this product: get-own-enumerable-property-symbols. A copy of the source code may be downloaded from git+https://github.com/mightyiam/get-own-enumerable-property-symbols.git. This software contains the following license and notice below: - -Copyright (c) 2019, Shahar Or - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - ------ - The following software may be included in this product: get-package-type. A copy of the source code may be downloaded from git+https://github.com/cfware/get-package-type.git. This software contains the following license and notice below: MIT License @@ -18289,17 +17578,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: icss-utils. A copy of the source code may be downloaded from git+https://github.com/css-modules/icss-utils.git. This software contains the following license and notice below: - -ISC License (ISC) -Copyright 2018 Glen Maddern - -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ------ - The following software may be included in this product: idb. A copy of the source code may be downloaded from git://github.com/jakearchibald/idb.git. This software contains the following license and notice below: ISC License (ISC) @@ -19282,32 +18560,6 @@ limitations under the License. ----- -The following software may be included in this product: jora. A copy of the source code may be downloaded from https://github.com/discoveryjs/jora.git. This software contains the following license and notice below: - -MIT License - -Copyright (c) 2018-2023 Roman Dvornov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: js-cookie. A copy of the source code may be downloaded from git://github.com/js-cookie/js-cookie.git. This software contains the following license and notice below: MIT License @@ -20157,32 +19409,6 @@ SOFTWARE. ----- -The following software may be included in this product: listr, listr-silent-renderer, listr-update-renderer, listr-verbose-renderer. A copy of the source code may be downloaded from https://github.com/SamVerschueren/listr.git (listr), https://github.com/SamVerschueren/listr-silent-renderer.git (listr-silent-renderer), https://github.com/SamVerschueren/listr-update-renderer.git (listr-update-renderer), https://github.com/SamVerschueren/listr-verbose-renderer.git (listr-verbose-renderer). This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) Sam Verschueren (github.com/SamVerschueren) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - The following software may be included in this product: listr2. A copy of the source code may be downloaded from https://github.com/listr2/listr2. This software contains the following license and notice below: The MIT License (MIT) @@ -20235,29 +19461,28 @@ SOFTWARE. ----- -The following software may be included in this product: loader-runner. A copy of the source code may be downloaded from git+https://github.com/webpack/loader-runner.git. This software contains the following license and notice below: - -The MIT License +The following software may be included in this product: loader-utils, schema-utils. A copy of the source code may be downloaded from https://github.com/webpack/loader-utils.git (loader-utils), https://github.com/webpack/schema-utils.git (schema-utils). This software contains the following license and notice below: -Copyright (c) Tobias Koppers @sokra +Copyright JS Foundation and other contributors -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- @@ -20313,7 +19538,7 @@ terms above. ----- -The following software may be included in this product: lodash.defaults, lodash.difference, lodash.flatten, lodash.get, lodash.ismatch, lodash.isplainobject, lodash.memoize, lodash.truncate, lodash.union, lodash.uniq. A copy of the source code may be downloaded from https://github.com/lodash/lodash.git (lodash.defaults), https://github.com/lodash/lodash.git (lodash.difference), https://github.com/lodash/lodash.git (lodash.flatten), https://github.com/lodash/lodash.git (lodash.get), https://github.com/lodash/lodash.git (lodash.ismatch), https://github.com/lodash/lodash.git (lodash.isplainobject), https://github.com/lodash/lodash.git (lodash.memoize), https://github.com/lodash/lodash.git (lodash.truncate), https://github.com/lodash/lodash.git (lodash.union), https://github.com/lodash/lodash.git (lodash.uniq). This software contains the following license and notice below: +The following software may be included in this product: lodash.defaults, lodash.difference, lodash.flatten, lodash.get, lodash.ismatch, lodash.isplainobject, lodash.truncate, lodash.union. A copy of the source code may be downloaded from https://github.com/lodash/lodash.git (lodash.defaults), https://github.com/lodash/lodash.git (lodash.difference), https://github.com/lodash/lodash.git (lodash.flatten), https://github.com/lodash/lodash.git (lodash.get), https://github.com/lodash/lodash.git (lodash.ismatch), https://github.com/lodash/lodash.git (lodash.isplainobject), https://github.com/lodash/lodash.git (lodash.truncate), https://github.com/lodash/lodash.git (lodash.union). This software contains the following license and notice below: Copyright jQuery Foundation and other contributors @@ -20655,127 +19880,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----- -The following software may be included in this product: mdn-data. A copy of the source code may be downloaded from https://github.com/mdn/data.git. This software contains the following license and notice below: - -CC0 1.0 Universal - -Statement of Purpose - -The laws of most jurisdictions throughout the world automatically confer -exclusive Copyright and Related Rights (defined below) upon the creator and -subsequent owner(s) (each and all, an "owner") of an original work of -authorship and/or a database (each, a "Work"). - -Certain owners wish to permanently relinquish those rights to a Work for the -purpose of contributing to a commons of creative, cultural and scientific -works ("Commons") that the public can reliably and without fear of later -claims of infringement build upon, modify, incorporate in other works, reuse -and redistribute as freely as possible in any form whatsoever and for any -purposes, including without limitation commercial purposes. These owners may -contribute to the Commons to promote the ideal of a free culture and the -further production of creative, cultural and scientific works, or to gain -reputation or greater distribution for their Work in part through the use and -efforts of others. - -For these and/or other purposes and motivations, and without any expectation -of additional consideration or compensation, the person associating CC0 with a -Work (the "Affirmer"), to the extent that he or she is an owner of Copyright -and Related Rights in the Work, voluntarily elects to apply CC0 to the Work -and publicly distribute the Work under its terms, with knowledge of his or her -Copyright and Related Rights in the Work and the meaning and intended legal -effect of CC0 on those rights. - -1. Copyright and Related Rights. A Work made available under CC0 may be -protected by copyright and related or neighboring rights ("Copyright and -Related Rights"). Copyright and Related Rights include, but are not limited -to, the following: - - i. the right to reproduce, adapt, distribute, perform, display, communicate, - and translate a Work; - - ii. moral rights retained by the original author(s) and/or performer(s); - - iii. publicity and privacy rights pertaining to a person's image or likeness - depicted in a Work; - - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - - v. rights protecting the extraction, dissemination, use and reuse of data in - a Work; - - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation thereof, - including any amended or successor version of such directive); and - - vii. other similar, equivalent or corresponding rights throughout the world - based on applicable law or treaty, and any national implementations thereof. - -2. Waiver. To the greatest extent permitted by, but not in contravention of, -applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and -unconditionally waives, abandons, and surrenders all of Affirmer's Copyright -and Related Rights and associated claims and causes of action, whether now -known or unknown (including existing as well as future claims and causes of -action), in the Work (i) in all territories worldwide, (ii) for the maximum -duration provided by applicable law or treaty (including future time -extensions), (iii) in any current or future medium and for any number of -copies, and (iv) for any purpose whatsoever, including without limitation -commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes -the Waiver for the benefit of each member of the public at large and to the -detriment of Affirmer's heirs and successors, fully intending that such Waiver -shall not be subject to revocation, rescission, cancellation, termination, or -any other legal or equitable action to disrupt the quiet enjoyment of the Work -by the public as contemplated by Affirmer's express Statement of Purpose. - -3. Public License Fallback. Should any part of the Waiver for any reason be -judged legally invalid or ineffective under applicable law, then the Waiver -shall be preserved to the maximum extent permitted taking into account -Affirmer's express Statement of Purpose. In addition, to the extent the Waiver -is so judged Affirmer hereby grants to each affected person a royalty-free, -non transferable, non sublicensable, non exclusive, irrevocable and -unconditional license to exercise Affirmer's Copyright and Related Rights in -the Work (i) in all territories worldwide, (ii) for the maximum duration -provided by applicable law or treaty (including future time extensions), (iii) -in any current or future medium and for any number of copies, and (iv) for any -purpose whatsoever, including without limitation commercial, advertising or -promotional purposes (the "License"). The License shall be deemed effective as -of the date CC0 was applied by Affirmer to the Work. Should any part of the -License for any reason be judged legally invalid or ineffective under -applicable law, such partial invalidity or ineffectiveness shall not -invalidate the remainder of the License, and in such case Affirmer hereby -affirms that he or she will not (i) exercise any of his or her remaining -Copyright and Related Rights in the Work or (ii) assert any associated claims -and causes of action with respect to the Work, in either case contrary to -Affirmer's express Statement of Purpose. - -4. Limitations and Disclaimers. - - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - - b. Affirmer offers the Work as-is and makes no representations or warranties - of any kind concerning the Work, express, implied, statutory or otherwise, - including without limitation warranties of title, merchantability, fitness - for a particular purpose, non infringement, or the absence of latent or - other defects, accuracy, or the present or absence of errors, whether or not - discoverable, all to the greatest extent permissible under applicable law. - - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without limitation - any person's Copyright and Related Rights in the Work. Further, Affirmer - disclaims responsibility for obtaining any necessary consents, permissions - or other rights required for any use of the Work. - - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to this - CC0 or use of the Work. - -For more information, please see - - ------ - The following software may be included in this product: mdurl. A copy of the source code may be downloaded from https://github.com/markdown-it/mdurl.git. This software contains the following license and notice below: Copyright (c) 2015 Vitaly Puzrin, Alex Kocharin. @@ -21625,26 +20729,6 @@ THE SOFTWARE. ----- -The following software may be included in this product: nanospinner. A copy of the source code may be downloaded from https://github.com/usmanyunusov/nanospinner.git. This software contains the following license and notice below: - -ISC License - -Copyright 2021 Usman Yunusov - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ------ - The following software may be included in this product: napi-build-utils. A copy of the source code may be downloaded from git+https://github.com/inspiredware/napi-build-utils.git. This software contains the following license and notice below: MIT License @@ -22867,249 +21951,63 @@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - -The following software may be included in this product: plist. A copy of the source code may be downloaded from git://github.com/TooTallNate/node-plist.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2010-2017 Nathan Rajlich - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - ------ - -The following software may be included in this product: pluralize. A copy of the source code may be downloaded from https://github.com/blakeembrey/pluralize.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2013 Blake Embrey (hello@blakeembrey.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - -The following software may be included in this product: postcss. A copy of the source code may be downloaded from https://github.com/postcss/postcss.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright 2013 Andrey Sitnik - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - -The following software may be included in this product: postcss-calc. A copy of the source code may be downloaded from https://github.com/postcss/postcss-calc.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2014 Maxime Thirouin - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - -The following software may be included in this product: postcss-discard-overridden. A copy of the source code may be downloaded from https://github.com/cssnano/cssnano.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright 2016 Justineo - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - -The following software may be included in this product: postcss-minify-font-values, postcss-value-parser. A copy of the source code may be downloaded from https://github.com/cssnano/cssnano.git (postcss-minify-font-values), https://github.com/TrySound/postcss-value-parser.git (postcss-value-parser). This software contains the following license and notice below: - -Copyright (c) Bogdan Chadkin - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - ------ - -The following software may be included in this product: postcss-minify-params, postcss-normalize-charset. A copy of the source code may be downloaded from https://github.com/cssnano/cssnano.git (postcss-minify-params), https://github.com/cssnano/cssnano.git (postcss-normalize-charset). This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright 2015 Bogdan Chadkin - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - -The following software may be included in this product: postcss-modules-extract-imports. A copy of the source code may be downloaded from https://github.com/css-modules/postcss-modules-extract-imports.git. This software contains the following license and notice below: - -Copyright 2015 Glen Maddern - -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ------ - -The following software may be included in this product: postcss-modules-local-by-default. A copy of the source code may be downloaded from https://github.com/css-modules/postcss-modules-local-by-default.git. This software contains the following license and notice below: - -The MIT License (MIT) - -Copyright 2015 Mark Dalgleish - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. ----- -The following software may be included in this product: postcss-modules-scope. A copy of the source code may be downloaded from https://github.com/css-modules/postcss-modules-scope.git. This software contains the following license and notice below: +The following software may be included in this product: plist. A copy of the source code may be downloaded from git://github.com/TooTallNate/node-plist.git. This software contains the following license and notice below: -ISC License (ISC) +(The MIT License) -Copyright (c) 2015, Glen Maddern +Copyright (c) 2010-2017 Nathan Rajlich -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: postcss-modules-values. A copy of the source code may be downloaded from git+https://github.com/css-modules/postcss-modules-values.git. This software contains the following license and notice below: +The following software may be included in this product: pluralize. A copy of the source code may be downloaded from https://github.com/blakeembrey/pluralize.git. This software contains the following license and notice below: -ISC License (ISC) +The MIT License (MIT) -Copyright (c) 2015, Glen Maddern +Copyright (c) 2013 Blake Embrey (hello@blakeembrey.com) -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. ----- @@ -29424,32 +28322,6 @@ IN THE SOFTWARE. ----- -The following software may be included in this product: randombytes. A copy of the source code may be downloaded from git@github.com:crypto-browserify/randombytes.git. This software contains the following license and notice below: - -MIT License - -Copyright (c) 2017 crypto-browserify - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: range-parser. A copy of the source code may be downloaded from https://github.com/jshttp/range-parser.git. This software contains the following license and notice below: (The MIT License) @@ -30875,38 +29747,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: serialize-javascript. A copy of the source code may be downloaded from git+https://github.com/yahoo/serialize-javascript.git. This software contains the following license and notice below: - -Copyright 2014 Yahoo! Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the Yahoo! Inc. nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL YAHOO! INC. BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------ - The following software may be included in this product: serve-static. A copy of the source code may be downloaded from https://github.com/expressjs/serve-static.git. This software contains the following license and notice below: (The MIT License) @@ -31221,33 +30061,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI ----- -The following software may be included in this product: slice-ansi. A copy of the source code may be downloaded from https://github.com/chalk/slice-ansi.git. This software contains the following license and notice below: - -(The MIT License) - -Copyright (c) 2015 DC - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------ - The following software may be included in this product: smart-buffer. A copy of the source code may be downloaded from https://github.com/JoshGlazebrook/smart-buffer.git. This software contains the following license and notice below: The MIT License (MIT) @@ -31324,7 +30137,7 @@ THE SOFTWARE. ----- -The following software may be included in this product: source-map, source-map-js. A copy of the source code may be downloaded from http://github.com/mozilla/source-map.git (source-map), https://github.com/7rulnik/source-map-js.git (source-map-js). This software contains the following license and notice below: +The following software may be included in this product: source-map. A copy of the source code may be downloaded from http://github.com/mozilla/source-map.git. This software contains the following license and notice below: Copyright (c) 2009-2011, Mozilla Foundation and contributors All rights reserved. @@ -31923,33 +30736,6 @@ SOFTWARE. ----- -The following software may be included in this product: stringify-object. A copy of the source code may be downloaded from https://github.com/yeoman/stringify-object.git. This software contains the following license and notice below: - -Copyright (c) 2015, Yeoman team -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------ - The following software may be included in this product: strnum. A copy of the source code may be downloaded from https://github.com/NaturalIntelligence/strnum. This software contains the following license and notice below: MIT License @@ -32012,32 +30798,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI ----- -The following software may be included in this product: svgo. A copy of the source code may be downloaded from git://github.com/svg/svgo.git. This software contains the following license and notice below: - -MIT License - -Copyright (c) Kir Belevich - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: symbol-observable. A copy of the source code may be downloaded from https://github.com/blesh/symbol-observable.git. This software contains the following license and notice below: The MIT License (MIT) @@ -32091,32 +30851,6 @@ THE SOFTWARE. ----- -The following software may be included in this product: tapable. A copy of the source code may be downloaded from http://github.com/webpack/tapable.git. This software contains the following license and notice below: - -The MIT License - -Copyright JS Foundation and other contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------ - The following software may be included in this product: tarn. A copy of the source code may be downloaded from git://github.com/vincit/tarn.js.git. This software contains the following license and notice below: The MIT License (MIT) @@ -32143,38 +30877,6 @@ SOFTWARE. ----- -The following software may be included in this product: terser. A copy of the source code may be downloaded from https://github.com/terser/terser. This software contains the following license and notice below: - -Copyright 2012-2018 (c) Mihai Bazon - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, -OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - ------ - The following software may be included in this product: text-hex. A copy of the source code may be downloaded from https://github.com/3rd-Eden/text-hex. This software contains the following license and notice below: The MIT License (MIT) @@ -33369,32 +32071,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ----- -The following software may be included in this product: webpack-sources. A copy of the source code may be downloaded from git+https://github.com/webpack/webpack-sources.git. This software contains the following license and notice below: - -MIT License - -Copyright (c) 2017 JS Foundation and other contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: whatwg-encoding. A copy of the source code may be downloaded from https://github.com/jsdom/whatwg-encoding.git. This software contains the following license and notice below: Copyright © 2016–2018 Domenic Denicola diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md deleted file mode 100644 index 1adc40a5da..0000000000 --- a/packages/amplify-category-api/CHANGELOG.md +++ /dev/null @@ -1,2408 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [5.12.6](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.12.5...@aws-amplify/amplify-category-api@5.12.6) (2024-08-12) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.12.5](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.12.4...@aws-amplify/amplify-category-api@5.12.5) (2024-08-01) - -### Bug Fixes - -- update awaiter s3 key ([#2732](https://github.com/aws-amplify/amplify-category-api/issues/2732)) ([08db67b](https://github.com/aws-amplify/amplify-category-api/commit/08db67b4e291995f4050d845771228859af9e799)) - -## [5.12.4](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.12.3...@aws-amplify/amplify-category-api@5.12.4) (2024-07-25) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.12.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.12.2...@aws-amplify/amplify-category-api@5.12.3) (2024-07-15) - -### Bug Fixes - -- add translation behavior to disable gen 1 patterns ([#2670](https://github.com/aws-amplify/amplify-category-api/issues/2670)) ([38d1a71](https://github.com/aws-amplify/amplify-category-api/commit/38d1a718ec2b0290f514780c6d1d5f0790ba7764)) -- set allowGen1Patterns to true in gen 1 ([#2699](https://github.com/aws-amplify/amplify-category-api/issues/2699)) ([1e2a0f3](https://github.com/aws-amplify/amplify-category-api/commit/1e2a0f33f7ff5784ccdedf315084ad098f81b9c3)) - -## [5.12.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.12.1...@aws-amplify/amplify-category-api@5.12.2) (2024-07-02) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.12.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.12.0...@aws-amplify/amplify-category-api@5.12.1) (2024-07-01) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -# [5.12.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.11.7...@aws-amplify/amplify-category-api@5.12.0) (2024-06-25) - -### Features - -- allow subscriptions to inherit primary model auth rules for relational fields behind a feature flag ([#2649](https://github.com/aws-amplify/amplify-category-api/issues/2649)) ([56a853a](https://github.com/aws-amplify/amplify-category-api/commit/56a853ace0026de97395cfa17ca156cf360ac5c2)) -- **generate-schema:** custom ssl cert support to generate schema command ([#2615](https://github.com/aws-amplify/amplify-category-api/issues/2615)) ([390887f](https://github.com/aws-amplify/amplify-category-api/commit/390887ff4467baca9dad8f70071442b95bb04cf9)) - -## [5.11.7](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.11.6...@aws-amplify/amplify-category-api@5.11.7) (2024-06-06) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.11.6](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.11.5...@aws-amplify/amplify-category-api@5.11.6) (2024-06-04) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.11.5](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.11.4...@aws-amplify/amplify-category-api@5.11.5) (2024-05-15) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.11.4](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.11.3...@aws-amplify/amplify-category-api@5.11.4) (2024-05-10) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.11.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.11.2...@aws-amplify/amplify-category-api@5.11.3) (2024-05-01) - -### Performance Improvements - -- **graphql-model-transformer:** minimal provider framework and inline policies ([#2490](https://github.com/aws-amplify/amplify-category-api/issues/2490)) ([a86c816](https://github.com/aws-amplify/amplify-category-api/commit/a86c816ceb288376c4dfa9b1d12413edd28cf75e)) - -## [5.11.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.11.1...@aws-amplify/amplify-category-api@5.11.2) (2024-04-26) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.11.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.11.0...@aws-amplify/amplify-category-api@5.11.1) (2024-04-16) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -# [5.11.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.10.0...@aws-amplify/amplify-category-api@5.11.0) (2024-04-11) - -### Features - -- Fetch SNS topic ARN from SQL manifest ([#2345](https://github.com/aws-amplify/amplify-category-api/issues/2345)) ([fca256e](https://github.com/aws-amplify/amplify-category-api/commit/fca256e7cabf5af838b28b26c4ae0c3c8b1583eb)) - -# [5.10.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.9.8...@aws-amplify/amplify-category-api@5.10.0) (2024-03-28) - -### Bug Fixes - -- REST deployment issue due to missing ecs:TagResource permission ([#2378](https://github.com/aws-amplify/amplify-category-api/issues/2378)) ([96d08e9](https://github.com/aws-amplify/amplify-category-api/commit/96d08e9812e2ed45541f88d1360c90d5bc8a2fca)) - -### Features - -- add secrets manager as credential store for sql lambda ([#2289](https://github.com/aws-amplify/amplify-category-api/issues/2289)) ([affdb98](https://github.com/aws-amplify/amplify-category-api/commit/affdb988b499591c3a96608f772b637ddd8c3a0c)) - -## [5.9.8](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.9.7...@aws-amplify/amplify-category-api@5.9.8) (2024-03-13) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.9.7](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.9.6...@aws-amplify/amplify-category-api@5.9.7) (2024-02-28) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.9.6](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.9.5...@aws-amplify/amplify-category-api@5.9.6) (2024-02-05) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.9.5](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.9.4...@aws-amplify/amplify-category-api@5.9.5) (2024-01-30) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.9.4](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.9.3...@aws-amplify/amplify-category-api@5.9.4) (2024-01-22) - -### Bug Fixes - -- **api:** download rds layer only if required ([9373673](https://github.com/aws-amplify/amplify-category-api/commit/9373673fea95f37a8ce1a01d8034aae556ce6921)) - -## [5.9.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.9.2...@aws-amplify/amplify-category-api@5.9.3) (2023-12-21) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.9.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.9.1...@aws-amplify/amplify-category-api@5.9.2) (2023-12-18) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.9.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.9.0...@aws-amplify/amplify-category-api@5.9.1) (2023-12-14) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -# [5.9.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.8.3...@aws-amplify/amplify-category-api@5.9.0) (2023-12-06) - -### Features - -- combine heterogeneous data sources ([#2109](https://github.com/aws-amplify/amplify-category-api/issues/2109)) ([fd58bb5](https://github.com/aws-amplify/amplify-category-api/commit/fd58bb5af4249220d17c9751acf677955aed74ea)) - -## [5.8.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.8.2...@aws-amplify/amplify-category-api@5.8.3) (2023-11-22) - -### Bug Fixes - -- Allow custom SQL statements without model declarations ([#2087](https://github.com/aws-amplify/amplify-category-api/issues/2087)) ([ea5b26c](https://github.com/aws-amplify/amplify-category-api/commit/ea5b26cd554f5c74b6431cbad6ccf60ab556478f)) - -## [5.8.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.8.1...@aws-amplify/amplify-category-api@5.8.2) (2023-11-18) - -### Bug Fixes - -- regionalize lambda layer patching SNS topics ([#2079](https://github.com/aws-amplify/amplify-category-api/issues/2079)) ([6006c86](https://github.com/aws-amplify/amplify-category-api/commit/6006c86cd4ee624b24c184fab523fcdcdb38be63)) - -## [5.8.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.8.0...@aws-amplify/amplify-category-api@5.8.1) (2023-11-16) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -# [5.8.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.7.8...@aws-amplify/amplify-category-api@5.8.0) (2023-11-15) - -### Bug Fixes - -- **api:** make id optional if not a string type ([48ecac0](https://github.com/aws-amplify/amplify-category-api/commit/48ecac0989097106a531ebb898abbda7a0f1745c)) -- Change 'rds' to 'sql' in public-facing symbols ([#2069](https://github.com/aws-amplify/amplify-category-api/issues/2069)) ([ff374dd](https://github.com/aws-amplify/amplify-category-api/commit/ff374dd8398d3f1138a31669b1a5962122039437)) - -### Features - -- add graphqlSchemaFromRDSSchema for unauth schema import ([#2004](https://github.com/aws-amplify/amplify-category-api/issues/2004)) ([4d79599](https://github.com/aws-amplify/amplify-category-api/commit/4d79599855b86b5ef8040519f39039d619a34d9a)) -- add managed table support in API construct ([#2024](https://github.com/aws-amplify/amplify-category-api/issues/2024)) ([96a0d94](https://github.com/aws-amplify/amplify-category-api/commit/96a0d94fa872a5329da120f53be139833449b815)), closes [#1849](https://github.com/aws-amplify/amplify-category-api/issues/1849) [#1903](https://github.com/aws-amplify/amplify-category-api/issues/1903) [#1940](https://github.com/aws-amplify/amplify-category-api/issues/1940) [#1971](https://github.com/aws-amplify/amplify-category-api/issues/1971) [#1973](https://github.com/aws-amplify/amplify-category-api/issues/1973) -- add postgres engine and update types as needed ([#1979](https://github.com/aws-amplify/amplify-category-api/issues/1979)) ([5257d53](https://github.com/aws-amplify/amplify-category-api/commit/5257d53f1d4d02be71b34ddf6757f22dd5d74aff)) -- add postgres support to graphqlSchemaFromRDSSchema ([#2015](https://github.com/aws-amplify/amplify-category-api/issues/2015)) ([6a2c5f0](https://github.com/aws-amplify/amplify-category-api/commit/6a2c5f00d72ff10ebf011b763348158a353deb31)) -- Add SQL database support to AmplifyGraphqlApi construct ([#1986](https://github.com/aws-amplify/amplify-category-api/issues/1986)) ([2ff63a5](https://github.com/aws-amplify/amplify-category-api/commit/2ff63a540387d96cf10d8ae1975858a76d9ba045)), closes [#1917](https://github.com/aws-amplify/amplify-category-api/issues/1917) [#1983](https://github.com/aws-amplify/amplify-category-api/issues/1983) -- **api:** add vpc endpoints for ssm ([5a4ffc4](https://github.com/aws-amplify/amplify-category-api/commit/5a4ffc4c1889536c8e1fdd1f31fe28ca4326100f)) -- **api:** custom queries support using sql directive ([5214037](https://github.com/aws-amplify/amplify-category-api/commit/52140374ca974956c5d5eac09fec91a51cfc9027)) -- **api:** postgres import workflow ([a87203f](https://github.com/aws-amplify/amplify-category-api/commit/a87203f5e7b0a279f6c916069b648f973089e074)) -- **api:** prompt changes to add postgres support ([9e4c41c](https://github.com/aws-amplify/amplify-category-api/commit/9e4c41c28b286e15a574eff9867f1f910a6f9ed3)) -- **api:** refactor auth transformer to use vtl generator factory pattern ([e965d24](https://github.com/aws-amplify/amplify-category-api/commit/e965d24731fc1e2300ef0e16b61af6b39afb0cad)) -- Support RDS Proxy schema imports ([#1917](https://github.com/aws-amplify/amplify-category-api/issues/1917)) ([55bb698](https://github.com/aws-amplify/amplify-category-api/commit/55bb698f319d3abb63ad0a8260f731e57c0d0fa9)) -- transformer behavior of replacing table upon gsi updates ([#2067](https://github.com/aws-amplify/amplify-category-api/issues/2067)) ([c4b7530](https://github.com/aws-amplify/amplify-category-api/commit/c4b7530e0880b34d411fc2732fa199e4a28bcea1)) - -## [5.7.8](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.7.7...@aws-amplify/amplify-category-api@5.7.8) (2023-11-02) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.7.7](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.7.6...@aws-amplify/amplify-category-api@5.7.7) (2023-10-27) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.7.6](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.7.5...@aws-amplify/amplify-category-api@5.7.6) (2023-10-21) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.7.5](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.7.4...@aws-amplify/amplify-category-api@5.7.5) (2023-10-12) - -### Bug Fixes - -- convert single action to list of actions ([#1937](https://github.com/aws-amplify/amplify-category-api/issues/1937)) ([22c3115](https://github.com/aws-amplify/amplify-category-api/commit/22c3115b93264d1fb637c13ba7c9f20915f99904)) - -## [5.7.4](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.7.3...@aws-amplify/amplify-category-api@5.7.4) (2023-10-05) - -### Bug Fixes - -- iam auth values can be passed as cdk tokens ([#1919](https://github.com/aws-amplify/amplify-category-api/issues/1919)) ([9297fa5](https://github.com/aws-amplify/amplify-category-api/commit/9297fa5cda87697645ad0c78b84c3004b32ac319)) - -## [5.7.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.7.2...@aws-amplify/amplify-category-api@5.7.3) (2023-10-03) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.7.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.7.1...@aws-amplify/amplify-category-api@5.7.2) (2023-10-02) - -### Bug Fixes - -- change the ttl to integer ([#1901](https://github.com/aws-amplify/amplify-category-api/issues/1901)) ([9cfaa02](https://github.com/aws-amplify/amplify-category-api/commit/9cfaa02b429f3933d44c5dd117105a816d24ef6c)) - -## [5.7.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.7.0...@aws-amplify/amplify-category-api@5.7.1) (2023-09-27) - -### Bug Fixes - -- **apigw:** replace path param with wildcard ([#1880](https://github.com/aws-amplify/amplify-category-api/issues/1880)) ([25b6523](https://github.com/aws-amplify/amplify-category-api/commit/25b65238b5e35e03b1275f432693d8dd6c8fc966)) - -# [5.7.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.6.4...@aws-amplify/amplify-category-api@5.7.0) (2023-09-20) - -### Features - -- disable amplify cfn outputs for cdk apps ([0c72d18](https://github.com/aws-amplify/amplify-category-api/commit/0c72d1822f8e5ccb3e04a0a49049a459b5fb49e6)) - -## [5.6.4](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.6.3...@aws-amplify/amplify-category-api@5.6.4) (2023-09-13) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.6.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.6.2...@aws-amplify/amplify-category-api@5.6.3) (2023-09-07) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.6.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.6.1...@aws-amplify/amplify-category-api@5.6.2) (2023-08-30) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.6.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.6.0...@aws-amplify/amplify-category-api@5.6.1) (2023-08-28) - -### Bug Fixes - -- reading admin role names ([#1823](https://github.com/aws-amplify/amplify-category-api/issues/1823)) ([987b6a6](https://github.com/aws-amplify/amplify-category-api/commit/987b6a6d4e0cbdcc64edbbddbfd8a16b30c7f199)) - -# [5.6.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.5.3...@aws-amplify/amplify-category-api@5.6.0) (2023-08-09) - -### Features - -- bump major version of transformer packages ([2458c84](https://github.com/aws-amplify/amplify-category-api/commit/2458c8426da5772aa669d37e11f99ee9c6c5ac2e)) - -## [5.5.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.5.2...@aws-amplify/amplify-category-api@5.5.3) (2023-08-07) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.5.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.5.1...@aws-amplify/amplify-category-api@5.5.2) (2023-07-31) - -### Bug Fixes - -- add build packages ([5b98ca0](https://github.com/aws-amplify/amplify-category-api/commit/5b98ca029994fab8f20b2ff5e762d01877e6beb2)) - -## [5.5.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.5.0...@aws-amplify/amplify-category-api@5.5.1) (2023-07-27) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -# [5.5.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.4.7...@aws-amplify/amplify-category-api@5.5.0) (2023-07-21) - -### Bug Fixes - -- remove vm2 dependency ([e684c0d](https://github.com/aws-amplify/amplify-category-api/commit/e684c0d0674e0b2e1708fe1ad4b0e0b910dd0c06)) - -### Features - -- **api:** accept database url in import api command ([7d13f6c](https://github.com/aws-amplify/amplify-category-api/commit/7d13f6c7a348b0dc90c6f7ec0d9dae7770f9d8ee)) -- **graphql:** add vpc support for import workflow ([44170f9](https://github.com/aws-amplify/amplify-category-api/commit/44170f9f6ea4c7fe8b30604037067c4d36f71d2e)) -- **graphql:** pull rds latest layer ([8325ef5](https://github.com/aws-amplify/amplify-category-api/commit/8325ef559b4bd5d86e9502bb1dc2cff833e7db0c)) -- **graphql:** vpc support for sql lambda ([9cc4407](https://github.com/aws-amplify/amplify-category-api/commit/9cc4407bdc4799fe548919808961911a3d5995c7)) - -## [5.4.7](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.4.6...@aws-amplify/amplify-category-api@5.4.7) (2023-07-17) - -### Bug Fixes - -- make iam.PolicyStatement from IAM policy JSON object ([#1556](https://github.com/aws-amplify/amplify-category-api/issues/1556)) ([41219c3](https://github.com/aws-amplify/amplify-category-api/commit/41219c3295352c10871232d7bd6aad5f85b9b486)), closes [#1445](https://github.com/aws-amplify/amplify-category-api/issues/1445) - -## [5.4.6](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.4.5...@aws-amplify/amplify-category-api@5.4.6) (2023-07-07) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.4.5](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.4.4...@aws-amplify/amplify-category-api@5.4.5) (2023-07-07) - -### Bug Fixes - -- trigger republish of dependencies that failed in https://app.circleci.com/pipelines/github/aws-amplify/amplify-category-api/7981/workflows/e7366f04-6f0a-4ee4-9cc2-1772089e8005/jobs/163571 ([f2c7151](https://github.com/aws-amplify/amplify-category-api/commit/f2c7151005e4a9fd29d91ac1af1f3e482a06a5cc)) - -## [5.4.4](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.4.3...@aws-amplify/amplify-category-api@5.4.4) (2023-07-07) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [5.4.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.4.2...@aws-amplify/amplify-category-api@5.4.3) (2023-06-29) - -### Bug Fixes - -- handling of all floating promises ([#1577](https://github.com/aws-amplify/amplify-category-api/issues/1577)) ([d5981b2](https://github.com/aws-amplify/amplify-category-api/commit/d5981b2f912d03b44e1269ca704816dd250ff501)) - -## [5.4.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.4.1...@aws-amplify/amplify-category-api@5.4.2) (2023-06-20) - -### Bug Fixes - -- remove unsupported errors for rds cmands ([11d8305](https://github.com/aws-amplify/amplify-category-api/commit/11d8305abddfe5ba82d9fcf2d009575e8d3c77c7)) - -## [5.4.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.4.0...@aws-amplify/amplify-category-api@5.4.1) (2023-06-05) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -# [5.4.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.3.0...@aws-amplify/amplify-category-api@5.4.0) (2023-05-23) - -### Bug Fixes - -- container resource name input validation pattern ([9a16282](https://github.com/aws-amplify/amplify-category-api/commit/9a16282392764890cdca71d1fc9598af8b42cb77)) -- update version nodejs16.x from nodejs12.x since nodejs12.x is deprecated ([50da1df](https://github.com/aws-amplify/amplify-category-api/commit/50da1df786b043109374cad0472e32b086e3b678)) - -### Features - -- add force-api-refresh option to the api push command in order to support refreshing an API (for example, on resolver code changes) ([2eba122](https://github.com/aws-amplify/amplify-category-api/commit/2eba122232ca6bb5f4c704e75c505a828fb56d12)) - -# [5.3.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.2.1...@aws-amplify/amplify-category-api@5.3.0) (2023-05-17) - -### Bug Fixes - -- added await ([9aa13a2](https://github.com/aws-amplify/amplify-category-api/commit/9aa13a2bd39d9697069633de59e5f4410589764e)) -- auto generate schema from import api ([1c55fcc](https://github.com/aws-amplify/amplify-category-api/commit/1c55fccf76e0f3ea838be904dfa2209db883c8df)) -- build jobs ([33c1495](https://github.com/aws-amplify/amplify-category-api/commit/33c1495347a0365c1eafab48840ada2c2667d8cd)) -- error flow when secrets do not work ([6d04354](https://github.com/aws-amplify/amplify-category-api/commit/6d04354c67fd7c153469a19f5293e0c2e5f22a43)) -- global Amplify input type removed from compiled schema ([f75af60](https://github.com/aws-amplify/amplify-category-api/commit/f75af6001c6ff50433437fad2a0697e00baf5b88)) -- handle edge cases in the user experience ([ebd1ba9](https://github.com/aws-amplify/amplify-category-api/commit/ebd1ba9e828c58856e072e5fc51064c9d5c0ed69)) -- populate database secrets map only if imported database exists ([446d456](https://github.com/aws-amplify/amplify-category-api/commit/446d456d8b10f827c7f5f26892c1b47e9ef729f1)) -- rds v2 e2e tests ([f0f344d](https://github.com/aws-amplify/amplify-category-api/commit/f0f344d7034ab1fa4cdeb4a97429b2705d622848)) -- remove DB info from schema global input ([d28a5cf](https://github.com/aws-amplify/amplify-category-api/commit/d28a5cfde7dbba31fe5540ef724b564c9c2eeef5)) -- remove dependency of v2 transformer core on schema generator ([aabbe46](https://github.com/aws-amplify/amplify-category-api/commit/aabbe466862e6f31e545a476d94644fd83295f45)) -- retain user Amplify input in the schema ([df3dbec](https://github.com/aws-amplify/amplify-category-api/commit/df3dbecba54183262c544499424c8dbbcc78b421)) -- store database also in parameter store ([41cd7f3](https://github.com/aws-amplify/amplify-category-api/commit/41cd7f3855c8019c18b3e998b7f702bcb21471f1)) -- update lambda to get db details from ssm ([4e3d10b](https://github.com/aws-amplify/amplify-category-api/commit/4e3d10bce43d17e2f489df4c40a09d9e5b7e315b)) -- update tests ([3981bfa](https://github.com/aws-amplify/amplify-category-api/commit/3981bfa12dedafebb636c10ea24b0c64414c2408)) - -### Features - -- add api import, generate-schema workflows ([a92c223](https://github.com/aws-amplify/amplify-category-api/commit/a92c223ee6b27d089991bbb1b1b4b7cd8592f910)) -- add multi-env secret management ([6c70600](https://github.com/aws-amplify/amplify-category-api/commit/6c70600bbb0fba5d6a33ac3a37739b5a65eef7a6)) -- add update RDS secrets workflow ([6966161](https://github.com/aws-amplify/amplify-category-api/commit/6966161eedf6fc7bac3266746fd8c5a39648bb0c)) -- add utils for param store calls ([bc26e71](https://github.com/aws-amplify/amplify-category-api/commit/bc26e71a99e279dc2fe2e7d2507ee50ee0d5c5fb)) -- **api:** generate graphql schema from internal schema representation ([5362983](https://github.com/aws-amplify/amplify-category-api/commit/5362983e7fa46f164f63f72c44c805dceb5f3f94)) -- **graphql:** read datasource type from schema file ([d7f50e5](https://github.com/aws-amplify/amplify-category-api/commit/d7f50e5ca026a3bbf378437cf6a165cc5b438bb5)) -- RDS generate schema handles default values ([e866dfa](https://github.com/aws-amplify/amplify-category-api/commit/e866dfa7cb113a736f52f4749dfc160350476970)) -- re-use the common flows b/w add and import api ([463bffc](https://github.com/aws-amplify/amplify-category-api/commit/463bffcf6d0b30d9e25027ca5a93d8dce15de0cf)) - -## [5.2.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.2.0...@aws-amplify/amplify-category-api@5.2.1) (2023-04-25) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -# [5.2.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.1.1...@aws-amplify/amplify-category-api@5.2.0) (2023-03-30) - -### Features - -- **api:** allow \${env} reference in custom-roles.json ([#804](https://github.com/aws-amplify/amplify-category-api/issues/804)) ([ba9d8c0](https://github.com/aws-amplify/amplify-category-api/commit/ba9d8c0f1dabf48675a555b027c16e4f8953f9dd)) -- inject project info into api overrides ([#1372](https://github.com/aws-amplify/amplify-category-api/issues/1372)) ([2b92351](https://github.com/aws-amplify/amplify-category-api/commit/2b92351c95a5c820e0e758e69226c08f4355d472)) - -## [5.1.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.1.0...@aws-amplify/amplify-category-api@5.1.1) (2023-03-15) - -### Bug Fixes - -- **api:** correct container code build policy ([517315a](https://github.com/aws-amplify/amplify-category-api/commit/517315a986bffb97c68299dfe585ac783fdd4a5a)) -- fixes apigw tests ([8e7a325](https://github.com/aws-amplify/amplify-category-api/commit/8e7a3253ad9696e94606abca962afe268beff7cb)) - -# [5.1.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.1.9...@aws-amplify/amplify-category-api@5.1.0) (2023-03-01) - -### Bug Fixes - -- container api cfn generation ([#947](https://github.com/aws-amplify/amplify-category-api/issues/947)) ([0f675f2](https://github.com/aws-amplify/amplify-category-api/commit/0f675f222e24c07084b2907bc62024d7126f574e)) -- lock CDK v2 version ([#923](https://github.com/aws-amplify/amplify-category-api/issues/923)) ([2afe40c](https://github.com/aws-amplify/amplify-category-api/commit/2afe40cf13e7d1ee7db37988b9b3297768c7bd0a)) -- migrate to cdkv2 - e2e tests fixes ([#910](https://github.com/aws-amplify/amplify-category-api/issues/910)) ([c7b2503](https://github.com/aws-amplify/amplify-category-api/commit/c7b250361bf0c82fc067e03675101b9dfb6a25de)) -- preserve logical id patterns for dynamodb tables and search domain ([#894](https://github.com/aws-amplify/amplify-category-api/issues/894)) ([7530fc2](https://github.com/aws-amplify/amplify-category-api/commit/7530fc2e9254b621dc3782271318dd3f5c97d2b8)) -- throw error if invalid override or invalid custom stack error ([#982](https://github.com/aws-amplify/amplify-category-api/issues/982)) ([6dfeeba](https://github.com/aws-amplify/amplify-category-api/commit/6dfeeba627cd84a41eb8b4248856fa487c741f87)) - -### Features - -- migrate amplify-category-api to CDK v2 ([#883](https://github.com/aws-amplify/amplify-category-api/issues/883)) ([2183f0f](https://github.com/aws-amplify/amplify-category-api/commit/2183f0f7144369cbcf6e7de3c8a2af7f5dc5b6b4)) - -# [5.1.0-beta.6](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.1.8...@aws-amplify/amplify-category-api@5.1.0-beta.6) (2023-02-21) - -### Bug Fixes - -- container api cfn generation ([#947](https://github.com/aws-amplify/amplify-category-api/issues/947)) ([0f675f2](https://github.com/aws-amplify/amplify-category-api/commit/0f675f222e24c07084b2907bc62024d7126f574e)) -- lock CDK v2 version ([#923](https://github.com/aws-amplify/amplify-category-api/issues/923)) ([2afe40c](https://github.com/aws-amplify/amplify-category-api/commit/2afe40cf13e7d1ee7db37988b9b3297768c7bd0a)) -- migrate to cdkv2 - e2e tests fixes ([#910](https://github.com/aws-amplify/amplify-category-api/issues/910)) ([c7b2503](https://github.com/aws-amplify/amplify-category-api/commit/c7b250361bf0c82fc067e03675101b9dfb6a25de)) -- preserve logical id patterns for dynamodb tables and search domain ([#894](https://github.com/aws-amplify/amplify-category-api/issues/894)) ([7530fc2](https://github.com/aws-amplify/amplify-category-api/commit/7530fc2e9254b621dc3782271318dd3f5c97d2b8)) -- throw error if invalid override or invalid custom stack error ([#982](https://github.com/aws-amplify/amplify-category-api/issues/982)) ([6dfeeba](https://github.com/aws-amplify/amplify-category-api/commit/6dfeeba627cd84a41eb8b4248856fa487c741f87)) - -### Features - -- migrate amplify-category-api to CDK v2 ([#883](https://github.com/aws-amplify/amplify-category-api/issues/883)) ([2183f0f](https://github.com/aws-amplify/amplify-category-api/commit/2183f0f7144369cbcf6e7de3c8a2af7f5dc5b6b4)) - -# [5.1.0-beta.5](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.1.8...@aws-amplify/amplify-category-api@5.1.0-beta.5) (2023-02-15) - -### Bug Fixes - -- container api cfn generation ([#947](https://github.com/aws-amplify/amplify-category-api/issues/947)) ([0f675f2](https://github.com/aws-amplify/amplify-category-api/commit/0f675f222e24c07084b2907bc62024d7126f574e)) -- lock CDK v2 version ([#923](https://github.com/aws-amplify/amplify-category-api/issues/923)) ([2afe40c](https://github.com/aws-amplify/amplify-category-api/commit/2afe40cf13e7d1ee7db37988b9b3297768c7bd0a)) -- migrate to cdkv2 - e2e tests fixes ([#910](https://github.com/aws-amplify/amplify-category-api/issues/910)) ([c7b2503](https://github.com/aws-amplify/amplify-category-api/commit/c7b250361bf0c82fc067e03675101b9dfb6a25de)) -- preserve logical id patterns for dynamodb tables and search domain ([#894](https://github.com/aws-amplify/amplify-category-api/issues/894)) ([7530fc2](https://github.com/aws-amplify/amplify-category-api/commit/7530fc2e9254b621dc3782271318dd3f5c97d2b8)) -- throw error if invalid override or invalid custom stack error ([#982](https://github.com/aws-amplify/amplify-category-api/issues/982)) ([6dfeeba](https://github.com/aws-amplify/amplify-category-api/commit/6dfeeba627cd84a41eb8b4248856fa487c741f87)) - -### Features - -- migrate amplify-category-api to CDK v2 ([#883](https://github.com/aws-amplify/amplify-category-api/issues/883)) ([2183f0f](https://github.com/aws-amplify/amplify-category-api/commit/2183f0f7144369cbcf6e7de3c8a2af7f5dc5b6b4)) - -# [5.1.0-beta.4](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.1.6...@aws-amplify/amplify-category-api@5.1.0-beta.4) (2023-02-03) - -### Bug Fixes - -- container api cfn generation ([#947](https://github.com/aws-amplify/amplify-category-api/issues/947)) ([0f675f2](https://github.com/aws-amplify/amplify-category-api/commit/0f675f222e24c07084b2907bc62024d7126f574e)) -- lock CDK v2 version ([#923](https://github.com/aws-amplify/amplify-category-api/issues/923)) ([2afe40c](https://github.com/aws-amplify/amplify-category-api/commit/2afe40cf13e7d1ee7db37988b9b3297768c7bd0a)) -- migrate to cdkv2 - e2e tests fixes ([#910](https://github.com/aws-amplify/amplify-category-api/issues/910)) ([c7b2503](https://github.com/aws-amplify/amplify-category-api/commit/c7b250361bf0c82fc067e03675101b9dfb6a25de)) -- preserve logical id patterns for dynamodb tables and search domain ([#894](https://github.com/aws-amplify/amplify-category-api/issues/894)) ([7530fc2](https://github.com/aws-amplify/amplify-category-api/commit/7530fc2e9254b621dc3782271318dd3f5c97d2b8)) -- throw error if invalid override or invalid custom stack error ([#982](https://github.com/aws-amplify/amplify-category-api/issues/982)) ([6dfeeba](https://github.com/aws-amplify/amplify-category-api/commit/6dfeeba627cd84a41eb8b4248856fa487c741f87)) - -### Features - -- migrate amplify-category-api to CDK v2 ([#883](https://github.com/aws-amplify/amplify-category-api/issues/883)) ([2183f0f](https://github.com/aws-amplify/amplify-category-api/commit/2183f0f7144369cbcf6e7de3c8a2af7f5dc5b6b4)) - -# [5.1.0-beta.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.1.2...@aws-amplify/amplify-category-api@5.1.0-beta.3) (2022-12-27) - -### Bug Fixes - -- container api cfn generation ([#947](https://github.com/aws-amplify/amplify-category-api/issues/947)) ([0f675f2](https://github.com/aws-amplify/amplify-category-api/commit/0f675f222e24c07084b2907bc62024d7126f574e)) -- lock CDK v2 version ([#923](https://github.com/aws-amplify/amplify-category-api/issues/923)) ([2afe40c](https://github.com/aws-amplify/amplify-category-api/commit/2afe40cf13e7d1ee7db37988b9b3297768c7bd0a)) -- migrate to cdkv2 - e2e tests fixes ([#910](https://github.com/aws-amplify/amplify-category-api/issues/910)) ([c7b2503](https://github.com/aws-amplify/amplify-category-api/commit/c7b250361bf0c82fc067e03675101b9dfb6a25de)) -- preserve logical id patterns for dynamodb tables and search domain ([#894](https://github.com/aws-amplify/amplify-category-api/issues/894)) ([7530fc2](https://github.com/aws-amplify/amplify-category-api/commit/7530fc2e9254b621dc3782271318dd3f5c97d2b8)) -- throw error if invalid override or invalid custom stack error ([#982](https://github.com/aws-amplify/amplify-category-api/issues/982)) ([6dfeeba](https://github.com/aws-amplify/amplify-category-api/commit/6dfeeba627cd84a41eb8b4248856fa487c741f87)) - -### Features - -- migrate amplify-category-api to CDK v2 ([#883](https://github.com/aws-amplify/amplify-category-api/issues/883)) ([2183f0f](https://github.com/aws-amplify/amplify-category-api/commit/2183f0f7144369cbcf6e7de3c8a2af7f5dc5b6b4)) - -# [5.1.0-beta.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.1.0-beta.0...@aws-amplify/amplify-category-api@5.1.0-beta.2) (2022-12-12) - -### Features - -- 🎸 Added bracket mismatch error detection ([40fdd88](https://github.com/aws-amplify/amplify-category-api/commit/40fdd885e5553ea4b087ff15b1305328a37fdecd)), closes [#107](https://github.com/aws-amplify/amplify-category-api/issues/107) - -# [5.1.0-beta.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.1.0-beta.0...@aws-amplify/amplify-category-api@5.1.0-beta.1) (2022-11-30) - -### Features - -- 🎸 Added bracket mismatch error detection ([40fdd88](https://github.com/aws-amplify/amplify-category-api/commit/40fdd885e5553ea4b087ff15b1305328a37fdecd)), closes [#107](https://github.com/aws-amplify/amplify-category-api/issues/107) - -# [5.1.0-beta.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.1.0-cdkv2.3...@aws-amplify/amplify-category-api@5.1.0-beta.0) (2022-11-18) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -# [5.1.0-cdkv2.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.0.9...@aws-amplify/amplify-category-api@5.1.0-cdkv2.3) (2022-11-15) - -### Bug Fixes - -- container api cfn generation ([#947](https://github.com/aws-amplify/amplify-category-api/issues/947)) ([0f675f2](https://github.com/aws-amplify/amplify-category-api/commit/0f675f222e24c07084b2907bc62024d7126f574e)) -- lock CDK v2 version ([#923](https://github.com/aws-amplify/amplify-category-api/issues/923)) ([2afe40c](https://github.com/aws-amplify/amplify-category-api/commit/2afe40cf13e7d1ee7db37988b9b3297768c7bd0a)) -- migrate to cdkv2 - e2e tests fixes ([#910](https://github.com/aws-amplify/amplify-category-api/issues/910)) ([c7b2503](https://github.com/aws-amplify/amplify-category-api/commit/c7b250361bf0c82fc067e03675101b9dfb6a25de)) -- preserve logical id patterns for dynamodb tables and search domain ([#894](https://github.com/aws-amplify/amplify-category-api/issues/894)) ([7530fc2](https://github.com/aws-amplify/amplify-category-api/commit/7530fc2e9254b621dc3782271318dd3f5c97d2b8)) -- throw error if invalid override or invalid custom stack error ([#982](https://github.com/aws-amplify/amplify-category-api/issues/982)) ([6dfeeba](https://github.com/aws-amplify/amplify-category-api/commit/6dfeeba627cd84a41eb8b4248856fa487c741f87)) - -### Features - -- migrate amplify-category-api to CDK v2 ([#883](https://github.com/aws-amplify/amplify-category-api/issues/883)) ([2183f0f](https://github.com/aws-amplify/amplify-category-api/commit/2183f0f7144369cbcf6e7de3c8a2af7f5dc5b6b4)) - -# [5.1.0-cdkv2.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.1.0-cdkv2.1...@aws-amplify/amplify-category-api@5.1.0-cdkv2.2) (2022-11-03) - -### Bug Fixes - -- container api cfn generation ([#947](https://github.com/aws-amplify/amplify-category-api/issues/947)) ([0f675f2](https://github.com/aws-amplify/amplify-category-api/commit/0f675f222e24c07084b2907bc62024d7126f574e)) - -# [5.1.0-cdkv2.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@5.1.0-cdkv2.0...@aws-amplify/amplify-category-api@5.1.0-cdkv2.1) (2022-10-24) - -### Bug Fixes - -- lock CDK v2 version ([#923](https://github.com/aws-amplify/amplify-category-api/issues/923)) ([2afe40c](https://github.com/aws-amplify/amplify-category-api/commit/2afe40cf13e7d1ee7db37988b9b3297768c7bd0a)) - -# [5.1.0-cdkv2.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.0.5...@aws-amplify/amplify-category-api@5.1.0-cdkv2.0) (2022-10-24) - -### Bug Fixes - -- **graphql:** add rds datasource v1 fix ([#853](https://github.com/aws-amplify/amplify-category-api/issues/853)) ([9bf32c2](https://github.com/aws-amplify/amplify-category-api/commit/9bf32c21f8e7e7ea6e8d602846c1128f38fb9897)) -- migrate to cdkv2 - e2e tests fixes ([#910](https://github.com/aws-amplify/amplify-category-api/issues/910)) ([c7b2503](https://github.com/aws-amplify/amplify-category-api/commit/c7b250361bf0c82fc067e03675101b9dfb6a25de)) -- preserve logical id patterns for dynamodb tables and search domain ([#894](https://github.com/aws-amplify/amplify-category-api/issues/894)) ([7530fc2](https://github.com/aws-amplify/amplify-category-api/commit/7530fc2e9254b621dc3782271318dd3f5c97d2b8)) - -### Features - -- migrate amplify-category-api to CDK v2 ([#883](https://github.com/aws-amplify/amplify-category-api/issues/883)) ([2183f0f](https://github.com/aws-amplify/amplify-category-api/commit/2183f0f7144369cbcf6e7de3c8a2af7f5dc5b6b4)) - -## [4.1.9](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.1.8...@aws-amplify/amplify-category-api@4.1.9) (2023-02-27) - -### Bug Fixes - -- **test:** update cli dependencies to use the cli rc packages ([#1294](https://github.com/aws-amplify/amplify-category-api/issues/1294)) ([7b13884](https://github.com/aws-amplify/amplify-category-api/commit/7b138841bf2c26fa16465ef263af0de7ce5a4122)) - -## [4.1.8](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.1.7...@aws-amplify/amplify-category-api@4.1.8) (2023-02-15) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [4.1.7](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.1.6...@aws-amplify/amplify-category-api@4.1.7) (2023-02-10) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [4.1.6](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.1.5...@aws-amplify/amplify-category-api@4.1.6) (2023-01-26) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [4.1.5](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.1.4...@aws-amplify/amplify-category-api@4.1.5) (2023-01-12) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [4.1.4](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.1.3...@aws-amplify/amplify-category-api@4.1.4) (2023-01-12) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [4.1.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.1.2...@aws-amplify/amplify-category-api@4.1.3) (2023-01-12) - -### Bug Fixes - -- disable searchable nodeToNode encryption unless it is already deployed to mitigate impact from enabling or disabling. ([#1152](https://github.com/aws-amplify/amplify-category-api/issues/1152)) ([4a1c360](https://github.com/aws-amplify/amplify-category-api/commit/4a1c36091cff6162b4803651b72ed03c594c01dc)) - -### Reverts - -- remove bracket check since it's causing customer issues in hosting ([44d6e89](https://github.com/aws-amplify/amplify-category-api/commit/44d6e8904b2698581bfd88b092587d00cbda50b7)) - -## [4.1.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.1.1...@aws-amplify/amplify-category-api@4.1.2) (2022-12-13) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [4.1.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.1.0...@aws-amplify/amplify-category-api@4.1.1) (2022-12-09) - -### Bug Fixes - -- add rdsRegion check back ([6d8736f](https://github.com/aws-amplify/amplify-category-api/commit/6d8736f8f29bbe6d3469e91adcb95ef6f9f8abe6)) -- address PR feedback ([2a119e6](https://github.com/aws-amplify/amplify-category-api/commit/2a119e6b8e86889b5f206f49b5063b4ce99ea859)) -- remove unused variable ([b419119](https://github.com/aws-amplify/amplify-category-api/commit/b41911975c6741c5b66e7cbcf4ca01af2a9e805a)) - -# [4.1.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.0.9...@aws-amplify/amplify-category-api@4.1.0) (2022-12-03) - -### Features - -- 🎸 Added bracket mismatch error detection ([40fdd88](https://github.com/aws-amplify/amplify-category-api/commit/40fdd885e5553ea4b087ff15b1305328a37fdecd)), closes [#107](https://github.com/aws-amplify/amplify-category-api/issues/107) - -## [4.0.9](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.0.8...@aws-amplify/amplify-category-api@4.0.9) (2022-11-08) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [4.0.8](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.0.7...@aws-amplify/amplify-category-api@4.0.8) (2022-11-04) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [4.0.7](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.0.6...@aws-amplify/amplify-category-api@4.0.7) (2022-10-26) - -### Bug Fixes - -- suppress CDK deprecation warnings ([d38930f](https://github.com/aws-amplify/amplify-category-api/commit/d38930fe7e563ca350999bb4c5433444f45a8290)) - -## [4.0.6](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.0.5...@aws-amplify/amplify-category-api@4.0.6) (2022-10-24) - -### Bug Fixes - -- **graphql:** add rds datasource v1 fix ([#853](https://github.com/aws-amplify/amplify-category-api/issues/853)) ([9bf32c2](https://github.com/aws-amplify/amplify-category-api/commit/9bf32c21f8e7e7ea6e8d602846c1128f38fb9897)) - -## [4.0.5](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.0.4...@aws-amplify/amplify-category-api@4.0.5) (2022-10-04) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [4.0.4](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.0.3...@aws-amplify/amplify-category-api@4.0.4) (2022-09-20) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [4.0.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.0.2...@aws-amplify/amplify-category-api@4.0.3) (2022-09-14) - -### Bug Fixes - -- **api:** gateway response dropping on update api ([#764](https://github.com/aws-amplify/amplify-category-api/issues/764)) ([942d1d1](https://github.com/aws-amplify/amplify-category-api/commit/942d1d18a4a6b09fe2fe23e3d48fe591a43abf9f)) - -## [4.0.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@4.0.1...@aws-amplify/amplify-category-api@4.0.2) (2022-08-23) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [4.0.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@3.1.10...@aws-amplify/amplify-category-api@4.0.1) (2022-08-18) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [3.1.10](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@3.1.9...@aws-amplify/amplify-category-api@3.1.10) (2022-08-18) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [3.1.9](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@3.1.8...@aws-amplify/amplify-category-api@3.1.9) (2022-08-18) - -### Bug Fixes - -- race condition provisioning default apigw responses ([#731](https://github.com/aws-amplify/amplify-category-api/issues/731)) ([a29b5e5](https://github.com/aws-amplify/amplify-category-api/commit/a29b5e5bf8522d493ce2753916d3f6b3703fb431)) - -## [3.1.8](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@3.1.7...@aws-amplify/amplify-category-api@3.1.8) (2022-08-16) - -### Bug Fixes - -- update api should allow setting NEW lambda conflict resolver ([10553ab](https://github.com/aws-amplify/amplify-category-api/commit/10553ab42b0ce56092c8006b728808d2b71fb412)) - -### Reverts - -- Revert "Feat: Single Source Read (#573)" ([726d45a](https://github.com/aws-amplify/amplify-category-api/commit/726d45a319d51124118d06145d4b2cd7522a1bd7)), closes [#573](https://github.com/aws-amplify/amplify-category-api/issues/573) -- Revert "Fix: add additional checks to resource dir cache" ([5d5255e](https://github.com/aws-amplify/amplify-category-api/commit/5d5255e3783f75ea5a7d6b4bf19853b5f81122f7)) -- Revert "Try to find the error" ([65d6289](https://github.com/aws-amplify/amplify-category-api/commit/65d628902f63dc6c32720a343e33a73cf8aa700c)) -- Revert "Try to find the error" ([a9a4808](https://github.com/aws-amplify/amplify-category-api/commit/a9a48080cd0da66e920509e30968cf2a87870a99)) - -## [3.1.7](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@3.1.6...@aws-amplify/amplify-category-api@3.1.7) (2022-08-04) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [3.1.6](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@3.1.5...@aws-amplify/amplify-category-api@3.1.6) (2022-07-26) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [3.1.5](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@3.1.3...@aws-amplify/amplify-category-api@3.1.5) (2022-07-20) - -### Bug Fixes - -- remove `gqlSchemaPath` in cli-inputs.json ([9400814](https://github.com/aws-amplify/amplify-category-api/commit/9400814dff0fead5ea0eaaf55078da876d7a4ae6)), closes [#123](https://github.com/aws-amplify/amplify-category-api/issues/123) -- update object reference to match cap change ([#627](https://github.com/aws-amplify/amplify-category-api/issues/627)) ([3ccdd9b](https://github.com/aws-amplify/amplify-category-api/commit/3ccdd9bc613a80c5cb08c6324332bc054a6bca6c)) - -## [3.1.4](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@3.1.3...@aws-amplify/amplify-category-api@3.1.4) (2022-07-14) - -### Bug Fixes - -- remove `gqlSchemaPath` in cli-inputs.json ([6356f8a](https://github.com/aws-amplify/amplify-category-api/commit/6356f8a62d4dad930777684b7484f65803bd4c20)), closes [#123](https://github.com/aws-amplify/amplify-category-api/issues/123) -- update object reference to match cap change ([#627](https://github.com/aws-amplify/amplify-category-api/issues/627)) ([8ad6a23](https://github.com/aws-amplify/amplify-category-api/commit/8ad6a237eb50bf20b5391d8b4a79991552676b49)) - -## [3.1.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@3.1.2...@aws-amplify/amplify-category-api@3.1.3) (2022-07-01) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [3.1.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@3.1.1...@aws-amplify/amplify-category-api@3.1.2) (2022-06-23) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [3.1.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@3.1.0...@aws-amplify/amplify-category-api@3.1.1) (2022-06-13) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -# [3.1.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@3.0.1...@aws-amplify/amplify-category-api@3.1.0) (2022-06-10) - -### Features - -- **amplify-category-api:** rename private packages to scope them down ([e131d06](https://github.com/aws-amplify/amplify-category-api/commit/e131d06463745d448a699e0e75eedd040c167d9d)) -- **amplify-category-api:** update descriptions to properly publish ([f685bbe](https://github.com/aws-amplify/amplify-category-api/commit/f685bbe52fd2d364e34c0ecb45c8a903555de3fe)) -- **amplify-category-api:** update yarn lock with dynamodb simulator version ([4dce641](https://github.com/aws-amplify/amplify-category-api/commit/4dce6411fbcd45c7f25db3383a0f1f21450738c0)) - -## [3.0.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@3.0.0...@aws-amplify/amplify-category-api@3.0.1) (2022-06-10) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -# [3.0.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/amplify-category-api@2.0.4...@aws-amplify/amplify-category-api@3.0.0) (2022-06-07) - -### Bug Fixes - -- [#429](https://github.com/aws-amplify/amplify-category-api/issues/429) - Editor hanging bug ([#2086](https://github.com/aws-amplify/amplify-category-api/issues/2086)) ([9f051bd](https://github.com/aws-amplify/amplify-category-api/commit/9f051bd94bcabfc0a6dd7910a118d50299dc5b7f)) -- [#6123](https://github.com/aws-amplify/amplify-category-api/issues/6123) - add missing amplify-cli-core dependencies to packages ([#6124](https://github.com/aws-amplify/amplify-category-api/issues/6124)) ([74e0475](https://github.com/aws-amplify/amplify-category-api/commit/74e04756249f61ffb135a9895deae1d0999db096)) -- [#8223](https://github.com/aws-amplify/amplify-category-api/issues/8223), conversion to typescript ([#8245](https://github.com/aws-amplify/amplify-category-api/issues/8245)) ([02bd3af](https://github.com/aws-amplify/amplify-category-api/commit/02bd3af425f63427a0d62268e3c527b35670113b)) -- add missing salt to deployment logicalId ([#9234](https://github.com/aws-amplify/amplify-category-api/issues/9234)) ([8e859ef](https://github.com/aws-amplify/amplify-category-api/commit/8e859ef9d1cfda88a9f93daa11d7a0f5bd7ff5cf)) -- add safety check ([#9193](https://github.com/aws-amplify/amplify-category-api/issues/9193)) ([cf7b88f](https://github.com/aws-amplify/amplify-category-api/commit/cf7b88faed5f02e861cb1d25a757762c1a7afaa4)) -- add support for mobile hub migrated resources ([#5407](https://github.com/aws-amplify/amplify-category-api/issues/5407)) ([e112f69](https://github.com/aws-amplify/amplify-category-api/commit/e112f697954b0a96791d116ef7d719dee5731ea0)) -- add-graphql-datasource command ([#9288](https://github.com/aws-amplify/amplify-category-api/issues/9288)) ([12bd5b3](https://github.com/aws-amplify/amplify-category-api/commit/12bd5b312bfa3203f996cba3847d4fb97cdaaaef)) -- added exit code on remove ([#5427](https://github.com/aws-amplify/amplify-category-api/issues/5427)) ([78dc91e](https://github.com/aws-amplify/amplify-category-api/commit/78dc91ee1918cce30de73f1e3626266cbe54dd9b)) -- allow api updates without migration ([#9864](https://github.com/aws-amplify/amplify-category-api/issues/9864)) ([9f1a9df](https://github.com/aws-amplify/amplify-category-api/commit/9f1a9df9fc4c34a13d00359be4f38ae3f4d29a21)) -- **amplify-category-api:** add check for provider during migration ([52abb85](https://github.com/aws-amplify/amplify-category-api/commit/52abb85b3781c1c773245780daa02c696455297a)), closes [#918](https://github.com/aws-amplify/amplify-category-api/issues/918) -- **amplify-category-api:** add config check in writeResolverConfig ([22e6e9b](https://github.com/aws-amplify/amplify-category-api/commit/22e6e9b78e6e47b6bed7070002e1d082a290dae4)) -- **amplify-category-api:** added check to read schema in schema dir ([#3871](https://github.com/aws-amplify/amplify-category-api/issues/3871)) ([dc077d8](https://github.com/aws-amplify/amplify-category-api/commit/dc077d8ee9d9dd929d7428eb3d8e5c8cc24372c1)), closes [fixes#3082](https://github.com/fixes/issues/3082) -- **amplify-category-api:** change auth directive type and fix codegen bug ([#8639](https://github.com/aws-amplify/amplify-category-api/issues/8639)) ([e1fc46a](https://github.com/aws-amplify/amplify-category-api/commit/e1fc46a250c8d54c59f2beb42d188bc60b3e0dae)) -- **amplify-category-api:** edit auth workflow if cognito is not used ([#3232](https://github.com/aws-amplify/amplify-category-api/issues/3232)) ([8313093](https://github.com/aws-amplify/amplify-category-api/commit/8313093922a6badb7f725f26c6ff472d6f6a1b9a)), closes [#2967](https://github.com/aws-amplify/amplify-category-api/issues/2967) -- **amplify-category-api:** Fix [#2498](https://github.com/aws-amplify/amplify-category-api/issues/2498) ([#2503](https://github.com/aws-amplify/amplify-category-api/issues/2503)) ([36dab68](https://github.com/aws-amplify/amplify-category-api/commit/36dab68d3913106e54fbce22fa9c7a4538793d72)) -- **amplify-category-api:** fix api add-graphql-datasource command ([#2320](https://github.com/aws-amplify/amplify-category-api/issues/2320)) ([0586b6c](https://github.com/aws-amplify/amplify-category-api/commit/0586b6c55c7f8c76feaf1ce215fe3052b22236c1)) -- **amplify-category-api:** fix conflict resolution learn more ([#2954](https://github.com/aws-amplify/amplify-category-api/issues/2954)) ([cc0e428](https://github.com/aws-amplify/amplify-category-api/commit/cc0e428f8aeec73d47dce2b4c8cf32c1cc5bdbc7)) -- **amplify-category-api:** fix init env bug ([#1715](https://github.com/aws-amplify/amplify-category-api/issues/1715)) ([8ee27bb](https://github.com/aws-amplify/amplify-category-api/commit/8ee27bb910499d9326a80488551e41e100623344)), closes [#1713](https://github.com/aws-amplify/amplify-category-api/issues/1713) -- **amplify-category-api:** fixed api to reference stack name and deployment bucket ([#8145](https://github.com/aws-amplify/amplify-category-api/issues/8145)) ([6148835](https://github.com/aws-amplify/amplify-category-api/commit/61488351e72ebd83c75443a1952e47a013e9a32c)) -- **amplify-category-api:** include userpool id in parameter.json ([#2238](https://github.com/aws-amplify/amplify-category-api/issues/2238)) ([2da6916](https://github.com/aws-amplify/amplify-category-api/commit/2da6916581ce0637e6e9f96b8c76113697439f21)) -- **amplify-category-api:** mantain ff in iam api policy ([#6723](https://github.com/aws-amplify/amplify-category-api/issues/6723)) ([c3538f5](https://github.com/aws-amplify/amplify-category-api/commit/c3538f579c7d574a0c2b0dccde7a9a3c2860f22c)), closes [#6675](https://github.com/aws-amplify/amplify-category-api/issues/6675) -- **amplify-category-api:** plumb api id to resources that require it ([#3464](https://github.com/aws-amplify/amplify-category-api/issues/3464)) ([7d04381](https://github.com/aws-amplify/amplify-category-api/commit/7d04381fe8aabdda322589058209b27181390c28)), closes [#3431](https://github.com/aws-amplify/amplify-category-api/issues/3431) [#3386](https://github.com/aws-amplify/amplify-category-api/issues/3386) -- **amplify-category-api:** remove stack trace from printout for api ([#9877](https://github.com/aws-amplify/amplify-category-api/issues/9877)) ([449a7d2](https://github.com/aws-amplify/amplify-category-api/commit/449a7d2e4b2f7d810a88801e0b5f6714b16219b6)) -- **amplify-category-api:** safeguard prompt with empty options ([#2430](https://github.com/aws-amplify/amplify-category-api/issues/2430)) ([b64cea0](https://github.com/aws-amplify/amplify-category-api/commit/b64cea0b7a3f4a42dcc628315145040ee50c3bb5)), closes [#2423](https://github.com/aws-amplify/amplify-category-api/issues/2423) -- **amplify-category-api:** surface override build errors for REST APIs ([#9804](https://github.com/aws-amplify/amplify-category-api/issues/9804)) ([c159213](https://github.com/aws-amplify/amplify-category-api/commit/c1592132e0a5f1df4df4094ff2617596b6d1519a)) -- **amplify-category-api:** toggle datastore in update ([#4276](https://github.com/aws-amplify/amplify-category-api/issues/4276)) ([0feefcd](https://github.com/aws-amplify/amplify-category-api/commit/0feefcdcbef1939ff1ad0a9f57da35d8249e67ce)), closes [#4058](https://github.com/aws-amplify/amplify-category-api/issues/4058) -- **amplify-category-api:** use standard json read ([#2581](https://github.com/aws-amplify/amplify-category-api/issues/2581)) ([a71f5b7](https://github.com/aws-amplify/amplify-category-api/commit/a71f5b7762f9f54c3113afbccae99c5ec729f8ac)) -- **amplify-provider-awscloudformation:** apigw unauth access ([#1906](https://github.com/aws-amplify/amplify-category-api/issues/1906)) ([4ea0bb2](https://github.com/aws-amplify/amplify-category-api/commit/4ea0bb23f424be243d5c28fc61f24e2ed4f83b54)) -- api containers on repushing does not fail ([#8416](https://github.com/aws-amplify/amplify-category-api/issues/8416)) ([086c021](https://github.com/aws-amplify/amplify-category-api/commit/086c02130a037c2f36667cb0c69db47f2a25c71a)) -- api resource name case sensitivity failure ([#7452](https://github.com/aws-amplify/amplify-category-api/issues/7452)) ([7900ba3](https://github.com/aws-amplify/amplify-category-api/commit/7900ba398cf585e5a5c4105f3dca91b0a60625a2)) -- api sets auth dependency correctly in meta files ([#10072](https://github.com/aws-amplify/amplify-category-api/issues/10072)) ([c27656f](https://github.com/aws-amplify/amplify-category-api/commit/c27656fc97a70cd72f746ad0ed689da82fecaea5)) -- **api:** container rest api push treats incorrect initial push behavior ([#9556](https://github.com/aws-amplify/amplify-category-api/issues/9556)) ([b17baf4](https://github.com/aws-amplify/amplify-category-api/commit/b17baf4d5301e6506af4322663c63ab9251a0ac9)) -- **api:** container secrets pickup correct environment values ([#9513](https://github.com/aws-amplify/amplify-category-api/issues/9513)) ([0b6977a](https://github.com/aws-amplify/amplify-category-api/commit/0b6977a8d02e0ddff50c1c748cb25a086128a4c7)) -- asana bug fixes ([#8692](https://github.com/aws-amplify/amplify-category-api/issues/8692)) ([a72103c](https://github.com/aws-amplify/amplify-category-api/commit/a72103c6ca9eeafef1a29f356e238a1b18ecfe3a)) -- broken path on build-override ([cd17151](https://github.com/aws-amplify/amplify-category-api/commit/cd1715176d240323eb97f0bb6b8e6cac3c93711b)) -- call the correct migration function for Admin Queries ([#9174](https://github.com/aws-amplify/amplify-category-api/issues/9174)) ([2c8e8da](https://github.com/aws-amplify/amplify-category-api/commit/2c8e8dabca19f6fddc561e7d27d944caa0d09ee6)) -- capitalization for filter, e2e test ([#8667](https://github.com/aws-amplify/amplify-category-api/issues/8667)) ([edc04ad](https://github.com/aws-amplify/amplify-category-api/commit/edc04adbbff53d777dc4937581bbec9b7ca3016f)) -- carry existing container secret config over ([#7224](https://github.com/aws-amplify/amplify-category-api/issues/7224)) ([2ef548d](https://github.com/aws-amplify/amplify-category-api/commit/2ef548d6991e1d08d7d670013e4e1f6b6201174c)) -- change default length for api key back to 7 days ([#2507](https://github.com/aws-amplify/amplify-category-api/issues/2507)) ([7a4083f](https://github.com/aws-amplify/amplify-category-api/commit/7a4083f9bc85b80e63d6ecd7b6053681ae2edecb)) -- checking undefined auth config ([#5313](https://github.com/aws-amplify/amplify-category-api/issues/5313)) ([ab3fc14](https://github.com/aws-amplify/amplify-category-api/commit/ab3fc147d272b1fe9e91337ab258ed77392c78dc)) -- **cli:** add console command in the help message ([#2494](https://github.com/aws-amplify/amplify-category-api/issues/2494)) ([2477171](https://github.com/aws-amplify/amplify-category-api/commit/2477171634481c55e74388819dbf1262d9eadd99)), closes [#1607](https://github.com/aws-amplify/amplify-category-api/issues/1607) -- **cli:** deleting the amplify app on delete ([#3568](https://github.com/aws-amplify/amplify-category-api/issues/3568)) ([1428403](https://github.com/aws-amplify/amplify-category-api/commit/1428403b7e96eaae0117252566430c20e67c1c14)), closes [#3239](https://github.com/aws-amplify/amplify-category-api/issues/3239) -- **cli:** fix inquirer version ([#1690](https://github.com/aws-amplify/amplify-category-api/issues/1690)) ([a2ac1a7](https://github.com/aws-amplify/amplify-category-api/commit/a2ac1a7baa1ec7b10a75ba68f2074dc8f9e7eb50)), closes [#1688](https://github.com/aws-amplify/amplify-category-api/issues/1688) -- **cli:** remove calls to gluegun's prompt.confirm ([#546](https://github.com/aws-amplify/amplify-category-api/issues/546)) ([3e9e924](https://github.com/aws-amplify/amplify-category-api/commit/3e9e924f131682390e738eee955cda0143e97c6d)) -- **cli:** remove unnecessary stack trace log when adding services ([#4610](https://github.com/aws-amplify/amplify-category-api/issues/4610)) ([ae49ffc](https://github.com/aws-amplify/amplify-category-api/commit/ae49ffcd845ae5047366d6b501321ce55f81c4a8)) -- **cli:** use more inclusive language ([#6919](https://github.com/aws-amplify/amplify-category-api/issues/6919)) ([1c42597](https://github.com/aws-amplify/amplify-category-api/commit/1c42597fb25d5fc58c65d2d8d5f319736c67ab2b)) -- conditionally rebuild container apis on push ([#7175](https://github.com/aws-amplify/amplify-category-api/issues/7175)) ([44f7c02](https://github.com/aws-amplify/amplify-category-api/commit/44f7c028073076c1ab1b32d579724d44d510c714)) -- console override build issue ([#9078](https://github.com/aws-amplify/amplify-category-api/issues/9078)) ([02d13a8](https://github.com/aws-amplify/amplify-category-api/commit/02d13a800659b5805d4dca58746dc87b11ae0355)) -- consolidate REST API IAM policies ([#6904](https://github.com/aws-amplify/amplify-category-api/issues/6904)) (ref [#2084](https://github.com/aws-amplify/amplify-category-api/issues/2084)) ([2820ba7](https://github.com/aws-amplify/amplify-category-api/commit/2820ba7157ece78d08c598c30eb7c011176da839)) -- **container-api:** upgrade flask version for the python api ([#10077](https://github.com/aws-amplify/amplify-category-api/issues/10077)) ([4df2e94](https://github.com/aws-amplify/amplify-category-api/commit/4df2e94042599a67b973f9f1cb043368d919a923)) -- **container-hosting:** ignore test cases ([#7895](https://github.com/aws-amplify/amplify-category-api/issues/7895)) ([939e4f3](https://github.com/aws-amplify/amplify-category-api/commit/939e4f33b0e9dda38b0912b8887730308e63211c)) -- containers - don't wait for pipeline on hosting ([#6137](https://github.com/aws-amplify/amplify-category-api/issues/6137)) ([7841db2](https://github.com/aws-amplify/amplify-category-api/commit/7841db2a9860d9e009cebded1e198946da1d51eb)) -- data inconsitency ([#5344](https://github.com/aws-amplify/amplify-category-api/issues/5344)) ([867a959](https://github.com/aws-amplify/amplify-category-api/commit/867a9596f6d98fb52db5b1db46c9298b6a273dde)) -- expand region support for aurora serverless ([#8577](https://github.com/aws-amplify/amplify-category-api/issues/8577)) ([430e10c](https://github.com/aws-amplify/amplify-category-api/commit/430e10c729c0e8fc00f22df66f3df98fdc4eefb6)) -- fix appsync permission assignment from functions ([#5342](https://github.com/aws-amplify/amplify-category-api/issues/5342)) ([f48a32d](https://github.com/aws-amplify/amplify-category-api/commit/f48a32d25544bd05944be7e5bd568037818708bd)) -- fixing the IAM policies for AppSync API ([#1634](https://github.com/aws-amplify/amplify-category-api/issues/1634)) ([50b6ed5](https://github.com/aws-amplify/amplify-category-api/commit/50b6ed535848eb71682ea8ff36c24da5dd56cedd)) -- **graphql-auth-transformer:** add a time delay when creating apiKey ([#4493](https://github.com/aws-amplify/amplify-category-api/issues/4493)) ([6c980fa](https://github.com/aws-amplify/amplify-category-api/commit/6c980fa4e6e535d6e8224ffa419b788512064dd1)) -- **graphql-elasticsearch-transformer:** fix duplicate records in es lambda ([#3712](https://github.com/aws-amplify/amplify-category-api/issues/3712)) ([ca78270](https://github.com/aws-amplify/amplify-category-api/commit/ca78270d123982e03d942afe69ec6fce501427a2)), closes [#3602](https://github.com/aws-amplify/amplify-category-api/issues/3602) [#3705](https://github.com/aws-amplify/amplify-category-api/issues/3705) -- **graphql-model-transformer:** fixed schema template options check for transformer version ([#8449](https://github.com/aws-amplify/amplify-category-api/issues/8449)) ([b804c84](https://github.com/aws-amplify/amplify-category-api/commit/b804c8497bc754ddb20a79227639c7ba73ea3fd5)) -- **graphql-model-transformer:** model input fields transform ([#7857](https://github.com/aws-amplify/amplify-category-api/issues/7857)) ([165772e](https://github.com/aws-amplify/amplify-category-api/commit/165772e6f4e73dd5b8921637a5189576662ba316)) -- **graphql-transformer-common:** improve generated graphql pluralization ([#7258](https://github.com/aws-amplify/amplify-category-api/issues/7258)) ([9db4b2e](https://github.com/aws-amplify/amplify-category-api/commit/9db4b2e6c8573066aa3d4c1973508640a6cccdd3)), closes [#4224](https://github.com/aws-amplify/amplify-category-api/issues/4224) -- **graphql:** detect resource update on graphql api auth mode change ([#8782](https://github.com/aws-amplify/amplify-category-api/issues/8782)) ([1e9ee86](https://github.com/aws-amplify/amplify-category-api/commit/1e9ee8618d1c9a954cf7bbf6f8f617077357e27f)) -- **graphql:** lambda auth label fix ([#8623](https://github.com/aws-amplify/amplify-category-api/issues/8623)) ([7089114](https://github.com/aws-amplify/amplify-category-api/commit/70891148dcc3952257549254301ac66443c2ed06)) -- **graphql:** minor api prompt fixes ([#8603](https://github.com/aws-amplify/amplify-category-api/issues/8603)) ([21d2078](https://github.com/aws-amplify/amplify-category-api/commit/21d2078fbbe1b017a7b7fba57b942570f9302363)) -- **graphql:** refactor lambda authorizer code to use function category to create authorizer function ([#8784](https://github.com/aws-amplify/amplify-category-api/issues/8784)) ([5a4fc2e](https://github.com/aws-amplify/amplify-category-api/commit/5a4fc2ee16a4848b3ac699ea3caf719a1765148c)) -- handle auth and api dependency in state files correctly ([#9528](https://github.com/aws-amplify/amplify-category-api/issues/9528)) ([ab17d21](https://github.com/aws-amplify/amplify-category-api/commit/ab17d219d8d4b799c9ff5cd6f25af514d3f36760)), closes [#9341](https://github.com/aws-amplify/amplify-category-api/issues/9341) -- handle errors and provide better error message when adding data source ([#7117](https://github.com/aws-amplify/amplify-category-api/issues/7117)) (ref [#4384](https://github.com/aws-amplify/amplify-category-api/issues/4384)) ([b583d8d](https://github.com/aws-amplify/amplify-category-api/commit/b583d8d13d2e90c8bc97ff011453072de77df1ab)) -- improve api migration logic, update migration prompt ([#9267](https://github.com/aws-amplify/amplify-category-api/issues/9267)) ([8f0b72a](https://github.com/aws-amplify/amplify-category-api/commit/8f0b72ae36bedce6bd03b9cbdf5cfc442f8f1cce)) -- incorrect type on graphql boilerplate schema ([#4070](https://github.com/aws-amplify/amplify-category-api/issues/4070)) ([8bd0e4e](https://github.com/aws-amplify/amplify-category-api/commit/8bd0e4e6c87cdc31d87b951ed429a02835a7e977)) -- lambda timeout should be an integer type ([#7699](https://github.com/aws-amplify/amplify-category-api/issues/7699)) ([30ed3f4](https://github.com/aws-amplify/amplify-category-api/commit/30ed3f4772a0eb321ef106199cb623a083ffd71d)) -- make ECR repository name validation more strict ([#7337](https://github.com/aws-amplify/amplify-category-api/issues/7337)) ([009ffe6](https://github.com/aws-amplify/amplify-category-api/commit/009ffe64ae3016324dca1529249e9664fd91d434)) -- migrate rest apis with protected routes on push ([#9068](https://github.com/aws-amplify/amplify-category-api/issues/9068)) ([aac2fbb](https://github.com/aws-amplify/amplify-category-api/commit/aac2fbb7af01f3ec2c95381bfcab6135bcbca7be)) -- move test package dependencies to devDependencies ([#2034](https://github.com/aws-amplify/amplify-category-api/issues/2034)) ([646d21d](https://github.com/aws-amplify/amplify-category-api/commit/646d21ddc3ec28951487cb38a43a05bc5610271b)) -- multi-env container hosting ([#7009](https://github.com/aws-amplify/amplify-category-api/issues/7009)) ([#7346](https://github.com/aws-amplify/amplify-category-api/issues/7346)) ([0e2edac](https://github.com/aws-amplify/amplify-category-api/commit/0e2edacbde06d2c0b8626c7ed56b675f44f6976d)) -- only ignore root src folder ([#6136](https://github.com/aws-amplify/amplify-category-api/issues/6136)) ([d5c63e6](https://github.com/aws-amplify/amplify-category-api/commit/d5c63e6af163f0bfa6602fedc7b02c49abb221ff)) -- opensearch instance type check during push ([#10389](https://github.com/aws-amplify/amplify-category-api/issues/10389)) ([2ca26c9](https://github.com/aws-amplify/amplify-category-api/commit/2ca26c9f66fabd6c988ee585e23f3312956498b6)) -- populate API_KEY env var when present ([#4923](https://github.com/aws-amplify/amplify-category-api/issues/4923)) ([4baacec](https://github.com/aws-amplify/amplify-category-api/commit/4baacec6f22d1ec92138255a894a6fd07b1f0c0c)) -- pushing multiple APIs at a time ([#8663](https://github.com/aws-amplify/amplify-category-api/issues/8663)) ([839d852](https://github.com/aws-amplify/amplify-category-api/commit/839d852196eac97181435f460b380696ea28b066)) -- refactor mobile hub migration checks ([#5632](https://github.com/aws-amplify/amplify-category-api/issues/5632)) ([440e071](https://github.com/aws-amplify/amplify-category-api/commit/440e07117d09b36072d9b71f9caa4c1b5484652d)) -- remove await from sync read cfn calls ([#8977](https://github.com/aws-amplify/amplify-category-api/issues/8977)) ([452fece](https://github.com/aws-amplify/amplify-category-api/commit/452fece5eb75445e8f6ce8f2450eff7e251b403e)) -- remove duplicate error messages ([#8651](https://github.com/aws-amplify/amplify-category-api/issues/8651)) ([772ae5a](https://github.com/aws-amplify/amplify-category-api/commit/772ae5a8fc8bfc063c347ac9e07233570b3a8630)) -- remove mutableParametersState from stored function-params ([#4897](https://github.com/aws-amplify/amplify-category-api/issues/4897)) ([544cb0b](https://github.com/aws-amplify/amplify-category-api/commit/544cb0b50194d7c20a5063c6b058e26499028787)) -- remove process on next and await ([#6239](https://github.com/aws-amplify/amplify-category-api/issues/6239)) ([536e8b0](https://github.com/aws-amplify/amplify-category-api/commit/536e8b0706fe4f4b8c66ffa69e5cec2bb4aea483)) -- remove prompt from rds headless pull ([#10239](https://github.com/aws-amplify/amplify-category-api/issues/10239)) ([5469ef8](https://github.com/aws-amplify/amplify-category-api/commit/5469ef8ebb7e3725f16a08f69d6f5b92c48e124a)) -- removes duplicate auth types ([#5272](https://github.com/aws-amplify/amplify-category-api/issues/5272)) ([d470a72](https://github.com/aws-amplify/amplify-category-api/commit/d470a72d575cba8c43d5e8d91ddecc8d00f262a3)) -- rest api override CloudFormation parameters ([#9325](https://github.com/aws-amplify/amplify-category-api/issues/9325)) ([842a75b](https://github.com/aws-amplify/amplify-category-api/commit/842a75b2fa8bc393011f8b2c61ecf3459b503a85)), closes [#9221](https://github.com/aws-amplify/amplify-category-api/issues/9221) -- return undefined for empty conflict resolution ([#4982](https://github.com/aws-amplify/amplify-category-api/issues/4982)) ([1ccfb70](https://github.com/aws-amplify/amplify-category-api/commit/1ccfb7098c87c476af14976cfd27380f6bb76736)), closes [#4965](https://github.com/aws-amplify/amplify-category-api/issues/4965) -- root path handling for REST APIs ([#9842](https://github.com/aws-amplify/amplify-category-api/issues/9842)) ([af5fa1d](https://github.com/aws-amplify/amplify-category-api/commit/af5fa1d702d724f6aa78e33c49e262ef4bd3f3dd)) -- schema migrator utility as separate command ([#8720](https://github.com/aws-amplify/amplify-category-api/issues/8720)) ([60bf68c](https://github.com/aws-amplify/amplify-category-api/commit/60bf68c1031875ee96dac17b59222a83ac951c39)) -- sets policy resource name in api update flow ([14a1ed7](https://github.com/aws-amplify/amplify-category-api/commit/14a1ed7165ccf72c773b16a19458cfdc081e4b8e)) -- split policies for both legacy and migrated REST APIs ([#9572](https://github.com/aws-amplify/amplify-category-api/issues/9572)) ([7f70fb0](https://github.com/aws-amplify/amplify-category-api/commit/7f70fb0d7f62e8466c56bdb26b1d8c800807bb61)) -- stack generation logic when multiple paths ref same Lambda ([#8673](https://github.com/aws-amplify/amplify-category-api/issues/8673)) ([24d02fa](https://github.com/aws-amplify/amplify-category-api/commit/24d02faae31543e7f84100bf71b117383a1144d8)) -- sub \* for path parms in CFN policy ([#5092](https://github.com/aws-amplify/amplify-category-api/issues/5092)) ([cf42d05](https://github.com/aws-amplify/amplify-category-api/commit/cf42d05aaf8eed5715391b1b4137d4b73fcf2a95)) -- support adding REST API paths in 'add api' ([#7229](https://github.com/aws-amplify/amplify-category-api/issues/7229)) ([28f9bc6](https://github.com/aws-amplify/amplify-category-api/commit/28f9bc617ccfeebe99329a3daf744c21515ec1cb)) -- transformer version ([#9092](https://github.com/aws-amplify/amplify-category-api/issues/9092)) ([1f1fef9](https://github.com/aws-amplify/amplify-category-api/commit/1f1fef9d6b0368e89c61dd9b6d8680c34bb08a32)) -- unique api name check works when no existing apis ([#7615](https://github.com/aws-amplify/amplify-category-api/issues/7615)) ([d8eade3](https://github.com/aws-amplify/amplify-category-api/commit/d8eade3be250eb41ea167f4c6aab9eaca9524ecb)) -- update CLI to handle UTF8 BOM ([#1357](https://github.com/aws-amplify/amplify-category-api/issues/1357)) ([0e3475d](https://github.com/aws-amplify/amplify-category-api/commit/0e3475dfdf4dcd575dc00c5a4a67c4c042546fa0)), closes [#1355](https://github.com/aws-amplify/amplify-category-api/issues/1355) [#1122](https://github.com/aws-amplify/amplify-category-api/issues/1122) -- update dep and use node test environment ([#9434](https://github.com/aws-amplify/amplify-category-api/issues/9434)) ([b3a814b](https://github.com/aws-amplify/amplify-category-api/commit/b3a814b35b85be57f34e012ed9d78391971c0a27)) -- update graphql schema to match docs ([#3652](https://github.com/aws-amplify/amplify-category-api/issues/3652)) ([886c77f](https://github.com/aws-amplify/amplify-category-api/commit/886c77f12b81efd49ac478759cfef0c56a9df23a)), closes [#3513](https://github.com/aws-amplify/amplify-category-api/issues/3513) -- update overlapping REST path warning ([#7276](https://github.com/aws-amplify/amplify-category-api/issues/7276)) ([e79c262](https://github.com/aws-amplify/amplify-category-api/commit/e79c26225b67760d23bafb315507339dcca781da)) -- use \_\_dirname instead of '.' in import path ([#9105](https://github.com/aws-amplify/amplify-category-api/issues/9105)) ([1b342bb](https://github.com/aws-amplify/amplify-category-api/commit/1b342bb4330db76d2cac274c4823ebafd2f1bb56)) -- use prompter and handle deletions ([#10122](https://github.com/aws-amplify/amplify-category-api/issues/10122)) ([16b4358](https://github.com/aws-amplify/amplify-category-api/commit/16b4358ea95af395bbad4e46bc23f45805c26a44)) -- validatePathName_validPath matcher ([#4559](https://github.com/aws-amplify/amplify-category-api/issues/4559)) ([936ee53](https://github.com/aws-amplify/amplify-category-api/commit/936ee53860716545fb3cf11fd1b9ff914f9f614f)) -- wording: Enable, instead of Configure, conflict detection ([#6708](https://github.com/aws-amplify/amplify-category-api/issues/6708)) ([941a887](https://github.com/aws-amplify/amplify-category-api/commit/941a887b03468bbc2e81f98d04a0b1cb35382095)) - -### Features - -- add a warning on migration and force compile gql schema ([6ee1d2a](https://github.com/aws-amplify/amplify-category-api/commit/6ee1d2a3a80c98a09ea50d69a7ff8989d57b572a)) -- add graphQLEndpoint as an env var to lambda functions ([#1641](https://github.com/aws-amplify/amplify-category-api/issues/1641)) ([203ca3d](https://github.com/aws-amplify/amplify-category-api/commit/203ca3d543a34ab4a59b7b2886d74cdad45c9a66)), closes [#1620](https://github.com/aws-amplify/amplify-category-api/issues/1620) -- add option to open AppSync console using the CLI ([#386](https://github.com/aws-amplify/amplify-category-api/issues/386)) ([a13b19a](https://github.com/aws-amplify/amplify-category-api/commit/a13b19ab66cc7cff5044ca495214408f322d3bd9)) -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-category-api/issues/1936)) ([e1610bf](https://github.com/aws-amplify/amplify-category-api/commit/e1610bf53b1955babad4b69542f241855f65d272)) -- allow 3rd-party plugins to CDK override ([#9601](https://github.com/aws-amplify/amplify-category-api/issues/9601)) ([a179a32](https://github.com/aws-amplify/amplify-category-api/commit/a179a32bd86333a0a32cee2dfc7b60da792b72c5)) -- allow creation of REST API endpoint at root path (/) ([#4649](https://github.com/aws-amplify/amplify-category-api/issues/4649)) ([a671471](https://github.com/aws-amplify/amplify-category-api/commit/a67147185b4bc7f2e3ce8bd9489c371ac25f15fc)), closes [#3868](https://github.com/aws-amplify/amplify-category-api/issues/3868) [#4834](https://github.com/aws-amplify/amplify-category-api/issues/4834) -- allows adding graphql datasource with an empty graphql schema file ([#4464](https://github.com/aws-amplify/amplify-category-api/issues/4464)) ([e63c332](https://github.com/aws-amplify/amplify-category-api/commit/e63c332143ad969fff0298f6d952e19606092eac)) -- **amplify-category-api:** add rds support for new regions ([#5360](https://github.com/aws-amplify/amplify-category-api/issues/5360)) ([e82db85](https://github.com/aws-amplify/amplify-category-api/commit/e82db853a68a48fa888deb5fe88708efa668e974)), closes [#4739](https://github.com/aws-amplify/amplify-category-api/issues/4739) -- **amplify-category-api:** allow minified CF stack templates ([#3520](https://github.com/aws-amplify/amplify-category-api/issues/3520)) ([e7bee30](https://github.com/aws-amplify/amplify-category-api/commit/e7bee305f49e7f21d18369530c75f9c755ba533c)), closes [#2914](https://github.com/aws-amplify/amplify-category-api/issues/2914) -- **amplify-category-api:** enable default 4xx and 5xx api gateway cors response ([#9158](https://github.com/aws-amplify/amplify-category-api/issues/9158)) ([d0f4e32](https://github.com/aws-amplify/amplify-category-api/commit/d0f4e3223c4e724cad6a792927cbc0b458b58517)), closes [#5183](https://github.com/aws-amplify/amplify-category-api/issues/5183) -- **amplify-category-api:** support path parameters in REST APIs ([#3394](https://github.com/aws-amplify/amplify-category-api/issues/3394)) ([1bea981](https://github.com/aws-amplify/amplify-category-api/commit/1bea98120d244220a82f4e2d6f4310313ac15635)) -- **amplify-category-function:** refactor to support runtime and template plugins ([#3517](https://github.com/aws-amplify/amplify-category-api/issues/3517)) ([c4de09e](https://github.com/aws-amplify/amplify-category-api/commit/c4de09e8477b04c509b294fbf78b1baac8320cd8)) -- **amplify-provider-awscloudformation:** change global_auth_rule to globalAuthRule for global auth ([#8674](https://github.com/aws-amplify/amplify-category-api/issues/8674)) ([1f5d061](https://github.com/aws-amplify/amplify-category-api/commit/1f5d061c6db581236ef9ff977561883fb257e7b8)) -- **amplify-provider-awscloudformation:** change sandbox mode syntax in schema ([#8592](https://github.com/aws-amplify/amplify-category-api/issues/8592)) ([fe5cd3a](https://github.com/aws-amplify/amplify-category-api/commit/fe5cd3a08f277853d6efb4da1f1ae7e92b417739)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-category-api/issues/2742)) ([f8a6008](https://github.com/aws-amplify/amplify-category-api/commit/f8a60086157c1a5157f7186327048721fb7222fc)) -- **cli:** new plugin platform ([#2254](https://github.com/aws-amplify/amplify-category-api/issues/2254)) ([c326184](https://github.com/aws-amplify/amplify-category-api/commit/c326184051cd7eca9538f2128ee2ea17ca117266)) -- **cli:** usage measurement ([#3641](https://github.com/aws-amplify/amplify-category-api/issues/3641)) ([5e08167](https://github.com/aws-amplify/amplify-category-api/commit/5e081678466f91324dd1e9200c375458455c7c48)) -- conditions update ([#2789](https://github.com/aws-amplify/amplify-category-api/issues/2789)) ([b5811d5](https://github.com/aws-amplify/amplify-category-api/commit/b5811d5ad01b8db0f5c75a8b69f6b9bf9009f006)) -- container-based deployments([#5727](https://github.com/aws-amplify/amplify-category-api/issues/5727)) ([772ee60](https://github.com/aws-amplify/amplify-category-api/commit/772ee60335cba121547d9f4a4ba24bf7d6e5ce02)) -- Custom policies IAM Policies for Lambda and Containers ([#8068](https://github.com/aws-amplify/amplify-category-api/issues/8068)) ([692a947](https://github.com/aws-amplify/amplify-category-api/commit/692a94775055666ca5b901066c3ace7d001dfa3f)) -- Delete all ([#2615](https://github.com/aws-amplify/amplify-category-api/issues/2615)) ([432ff95](https://github.com/aws-amplify/amplify-category-api/commit/432ff95c273f08aad00f81c71a043af4cf8d8ac4)) -- dont open urls when CLI is running in CI ([#6503](https://github.com/aws-amplify/amplify-category-api/issues/6503)) ([722c680](https://github.com/aws-amplify/amplify-category-api/commit/722c6809158ea43ac40c73bd7b069e3d303f145a)), closes [#5973](https://github.com/aws-amplify/amplify-category-api/issues/5973) -- extensibility for REST APIs ([#8598](https://github.com/aws-amplify/amplify-category-api/issues/8598)) ([e6bd4c8](https://github.com/aws-amplify/amplify-category-api/commit/e6bd4c8389f88cc1e06d3e4de154d148e03efcdf)) -- flag to allow destructive schema changes ([#8273](https://github.com/aws-amplify/amplify-category-api/issues/8273)) ([d76c9cb](https://github.com/aws-amplify/amplify-category-api/commit/d76c9cb9da5b1f200bce9751b4359d5451e3641c)) -- Flag to allow schema changes that require table replacement ([#8144](https://github.com/aws-amplify/amplify-category-api/issues/8144)) ([a8c2252](https://github.com/aws-amplify/amplify-category-api/commit/a8c22524d7bbb7bcb3854549ac0b45cac956ce3e)) -- flow to add policies to access amplify resources from Lambda ([#1462](https://github.com/aws-amplify/amplify-category-api/issues/1462)) ([e7afdba](https://github.com/aws-amplify/amplify-category-api/commit/e7afdba619de8c8adf7a3e3f9b6ebf77a3cccd87)) -- headless mode for API category ([#4834](https://github.com/aws-amplify/amplify-category-api/issues/4834)) ([7d61047](https://github.com/aws-amplify/amplify-category-api/commit/7d6104753cdf6a1a9cf576f9704a269427e8c457)) -- implement multi-auth functionality ([#1916](https://github.com/aws-amplify/amplify-category-api/issues/1916)) ([d509244](https://github.com/aws-amplify/amplify-category-api/commit/d5092446233b2e3eb7a7fe764639b43e8cb2dc29)) -- Lambda layers ([#4697](https://github.com/aws-amplify/amplify-category-api/issues/4697)) ([e08dda4](https://github.com/aws-amplify/amplify-category-api/commit/e08dda4ca4aaadfadc2e807f7f1c5f74923e3304)) -- migration of API GW and Interactions ([b0077dc](https://github.com/aws-amplify/amplify-category-api/commit/b0077dca5599ec1d0e0d5ac06671d788ca6165cf)) -- migration of categories - s3,dynamo,lambda,appsync ([#495](https://github.com/aws-amplify/amplify-category-api/issues/495)) ([2e36f3d](https://github.com/aws-amplify/amplify-category-api/commit/2e36f3d719e83c87904eac20c9bcfe815f62f473)) -- multi-environment support for API Gateway ([#418](https://github.com/aws-amplify/amplify-category-api/issues/418)) ([848e28a](https://github.com/aws-amplify/amplify-category-api/commit/848e28a4eeefb9db83847c1c046cba13866cf147)) -- multi-environment support for interactions category ([83cf76e](https://github.com/aws-amplify/amplify-category-api/commit/83cf76eec1a8a7b5ad78ba4620100e9c31d2ae0b)) -- override support for api category ([#9013](https://github.com/aws-amplify/amplify-category-api/issues/9013)) ([02c0ea1](https://github.com/aws-amplify/amplify-category-api/commit/02c0ea106d1101cf9eb30b725dde3e99a48986d4)), closes [#9001](https://github.com/aws-amplify/amplify-category-api/issues/9001) [#8954](https://github.com/aws-amplify/amplify-category-api/issues/8954) [#8958](https://github.com/aws-amplify/amplify-category-api/issues/8958) [#8960](https://github.com/aws-amplify/amplify-category-api/issues/8960) [#8967](https://github.com/aws-amplify/amplify-category-api/issues/8967) [#8971](https://github.com/aws-amplify/amplify-category-api/issues/8971) [#8976](https://github.com/aws-amplify/amplify-category-api/issues/8976) [#8975](https://github.com/aws-amplify/amplify-category-api/issues/8975) [#8981](https://github.com/aws-amplify/amplify-category-api/issues/8981) [#8983](https://github.com/aws-amplify/amplify-category-api/issues/8983) [#8992](https://github.com/aws-amplify/amplify-category-api/issues/8992) [#9000](https://github.com/aws-amplify/amplify-category-api/issues/9000) [#9002](https://github.com/aws-amplify/amplify-category-api/issues/9002) [#9005](https://github.com/aws-amplify/amplify-category-api/issues/9005) [#9006](https://github.com/aws-amplify/amplify-category-api/issues/9006) [#9007](https://github.com/aws-amplify/amplify-category-api/issues/9007) [#9008](https://github.com/aws-amplify/amplify-category-api/issues/9008) [#9010](https://github.com/aws-amplify/amplify-category-api/issues/9010) [#9011](https://github.com/aws-amplify/amplify-category-api/issues/9011) [#9012](https://github.com/aws-amplify/amplify-category-api/issues/9012) [#9014](https://github.com/aws-amplify/amplify-category-api/issues/9014) [#9015](https://github.com/aws-amplify/amplify-category-api/issues/9015) [#9017](https://github.com/aws-amplify/amplify-category-api/issues/9017) [#9020](https://github.com/aws-amplify/amplify-category-api/issues/9020) [#9024](https://github.com/aws-amplify/amplify-category-api/issues/9024) [#9027](https://github.com/aws-amplify/amplify-category-api/issues/9027) [#9028](https://github.com/aws-amplify/amplify-category-api/issues/9028) [#9029](https://github.com/aws-amplify/amplify-category-api/issues/9029) [#9032](https://github.com/aws-amplify/amplify-category-api/issues/9032) [#9031](https://github.com/aws-amplify/amplify-category-api/issues/9031) [#9035](https://github.com/aws-amplify/amplify-category-api/issues/9035) [#9038](https://github.com/aws-amplify/amplify-category-api/issues/9038) [#9039](https://github.com/aws-amplify/amplify-category-api/issues/9039) -- pre-deploy pull, new login mechanism and pkg cli updates ([#5941](https://github.com/aws-amplify/amplify-category-api/issues/5941)) ([69e0f03](https://github.com/aws-amplify/amplify-category-api/commit/69e0f0395ebe31dc220afdb4e0aa3a48ac236ed0)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-category-api/issues/1815)) ([810b0ba](https://github.com/aws-amplify/amplify-category-api/commit/810b0ba450a41ab91de717b8863e798d72bc4a86)) -- support for provisioning Cognito Hosted UI and support CRUD operations in Storage and API categories ([4e3c6be](https://github.com/aws-amplify/amplify-category-api/commit/4e3c6be407d991bbfcdac3e6cc03314455af7362)) -- support importing of auth resources ([#5591](https://github.com/aws-amplify/amplify-category-api/issues/5591)) ([5094cde](https://github.com/aws-amplify/amplify-category-api/commit/5094cdeeb563e920c0182204d44b31debb50bbc0)) -- uplevel enabling of datastore and update of auth configs to top ([#3495](https://github.com/aws-amplify/amplify-category-api/issues/3495)) ([c5be4a0](https://github.com/aws-amplify/amplify-category-api/commit/c5be4a02d5f157861261b75765c4ff8b3e3121f0)) -- usage flow logging for interactive and non-interactive cli commands ([#10288](https://github.com/aws-amplify/amplify-category-api/issues/10288)) ([3ebea06](https://github.com/aws-amplify/amplify-category-api/commit/3ebea06e9c9265b8199158cae1d7cf104da8588f)), closes [#10293](https://github.com/aws-amplify/amplify-category-api/issues/10293) -- User Pool Groups, Admin Auth Support, Custom Group Role Policies ([#2443](https://github.com/aws-amplify/amplify-category-api/issues/2443)) ([e4c3457](https://github.com/aws-amplify/amplify-category-api/commit/e4c345722dde76d284327e2026adad18d74e6c94)) - -### Reverts - -- Revert "fix: handle auth and api dependency in state files correctly (#9528)" (#9602) ([9282774](https://github.com/aws-amplify/amplify-category-api/commit/928277489e40e9524afc9e8da556dc420b2cd886)), closes [#9528](https://github.com/aws-amplify/amplify-category-api/issues/9528) [#9602](https://github.com/aws-amplify/amplify-category-api/issues/9602) -- Revert "Lambda auth minor fixes (#8741)" (#8762) ([2830128](https://github.com/aws-amplify/amplify-category-api/commit/28301285376b9c22891d299789dbab78f661e997)), closes [#8741](https://github.com/aws-amplify/amplify-category-api/issues/8741) [#8762](https://github.com/aws-amplify/amplify-category-api/issues/8762) -- Revert "feat: Flag to allow schema changes that require table replacement (#8144)" (#8268) ([5770353](https://github.com/aws-amplify/amplify-category-api/commit/5770353e088ff0cad3fbc7721463b3ea0af22287)), closes [#8144](https://github.com/aws-amplify/amplify-category-api/issues/8144) [#8268](https://github.com/aws-amplify/amplify-category-api/issues/8268) -- Revert "docs: add readme to vtl resolvers directory (#6718)" (#6845) ([1bcbbbf](https://github.com/aws-amplify/amplify-category-api/commit/1bcbbbf1c3f57248047d74fba084a99db575bfc3)), closes [#6718](https://github.com/aws-amplify/amplify-category-api/issues/6718) [#6845](https://github.com/aws-amplify/amplify-category-api/issues/6845) -- Revert problematic PRs (#4803) ([ab69fc3](https://github.com/aws-amplify/amplify-category-api/commit/ab69fc3c2684e7495ffb9e847e9bf2def65589f9)), closes [#4803](https://github.com/aws-amplify/amplify-category-api/issues/4803) [#4796](https://github.com/aws-amplify/amplify-category-api/issues/4796) [#4576](https://github.com/aws-amplify/amplify-category-api/issues/4576) [#4575](https://github.com/aws-amplify/amplify-category-api/issues/4575) [#4610](https://github.com/aws-amplify/amplify-category-api/issues/4610) -- Revert "Changing behavior so that the switch to PAY_PER_REQUEST billing is explicit. Users now set a parameter UsePayPerRequestBilling. This makes the migration steps occur much faster." ([b591f1b](https://github.com/aws-amplify/amplify-category-api/commit/b591f1bdf3c40ad28ccba5acdfe642956a9308b7)) - -### BREAKING CHANGES - -- package name update requires version bump in order to keep in sync with lerna. - -# [2.2.0](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@2.1.2...@aws-amplify/amplify-category-api@2.2.0) (2022-06-03) - -### Features - -- allow 3rd-party plugins to CDK override ([#9601](https://github.com/aws-amplify/amplify-cli/issues/9601)) ([60498c5](https://github.com/aws-amplify/amplify-cli/commit/60498c5fb54dcf15e2fb5b87528540fdcffc0cd1)) - -## [2.1.2](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@2.1.1...@aws-amplify/amplify-category-api@2.1.2) (2022-05-27) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [2.1.1](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@2.1.0...@aws-amplify/amplify-category-api@2.1.1) (2022-05-24) - -### Bug Fixes - -- opensearch instance type check during push ([#10389](https://github.com/aws-amplify/amplify-cli/issues/10389)) ([bbb6586](https://github.com/aws-amplify/amplify-cli/commit/bbb658617ba5ea5186bdc68b81961342505b4430)) - -# [2.1.0](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@2.0.4...@aws-amplify/amplify-category-api@2.1.0) (2022-05-10) - -### Bug Fixes - -- root path handling for REST APIs ([#9842](https://github.com/aws-amplify/amplify-cli/issues/9842)) ([08fb69f](https://github.com/aws-amplify/amplify-cli/commit/08fb69f6237a8e0a98ffdf6d73cb0b030ace583e)) - -### Features - -- usage flow logging for interactive and non-interactive cli commands ([#10288](https://github.com/aws-amplify/amplify-cli/issues/10288)) ([da391b1](https://github.com/aws-amplify/amplify-cli/commit/da391b146612d8914f72e558e5503d075456c820)), closes [#10293](https://github.com/aws-amplify/amplify-cli/issues/10293) - -## [2.0.4](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@2.0.3...@aws-amplify/amplify-category-api@2.0.4) (2022-04-29) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [2.0.3](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@2.0.2...@aws-amplify/amplify-category-api@2.0.3) (2022-04-27) - -### Bug Fixes - -- remove prompt from rds headless pull ([#10239](https://github.com/aws-amplify/amplify-cli/issues/10239)) ([3e276d1](https://github.com/aws-amplify/amplify-cli/commit/3e276d1cc154995281ef9baeb7775b3f71d5948b)) - -## [2.0.2](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@2.0.1...@aws-amplify/amplify-category-api@2.0.2) (2022-04-18) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [2.0.1](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@2.0.0...@aws-amplify/amplify-category-api@2.0.1) (2022-04-11) - -### Bug Fixes - -- api sets auth dependency correctly in meta files ([#10072](https://github.com/aws-amplify/amplify-cli/issues/10072)) ([42edc57](https://github.com/aws-amplify/amplify-cli/commit/42edc572ab21064da16ede94d16884fda5a9a54f)) - -# [2.0.0](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.2.17...@aws-amplify/amplify-category-api@2.0.0) (2022-04-07) - -### Bug Fixes - -- **container-api:** upgrade flask version for the python api ([#10077](https://github.com/aws-amplify/amplify-cli/issues/10077)) ([64ba2f1](https://github.com/aws-amplify/amplify-cli/commit/64ba2f1b0231ba3d237bfdbd2d36db303bedb9d3)) -- use prompter and handle deletions ([#10122](https://github.com/aws-amplify/amplify-cli/issues/10122)) ([5c0e290](https://github.com/aws-amplify/amplify-cli/commit/5c0e2904e5ac65824642281e732aae4f02904fd0)) - -### BREAKING CHANGES - -- package name update requires version bump in order to keep in sync with lerna. - -## [1.2.17](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.2.16...@aws-amplify/amplify-category-api@1.2.17) (2022-03-23) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [1.2.16](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.2.15...@aws-amplify/amplify-category-api@1.2.16) (2022-03-17) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [1.2.15](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.2.14...@aws-amplify/amplify-category-api@1.2.15) (2022-03-14) - -### Bug Fixes - -- allow api updates without migration ([#9864](https://github.com/aws-amplify/amplify-cli/issues/9864)) ([389f551](https://github.com/aws-amplify/amplify-cli/commit/389f551ea800afc9563b6e546f3ea0073bc13c68)) -- **amplify-category-api:** remove stack trace from printout for api ([#9877](https://github.com/aws-amplify/amplify-cli/issues/9877)) ([55be9c3](https://github.com/aws-amplify/amplify-cli/commit/55be9c3bac002fb1cc2cc4c1eae3df1b6972c4cb)) -- split policies for both legacy and migrated REST APIs ([#9572](https://github.com/aws-amplify/amplify-cli/issues/9572)) ([436d53f](https://github.com/aws-amplify/amplify-cli/commit/436d53f348954dab02364d1bed528c3b4121ede3)) - -## [1.2.14](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.2.13...@aws-amplify/amplify-category-api@1.2.14) (2022-03-07) - -### Bug Fixes - -- **amplify-category-api:** surface override build errors for REST APIs ([#9804](https://github.com/aws-amplify/amplify-cli/issues/9804)) ([b22b67d](https://github.com/aws-amplify/amplify-cli/commit/b22b67de1cdcafbb9475374e7fdf989431b5ce9c)) - -## [1.2.13](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.2.12...@aws-amplify/amplify-category-api@1.2.13) (2022-02-25) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [1.2.12](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.2.11...@aws-amplify/amplify-category-api@1.2.12) (2022-02-18) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [1.2.11](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.2.10...@aws-amplify/amplify-category-api@1.2.11) (2022-02-15) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [1.2.10](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.2.6...@aws-amplify/amplify-category-api@1.2.10) (2022-02-10) - -## 7.6.19 (2022-02-08) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [1.2.6](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.2.5...@aws-amplify/amplify-category-api@1.2.6) (2022-02-03) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [1.2.5](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.2.4...@aws-amplify/amplify-category-api@1.2.5) (2022-01-31) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [1.2.4](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.2.3...@aws-amplify/amplify-category-api@1.2.4) (2022-01-27) - -### Bug Fixes - -- handle auth and api dependency in state files correctly ([#9528](https://github.com/aws-amplify/amplify-cli/issues/9528)) ([edced3e](https://github.com/aws-amplify/amplify-cli/commit/edced3ef76da02bd269cf85c7287bfb74875d967)), closes [#9341](https://github.com/aws-amplify/amplify-cli/issues/9341) -- rest api override CloudFormation parameters ([#9325](https://github.com/aws-amplify/amplify-cli/issues/9325)) ([3338cfa](https://github.com/aws-amplify/amplify-cli/commit/3338cfaee199f83d2e270f12bb41983c067f42fe)), closes [#9221](https://github.com/aws-amplify/amplify-cli/issues/9221) - -### Reverts - -- Revert "fix: handle auth and api dependency in state files correctly (#9528)" (#9602) ([b99b08e](https://github.com/aws-amplify/amplify-cli/commit/b99b08e187be8f2f77761ccdd1092a0cba86a051)), closes [#9528](https://github.com/aws-amplify/amplify-cli/issues/9528) [#9602](https://github.com/aws-amplify/amplify-cli/issues/9602) - -## [1.2.3](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.2.2...@aws-amplify/amplify-category-api@1.2.3) (2022-01-23) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [1.2.2](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.2.1...@aws-amplify/amplify-category-api@1.2.2) (2022-01-20) - -### Bug Fixes - -- **api:** container rest api push treats incorrect initial push behavior ([#9556](https://github.com/aws-amplify/amplify-cli/issues/9556)) ([e1fadef](https://github.com/aws-amplify/amplify-cli/commit/e1fadef8152608fc1a9a088b065af95846fe0efc)) - -## [1.2.1](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.2.0...@aws-amplify/amplify-category-api@1.2.1) (2022-01-20) - -### Bug Fixes - -- **api:** container secrets pickup correct environment values ([#9513](https://github.com/aws-amplify/amplify-cli/issues/9513)) ([9986bd6](https://github.com/aws-amplify/amplify-cli/commit/9986bd6e0885609a04080f617db6c7331fb76f6a)) - -# [1.2.0](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.1.10...@aws-amplify/amplify-category-api@1.2.0) (2022-01-13) - -### Features - -- **amplify-category-api:** enable default 4xx and 5xx api gateway cors response ([#9158](https://github.com/aws-amplify/amplify-cli/issues/9158)) ([b35cbda](https://github.com/aws-amplify/amplify-cli/commit/b35cbda1a567142b72dc068081abd8fb65860074)), closes [#5183](https://github.com/aws-amplify/amplify-cli/issues/5183) - -## [1.1.10](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.1.8...@aws-amplify/amplify-category-api@1.1.10) (2022-01-10) - -## 7.6.7 (2022-01-10) - -### Bug Fixes - -- update dep and use node test environment ([#9434](https://github.com/aws-amplify/amplify-cli/issues/9434)) ([1691327](https://github.com/aws-amplify/amplify-cli/commit/1691327740ea40d0ebb974e6aeabc64c62b288ef)) - -## [1.1.8](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.1.7...@aws-amplify/amplify-category-api@1.1.8) (2021-12-21) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -## [1.1.7](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.1.6...@aws-amplify/amplify-category-api@1.1.7) (2021-12-17) - -### Bug Fixes - -- add missing salt to deployment logicalId ([#9234](https://github.com/aws-amplify/amplify-cli/issues/9234)) ([d4109e2](https://github.com/aws-amplify/amplify-cli/commit/d4109e2e8a18e2e9b787a97b1508efb1bf97fac9)) -- add-graphql-datasource command ([#9288](https://github.com/aws-amplify/amplify-cli/issues/9288)) ([f4cb8cb](https://github.com/aws-amplify/amplify-cli/commit/f4cb8cb2acdbe3024ff26385395860127fa78b5c)) -- improve api migration logic, update migration prompt ([#9267](https://github.com/aws-amplify/amplify-cli/issues/9267)) ([beed4f9](https://github.com/aws-amplify/amplify-cli/commit/beed4f9aa77bfbbb92ff0cb504e8019ce01e48f6)) - -## [1.1.6](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.1.5...@aws-amplify/amplify-category-api@1.1.6) (2021-12-03) - -## 7.6.2 (2021-12-02) - -### Bug Fixes - -- add safety check ([#9193](https://github.com/aws-amplify/amplify-cli/issues/9193)) ([4c12eb1](https://github.com/aws-amplify/amplify-cli/commit/4c12eb16805e5866dc99d74c36fd1c97130bcd70)) - -## [1.1.5](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.1.4...@aws-amplify/amplify-category-api@1.1.5) (2021-12-02) - -## 7.5.6 (2021-12-01) - -### Bug Fixes - -- call the correct migration function for Admin Queries ([#9174](https://github.com/aws-amplify/amplify-cli/issues/9174)) ([1ab2e66](https://github.com/aws-amplify/amplify-cli/commit/1ab2e66e1b54d09d68def7186b85644cb6d91653)) - -## [1.1.4](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.1.3...@aws-amplify/amplify-category-api@1.1.4) (2021-12-01) - -### Bug Fixes - -- migrate rest apis with protected routes on push ([#9068](https://github.com/aws-amplify/amplify-cli/issues/9068)) ([62b4436](https://github.com/aws-amplify/amplify-cli/commit/62b44365108ba3410c9023623394aa98a52db84e)) - -## [1.1.3](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.1.2...@aws-amplify/amplify-category-api@1.1.3) (2021-11-29) - -### Bug Fixes - -- use \_\_dirname instead of '.' in import path ([#9105](https://github.com/aws-amplify/amplify-cli/issues/9105)) ([8b6c6e4](https://github.com/aws-amplify/amplify-cli/commit/8b6c6e43e86bdc067c2607df129a0aff64a7588d)) - -## [1.1.2](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.1.1...@aws-amplify/amplify-category-api@1.1.2) (2021-11-26) - -## 7.5.3 (2021-11-26) - -### Bug Fixes - -- console override build issue ([#9078](https://github.com/aws-amplify/amplify-cli/issues/9078)) ([5c9bc5c](https://github.com/aws-amplify/amplify-cli/commit/5c9bc5c4003dd21c2897dc3c4faef9a9c19c1d99)) -- transformer version ([#9092](https://github.com/aws-amplify/amplify-cli/issues/9092)) ([acfa82c](https://github.com/aws-amplify/amplify-cli/commit/acfa82c9b275df0a7347ae0700a919dd8c03a4de)) - -## [1.1.1](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/amplify-category-api@1.1.0...@aws-amplify/amplify-category-api@1.1.1) (2021-11-24) - -**Note:** Version bump only for package @aws-amplify/amplify-category-api - -# 1.1.0 (2021-11-23) - -### Bug Fixes - -- asana bug fixes ([#8692](https://github.com/aws-amplify/amplify-cli/issues/8692)) ([c41d8b6](https://github.com/aws-amplify/amplify-cli/commit/c41d8b6442c48266f3fa074c9a9d33ce086ce1b9)) -- broken path on build-override ([798fd79](https://github.com/aws-amplify/amplify-cli/commit/798fd7988880f3c6617549e99b035e147e6d2137)) -- capitalization for filter, e2e test ([#8667](https://github.com/aws-amplify/amplify-cli/issues/8667)) ([4c5c869](https://github.com/aws-amplify/amplify-cli/commit/4c5c8699ca9261194ba0e6a5bfb958a0d95f412c)) -- **graphql:** detect resource update on graphql api auth mode change ([#8782](https://github.com/aws-amplify/amplify-cli/issues/8782)) ([714a122](https://github.com/aws-amplify/amplify-cli/commit/714a1221ec1ce72c88ba732172be6b8feab56a09)) -- **graphql:** refactor lambda authorizer code to use function category to create authorizer function ([#8784](https://github.com/aws-amplify/amplify-cli/issues/8784)) ([f529b54](https://github.com/aws-amplify/amplify-cli/commit/f529b541e2607eb4d2dd9e27810621fca141d6e2)) -- pushing multiple APIs at a time ([#8663](https://github.com/aws-amplify/amplify-cli/issues/8663)) ([23c2c4b](https://github.com/aws-amplify/amplify-cli/commit/23c2c4bb8e970e86285b72c224c9a51b112bfc0f)) -- remove await from sync read cfn calls ([#8977](https://github.com/aws-amplify/amplify-cli/issues/8977)) ([7ef6fb7](https://github.com/aws-amplify/amplify-cli/commit/7ef6fb72739d4618d02dba689a927831b53cb098)) -- stack generation logic when multiple paths ref same Lambda ([#8673](https://github.com/aws-amplify/amplify-cli/issues/8673)) ([d4a04e6](https://github.com/aws-amplify/amplify-cli/commit/d4a04e61db325b65737a94f33f7dba77d8a07529)) - -### Features - -- extensibility for REST APIs ([#8598](https://github.com/aws-amplify/amplify-cli/issues/8598)) ([de19d23](https://github.com/aws-amplify/amplify-cli/commit/de19d231465c1f16bf7d1c7ccb8dba2f36d039d8)) -- override support for api category ([#9013](https://github.com/aws-amplify/amplify-cli/issues/9013)) ([ae7b001](https://github.com/aws-amplify/amplify-cli/commit/ae7b001f274f327a29c99c67fe851272c6208e84)), closes [#9001](https://github.com/aws-amplify/amplify-cli/issues/9001) [#8954](https://github.com/aws-amplify/amplify-cli/issues/8954) [#8958](https://github.com/aws-amplify/amplify-cli/issues/8958) [#8960](https://github.com/aws-amplify/amplify-cli/issues/8960) [#8967](https://github.com/aws-amplify/amplify-cli/issues/8967) [#8971](https://github.com/aws-amplify/amplify-cli/issues/8971) [#8976](https://github.com/aws-amplify/amplify-cli/issues/8976) [#8975](https://github.com/aws-amplify/amplify-cli/issues/8975) [#8981](https://github.com/aws-amplify/amplify-cli/issues/8981) [#8983](https://github.com/aws-amplify/amplify-cli/issues/8983) [#8992](https://github.com/aws-amplify/amplify-cli/issues/8992) [#9000](https://github.com/aws-amplify/amplify-cli/issues/9000) [#9002](https://github.com/aws-amplify/amplify-cli/issues/9002) [#9005](https://github.com/aws-amplify/amplify-cli/issues/9005) [#9006](https://github.com/aws-amplify/amplify-cli/issues/9006) [#9007](https://github.com/aws-amplify/amplify-cli/issues/9007) [#9008](https://github.com/aws-amplify/amplify-cli/issues/9008) [#9010](https://github.com/aws-amplify/amplify-cli/issues/9010) [#9011](https://github.com/aws-amplify/amplify-cli/issues/9011) [#9012](https://github.com/aws-amplify/amplify-cli/issues/9012) [#9014](https://github.com/aws-amplify/amplify-cli/issues/9014) [#9015](https://github.com/aws-amplify/amplify-cli/issues/9015) [#9017](https://github.com/aws-amplify/amplify-cli/issues/9017) [#9020](https://github.com/aws-amplify/amplify-cli/issues/9020) [#9024](https://github.com/aws-amplify/amplify-cli/issues/9024) [#9027](https://github.com/aws-amplify/amplify-cli/issues/9027) [#9028](https://github.com/aws-amplify/amplify-cli/issues/9028) [#9029](https://github.com/aws-amplify/amplify-cli/issues/9029) [#9032](https://github.com/aws-amplify/amplify-cli/issues/9032) [#9031](https://github.com/aws-amplify/amplify-cli/issues/9031) [#9035](https://github.com/aws-amplify/amplify-cli/issues/9035) [#9038](https://github.com/aws-amplify/amplify-cli/issues/9038) [#9039](https://github.com/aws-amplify/amplify-cli/issues/9039) - -# 6.4.0 (2021-11-10) - -### Bug Fixes - -- [#8223](https://github.com/aws-amplify/amplify-cli/issues/8223), conversion to typescript ([#8245](https://github.com/aws-amplify/amplify-cli/issues/8245)) ([096e6ca](https://github.com/aws-amplify/amplify-cli/commit/096e6ca19b94aa40ef249ea98d008380395afa16)) -- **amplify-category-api:** change auth directive type and fix codegen bug ([#8639](https://github.com/aws-amplify/amplify-cli/issues/8639)) ([b8d838d](https://github.com/aws-amplify/amplify-cli/commit/b8d838ddfd332c0f6fb36ef52ab76da24b5d26ca)) -- **amplify-category-api:** fixed api to reference stack name and deployment bucket ([#8145](https://github.com/aws-amplify/amplify-cli/issues/8145)) ([4c7493a](https://github.com/aws-amplify/amplify-cli/commit/4c7493ac34fa89cab0c80e5c674bbeb102891a64)) -- api containers on repushing does not fail ([#8416](https://github.com/aws-amplify/amplify-cli/issues/8416)) ([eb64172](https://github.com/aws-amplify/amplify-cli/commit/eb641725febba88ebb7349c0e662d4ffc6cf7e97)) -- expand region support for aurora serverless ([#8577](https://github.com/aws-amplify/amplify-cli/issues/8577)) ([ad0cd2b](https://github.com/aws-amplify/amplify-cli/commit/ad0cd2b7e0644986276aa295dd424976f5c3ab68)) -- **graphql-model-transformer:** fixed schema template options check for transformer version ([#8449](https://github.com/aws-amplify/amplify-cli/issues/8449)) ([aedcae3](https://github.com/aws-amplify/amplify-cli/commit/aedcae36f445c6e990bd94fd29d1b012e1b13787)) -- **graphql:** lambda auth label fix ([#8623](https://github.com/aws-amplify/amplify-cli/issues/8623)) ([6b4994d](https://github.com/aws-amplify/amplify-cli/commit/6b4994dd860015dd7f72b0f162314ffd580c727e)) -- **graphql:** minor api prompt fixes ([#8603](https://github.com/aws-amplify/amplify-cli/issues/8603)) ([b9aabe2](https://github.com/aws-amplify/amplify-cli/commit/b9aabe22705cc5d418e83fc8a957f2aac59e0693)) -- remove duplicate error messages ([#8651](https://github.com/aws-amplify/amplify-cli/issues/8651)) ([aad5de7](https://github.com/aws-amplify/amplify-cli/commit/aad5de7b56b9b077b6b689c5b37d51dbfd4b262d)) -- schema migrator utility as separate command ([#8720](https://github.com/aws-amplify/amplify-cli/issues/8720)) ([46e1ee6](https://github.com/aws-amplify/amplify-cli/commit/46e1ee6a49dd86bb682b182a37626bc3f2f966ea)) - -### Features - -- **amplify-provider-awscloudformation:** change global_auth_rule to globalAuthRule for global auth ([#8674](https://github.com/aws-amplify/amplify-cli/issues/8674)) ([7a06216](https://github.com/aws-amplify/amplify-cli/commit/7a06216c0a56d9ab886ebb16b2179394fc5e76d2)) -- **amplify-provider-awscloudformation:** change sandbox mode syntax in schema ([#8592](https://github.com/aws-amplify/amplify-cli/issues/8592)) ([a3bdd44](https://github.com/aws-amplify/amplify-cli/commit/a3bdd44fddd3414a39d561510092084a1b8e6e61)) -- Custom policies IAM Policies for Lambda and Containers ([#8068](https://github.com/aws-amplify/amplify-cli/issues/8068)) ([3e1ce0d](https://github.com/aws-amplify/amplify-cli/commit/3e1ce0de4d25ab239adcdcef778cc82f30b17a94)) -- flag to allow destructive schema changes ([#8273](https://github.com/aws-amplify/amplify-cli/issues/8273)) ([18de856](https://github.com/aws-amplify/amplify-cli/commit/18de856fb61bf2df8f73375e4e55a58c6159a232)) -- Flag to allow schema changes that require table replacement ([#8144](https://github.com/aws-amplify/amplify-cli/issues/8144)) ([2d4e65a](https://github.com/aws-amplify/amplify-cli/commit/2d4e65acfd034d33c6fa8ac1f5f8582e7e3bc399)) - -### Reverts - -- Revert "Lambda auth minor fixes (#8741)" (#8762) ([aa1096c](https://github.com/aws-amplify/amplify-cli/commit/aa1096ca504bdb7e6a2dca2963c546f957116f9d)), closes [#8741](https://github.com/aws-amplify/amplify-cli/issues/8741) [#8762](https://github.com/aws-amplify/amplify-cli/issues/8762) -- Revert "feat: Flag to allow schema changes that require table replacement (#8144)" (#8268) ([422dd04](https://github.com/aws-amplify/amplify-cli/commit/422dd04425c72aa7276e086d38ce4d5f4681f9f3)), closes [#8144](https://github.com/aws-amplify/amplify-cli/issues/8144) [#8268](https://github.com/aws-amplify/amplify-cli/issues/8268) - -# 5.3.0 (2021-08-04) - -### Bug Fixes - -- api resource name case sensitivity failure ([#7452](https://github.com/aws-amplify/amplify-cli/issues/7452)) ([7bd5524](https://github.com/aws-amplify/amplify-cli/commit/7bd5524703a8ac963cf4d9ef6a1fbb031e42e3c4)) -- carry existing container secret config over ([#7224](https://github.com/aws-amplify/amplify-cli/issues/7224)) ([b2f3bf7](https://github.com/aws-amplify/amplify-cli/commit/b2f3bf7059ce3ca1e72cf6c451edd3e61699828a)) -- conditionally rebuild container apis on push ([#7175](https://github.com/aws-amplify/amplify-cli/issues/7175)) ([a27a033](https://github.com/aws-amplify/amplify-cli/commit/a27a033af0fe6a9db8becd15b713113c64e70eb3)) -- **container-hosting:** ignore test cases ([#7895](https://github.com/aws-amplify/amplify-cli/issues/7895)) ([f051445](https://github.com/aws-amplify/amplify-cli/commit/f05144510311fd38f188fd2d86a9fb0c74219269)) -- **graphql-model-transformer:** model input fields transform ([#7857](https://github.com/aws-amplify/amplify-cli/issues/7857)) ([12ff663](https://github.com/aws-amplify/amplify-cli/commit/12ff663a94a4896bd9eacef3847be15b7631d8df)) -- **graphql-transformer-common:** improve generated graphql pluralization ([#7258](https://github.com/aws-amplify/amplify-cli/issues/7258)) ([fc3ad0d](https://github.com/aws-amplify/amplify-cli/commit/fc3ad0dd5a12a7912c59ae12024f593b4cdf7f2d)), closes [#4224](https://github.com/aws-amplify/amplify-cli/issues/4224) -- lambda timeout should be an integer type ([#7699](https://github.com/aws-amplify/amplify-cli/issues/7699)) ([cbacf4d](https://github.com/aws-amplify/amplify-cli/commit/cbacf4d3e497421855c09825970e025550aacfd7)) -- make ECR repository name validation more strict ([#7337](https://github.com/aws-amplify/amplify-cli/issues/7337)) ([188efdd](https://github.com/aws-amplify/amplify-cli/commit/188efdde6ded25a06c6fb52e0b2abe04981b0993)) -- multi-env container hosting ([#7009](https://github.com/aws-amplify/amplify-cli/issues/7009)) ([#7346](https://github.com/aws-amplify/amplify-cli/issues/7346)) ([6c33215](https://github.com/aws-amplify/amplify-cli/commit/6c33215d064029add6b93bb10cad96bb63f40101)) -- support adding REST API paths in 'add api' ([#7229](https://github.com/aws-amplify/amplify-cli/issues/7229)) ([fa9404a](https://github.com/aws-amplify/amplify-cli/commit/fa9404afd1eedd342ea6ff2033fcbd143b33748a)) -- unique api name check works when no existing apis ([#7615](https://github.com/aws-amplify/amplify-cli/issues/7615)) ([8cef10f](https://github.com/aws-amplify/amplify-cli/commit/8cef10f051bea8428f3b16095137e14346218bb3)) -- update overlapping REST path warning ([#7276](https://github.com/aws-amplify/amplify-cli/issues/7276)) ([3fc7534](https://github.com/aws-amplify/amplify-cli/commit/3fc75343ba228307080f3ef6a6cae4cf3387a007)) - -## 4.50.2 (2021-05-03) - -## 4.50.1 (2021-05-03) - -### Bug Fixes - -- [#6123](https://github.com/aws-amplify/amplify-cli/issues/6123) - add missing amplify-cli-core dependencies to packages ([#6124](https://github.com/aws-amplify/amplify-cli/issues/6124)) ([e6519f2](https://github.com/aws-amplify/amplify-cli/commit/e6519f2dd81d2983b797f226d723a73a25967d25)) -- **amplify-category-api:** mantain ff in iam api policy ([#6723](https://github.com/aws-amplify/amplify-cli/issues/6723)) ([51e5e1b](https://github.com/aws-amplify/amplify-cli/commit/51e5e1b53514a05788dd824a48991c0db0b9705d)), closes [#6675](https://github.com/aws-amplify/amplify-cli/issues/6675) -- **cli:** use more inclusive language ([#6919](https://github.com/aws-amplify/amplify-cli/issues/6919)) ([bb70464](https://github.com/aws-amplify/amplify-cli/commit/bb70464d6c24fa931c0eb80d234a496d936913f5)) -- consolidate REST API IAM policies ([#6904](https://github.com/aws-amplify/amplify-cli/issues/6904)) (ref [#2084](https://github.com/aws-amplify/amplify-cli/issues/2084)) ([5cfff17](https://github.com/aws-amplify/amplify-cli/commit/5cfff173d57ec9ab68984faf2d0f6474eccdcaae)) -- fix appsync permission assignment from functions ([#5342](https://github.com/aws-amplify/amplify-cli/issues/5342)) ([b2e2dd0](https://github.com/aws-amplify/amplify-cli/commit/b2e2dd0071c1a451ba032cf7f8cfe7cf6381a96e)) -- handle errors and provide better error message when adding data source ([#7117](https://github.com/aws-amplify/amplify-cli/issues/7117)) (ref [#4384](https://github.com/aws-amplify/amplify-cli/issues/4384)) ([888829b](https://github.com/aws-amplify/amplify-cli/commit/888829ba6f53209ca12d215ed510d5e201d025ee)) -- remove process on next and await ([#6239](https://github.com/aws-amplify/amplify-cli/issues/6239)) ([59d4a0e](https://github.com/aws-amplify/amplify-cli/commit/59d4a0eb318d2b3ad97be34bda9dee756cf82d74)) -- sets policy resource name in api update flow ([328abac](https://github.com/aws-amplify/amplify-cli/commit/328abacd81d03dbae8b0c0246536c465a7954c1e)) -- wording: Enable, instead of Configure, conflict detection ([#6708](https://github.com/aws-amplify/amplify-cli/issues/6708)) ([dac6ae9](https://github.com/aws-amplify/amplify-cli/commit/dac6ae94af47dd01da25ea4f61efd5442cb4c06b)) - -### Features - -- allows adding graphql datasource with an empty graphql schema file ([#4464](https://github.com/aws-amplify/amplify-cli/issues/4464)) ([2b71a2d](https://github.com/aws-amplify/amplify-cli/commit/2b71a2df31585ad06674417b7003dfb70d5b785d)) -- dont open urls when CLI is running in CI ([#6503](https://github.com/aws-amplify/amplify-cli/issues/6503)) ([27546a7](https://github.com/aws-amplify/amplify-cli/commit/27546a78159ea95c636dbbd094fe6a4f7fb8f8f4)), closes [#5973](https://github.com/aws-amplify/amplify-cli/issues/5973) - -### Reverts - -- Revert "docs: add readme to vtl resolvers directory (#6718)" (#6845) ([1b67327](https://github.com/aws-amplify/amplify-cli/commit/1b67327f4885c611708c73256094456ab95b67ef)), closes [#6718](https://github.com/aws-amplify/amplify-cli/issues/6718) [#6845](https://github.com/aws-amplify/amplify-cli/issues/6845) - -# 4.39.0 (2020-12-10) - -### Bug Fixes - -- containers - don't wait for pipeline on hosting ([#6137](https://github.com/aws-amplify/amplify-cli/issues/6137)) ([c75d694](https://github.com/aws-amplify/amplify-cli/commit/c75d69436104cb974684b0ed48c743294f70d556)) -- only ignore root src folder ([#6136](https://github.com/aws-amplify/amplify-cli/issues/6136)) ([6289f5d](https://github.com/aws-amplify/amplify-cli/commit/6289f5ddc803eecf4d048075d769153c978523ac)) - -### Features - -- container-based deployments([#5727](https://github.com/aws-amplify/amplify-cli/issues/5727)) ([fad6377](https://github.com/aws-amplify/amplify-cli/commit/fad6377bd384862ca4429cb1a83eee90efd62b58)) -- pre-deploy pull, new login mechanism and pkg cli updates ([#5941](https://github.com/aws-amplify/amplify-cli/issues/5941)) ([7274251](https://github.com/aws-amplify/amplify-cli/commit/7274251faadc1035acce5f44699b172e10e2e67d)) - -# 4.32.0-alpha.0 (2020-10-27) - -### Bug Fixes - -- [#429](https://github.com/aws-amplify/amplify-cli/issues/429) - Editor hanging bug ([#2086](https://github.com/aws-amplify/amplify-cli/issues/2086)) ([6767445](https://github.com/aws-amplify/amplify-cli/commit/676744549f903fa3a4804d814eb325301ed462ba)) -- add support for mobile hub migrated resources ([#5407](https://github.com/aws-amplify/amplify-cli/issues/5407)) ([5dfe287](https://github.com/aws-amplify/amplify-cli/commit/5dfe2872c153047ebdc56bc4f671fd57c12379d9)) -- added exit code on remove ([#5427](https://github.com/aws-amplify/amplify-cli/issues/5427)) ([33132f7](https://github.com/aws-amplify/amplify-cli/commit/33132f764b290cafd345720409a5db8ea6088069)) -- **amplify-category-api:** add check for provider during migration ([3207e41](https://github.com/aws-amplify/amplify-cli/commit/3207e4153e5a9f8a41dad5757d1ec83b7fc8185a)), closes [#918](https://github.com/aws-amplify/amplify-cli/issues/918) -- **amplify-category-api:** add config check in writeResolverConfig ([bed4929](https://github.com/aws-amplify/amplify-cli/commit/bed49295c22f372511abb94f7227ba686cccf214)) -- **amplify-category-api:** added check to read schema in schema dir ([#3871](https://github.com/aws-amplify/amplify-cli/issues/3871)) ([21bd229](https://github.com/aws-amplify/amplify-cli/commit/21bd229b5c15e4ce837da604ec73e7f40076170f)), closes [fixes#3082](https://github.com/fixes/issues/3082) -- **amplify-category-api:** edit auth workflow if cognito is not used ([#3232](https://github.com/aws-amplify/amplify-cli/issues/3232)) ([f9473cf](https://github.com/aws-amplify/amplify-cli/commit/f9473cf50bbcf43a701f1f44b6f4d451dc2be237)), closes [#2967](https://github.com/aws-amplify/amplify-cli/issues/2967) -- **amplify-category-api:** Fix [#2498](https://github.com/aws-amplify/amplify-cli/issues/2498) ([#2503](https://github.com/aws-amplify/amplify-cli/issues/2503)) ([35aab06](https://github.com/aws-amplify/amplify-cli/commit/35aab06c1ac9d3081f4f2e06ae18c14ef212aa43)) -- **amplify-category-api:** fix api add-graphql-datasource command ([#2320](https://github.com/aws-amplify/amplify-cli/issues/2320)) ([a9c829d](https://github.com/aws-amplify/amplify-cli/commit/a9c829d79e91246d2bb9a707ccfe886502ceebe2)) -- **amplify-category-api:** fix conflict resolution learn more ([#2954](https://github.com/aws-amplify/amplify-cli/issues/2954)) ([5b0825a](https://github.com/aws-amplify/amplify-cli/commit/5b0825a44ad0b64180eb5cc373944ef82829eb06)) -- **amplify-category-api:** fix init env bug ([#1715](https://github.com/aws-amplify/amplify-cli/issues/1715)) ([1e21371](https://github.com/aws-amplify/amplify-cli/commit/1e21371900c315ca9fcbb9bcb1f4c8ec9800ee86)), closes [#1713](https://github.com/aws-amplify/amplify-cli/issues/1713) -- **amplify-category-api:** include userpool id in parameter.json ([#2238](https://github.com/aws-amplify/amplify-cli/issues/2238)) ([143b847](https://github.com/aws-amplify/amplify-cli/commit/143b84739d754f09f29f73678fd5a60674fd9304)) -- **amplify-category-api:** plumb api id to resources that require it ([#3464](https://github.com/aws-amplify/amplify-cli/issues/3464)) ([2b2d52f](https://github.com/aws-amplify/amplify-cli/commit/2b2d52f05edc1190953965ca0f3ecd880ec66a63)), closes [#3431](https://github.com/aws-amplify/amplify-cli/issues/3431) [#3386](https://github.com/aws-amplify/amplify-cli/issues/3386) -- **amplify-category-api:** safeguard prompt with empty options ([#2430](https://github.com/aws-amplify/amplify-cli/issues/2430)) ([cb8f6dd](https://github.com/aws-amplify/amplify-cli/commit/cb8f6dddefb7f7e7f8159988563fc076f470ee79)), closes [#2423](https://github.com/aws-amplify/amplify-cli/issues/2423) -- **amplify-category-api:** toggle datastore in update ([#4276](https://github.com/aws-amplify/amplify-cli/issues/4276)) ([4f02a62](https://github.com/aws-amplify/amplify-cli/commit/4f02a62f5c8929cabe914e2e38fb28dc535d2d61)), closes [#4058](https://github.com/aws-amplify/amplify-cli/issues/4058) -- **amplify-category-api:** use standard json read ([#2581](https://github.com/aws-amplify/amplify-cli/issues/2581)) ([3adc395](https://github.com/aws-amplify/amplify-cli/commit/3adc395a5e4ccf3673735f8091db63923a46c501)) -- **amplify-provider-awscloudformation:** apigw unauth access ([#1906](https://github.com/aws-amplify/amplify-cli/issues/1906)) ([bcd0d02](https://github.com/aws-amplify/amplify-cli/commit/bcd0d02a229d3dab2e5babc40b68ac9090aa5f15)) -- change default length for api key back to 7 days ([#2507](https://github.com/aws-amplify/amplify-cli/issues/2507)) ([6a7e61f](https://github.com/aws-amplify/amplify-cli/commit/6a7e61fc7315f5e732ad7b36b5c0ae88ea36b628)) -- checking undefined auth config ([#5313](https://github.com/aws-amplify/amplify-cli/issues/5313)) ([42810c9](https://github.com/aws-amplify/amplify-cli/commit/42810c98b0015f12119f3387749889a6bf6abe9b)) -- **cli:** add console command in the help message ([#2494](https://github.com/aws-amplify/amplify-cli/issues/2494)) ([cf0eddd](https://github.com/aws-amplify/amplify-cli/commit/cf0eddd1ba27b1126b0745cc068f205b2c2c8343)), closes [#1607](https://github.com/aws-amplify/amplify-cli/issues/1607) -- **cli:** deleting the amplify app on delete ([#3568](https://github.com/aws-amplify/amplify-cli/issues/3568)) ([f39bbcb](https://github.com/aws-amplify/amplify-cli/commit/f39bbcb715875eeeb612bcbc40b275b33f85eaf6)), closes [#3239](https://github.com/aws-amplify/amplify-cli/issues/3239) -- **cli:** fix inquirer version ([#1690](https://github.com/aws-amplify/amplify-cli/issues/1690)) ([9246032](https://github.com/aws-amplify/amplify-cli/commit/9246032603db49022c444e41faa5881592ce5dc9)), closes [#1688](https://github.com/aws-amplify/amplify-cli/issues/1688) -- **cli:** remove calls to gluegun's prompt.confirm ([#546](https://github.com/aws-amplify/amplify-cli/issues/546)) ([0080ddb](https://github.com/aws-amplify/amplify-cli/commit/0080ddbf5bc19bbbff7d4187167a748b5b578fce)) -- **cli:** remove unnecessary stack trace log when adding services ([#4610](https://github.com/aws-amplify/amplify-cli/issues/4610)) ([56efb32](https://github.com/aws-amplify/amplify-cli/commit/56efb32b79c47839cb9506a9300d40a01875a9fc)) -- data inconsitency ([#5344](https://github.com/aws-amplify/amplify-cli/issues/5344)) ([bfe1903](https://github.com/aws-amplify/amplify-cli/commit/bfe19038b5b676056f45d7ffcc4c2460057936d8)) -- fixing the IAM policies for AppSync API ([#1634](https://github.com/aws-amplify/amplify-cli/issues/1634)) ([9fb2fa9](https://github.com/aws-amplify/amplify-cli/commit/9fb2fa956d9d86b07c837a547766000fe88d3011)) -- **graphql-auth-transformer:** add a time delay when creating apiKey ([#4493](https://github.com/aws-amplify/amplify-cli/issues/4493)) ([3f544e7](https://github.com/aws-amplify/amplify-cli/commit/3f544e7f421f66f3d4e920cdd89ddb926c412241)) -- **graphql-elasticsearch-transformer:** fix duplicate records in es lambda ([#3712](https://github.com/aws-amplify/amplify-cli/issues/3712)) ([dd9f7e0](https://github.com/aws-amplify/amplify-cli/commit/dd9f7e0031a0dc68a9027de02f60bbe69d315c3d)), closes [#3602](https://github.com/aws-amplify/amplify-cli/issues/3602) [#3705](https://github.com/aws-amplify/amplify-cli/issues/3705) -- incorrect type on graphql boilerplate schema ([#4070](https://github.com/aws-amplify/amplify-cli/issues/4070)) ([d96171a](https://github.com/aws-amplify/amplify-cli/commit/d96171a7461ecbb610c3cbcbcb05cdf5492dc8e5)) -- move test package dependencies to devDependencies ([#2034](https://github.com/aws-amplify/amplify-cli/issues/2034)) ([f5623d0](https://github.com/aws-amplify/amplify-cli/commit/f5623d04a43e685901f4f1cd96e2a227164c71ee)) -- populate API_KEY env var when present ([#4923](https://github.com/aws-amplify/amplify-cli/issues/4923)) ([81231f9](https://github.com/aws-amplify/amplify-cli/commit/81231f98305dd9e37bb64eb30a9c7307bb471ad9)) -- refactor mobile hub migration checks ([#5632](https://github.com/aws-amplify/amplify-cli/issues/5632)) ([b796eb8](https://github.com/aws-amplify/amplify-cli/commit/b796eb8303bb903f5f531506254441a63eba2962)) -- remove mutableParametersState from stored function-params ([#4897](https://github.com/aws-amplify/amplify-cli/issues/4897)) ([c608166](https://github.com/aws-amplify/amplify-cli/commit/c6081668798e94165ede40bb06439075946e3e86)) -- removes duplicate auth types ([#5272](https://github.com/aws-amplify/amplify-cli/issues/5272)) ([8747911](https://github.com/aws-amplify/amplify-cli/commit/8747911ff5a515e86971af7d5ad15681c64eb532)) -- return undefined for empty conflict resolution ([#4982](https://github.com/aws-amplify/amplify-cli/issues/4982)) ([7c5bf1a](https://github.com/aws-amplify/amplify-cli/commit/7c5bf1a36078a345d80ecbf2cea3a067ae1137e1)), closes [#4965](https://github.com/aws-amplify/amplify-cli/issues/4965) -- sub \* for path parms in CFN policy ([#5092](https://github.com/aws-amplify/amplify-cli/issues/5092)) ([2942688](https://github.com/aws-amplify/amplify-cli/commit/29426884968314122b65a24b2f9658a618bf9120)) -- update CLI to handle UTF8 BOM ([#1357](https://github.com/aws-amplify/amplify-cli/issues/1357)) ([b0afa07](https://github.com/aws-amplify/amplify-cli/commit/b0afa07ab22d50409ff93c41350995cd7d2a1084)), closes [#1355](https://github.com/aws-amplify/amplify-cli/issues/1355) [#1122](https://github.com/aws-amplify/amplify-cli/issues/1122) -- update graphql schema to match docs ([#3652](https://github.com/aws-amplify/amplify-cli/issues/3652)) ([dc3c866](https://github.com/aws-amplify/amplify-cli/commit/dc3c8661066be6bfdbb404b81a73bfed1fcf0095)), closes [#3513](https://github.com/aws-amplify/amplify-cli/issues/3513) -- validatePathName_validPath matcher ([#4559](https://github.com/aws-amplify/amplify-cli/issues/4559)) ([94c00c4](https://github.com/aws-amplify/amplify-cli/commit/94c00c43e912e94a03ab10acbd93ad3dc5d2c18c)) - -### Features - -- add a warning on migration and force compile gql schema ([77fb557](https://github.com/aws-amplify/amplify-cli/commit/77fb5573be5ca006a5cdcbc1226d834549a74732)) -- add graphQLEndpoint as an env var to lambda functions ([#1641](https://github.com/aws-amplify/amplify-cli/issues/1641)) ([ae825a6](https://github.com/aws-amplify/amplify-cli/commit/ae825a61514f7e173da012326a2f5de0de0626e4)), closes [#1620](https://github.com/aws-amplify/amplify-cli/issues/1620) -- add option to open AppSync console using the CLI ([#386](https://github.com/aws-amplify/amplify-cli/issues/386)) ([3874a57](https://github.com/aws-amplify/amplify-cli/commit/3874a571d9ee9699f5b73ca985ca80e92909133a)) -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c1927da10f8c54f38a523021187361131c)) -- allow creation of REST API endpoint at root path (/) ([#4649](https://github.com/aws-amplify/amplify-cli/issues/4649)) ([49d8121](https://github.com/aws-amplify/amplify-cli/commit/49d8121ade1f06bf23d511523b88e9dd6c289073)), closes [#3868](https://github.com/aws-amplify/amplify-cli/issues/3868) [#4834](https://github.com/aws-amplify/amplify-cli/issues/4834) -- **amplify-category-api:** add rds support for new regions ([#5360](https://github.com/aws-amplify/amplify-cli/issues/5360)) ([4f65ed1](https://github.com/aws-amplify/amplify-cli/commit/4f65ed1ba6ab76f7d018b998525b73aa1e47fbcd)), closes [#4739](https://github.com/aws-amplify/amplify-cli/issues/4739) -- **amplify-category-api:** allow minified CF stack templates ([#3520](https://github.com/aws-amplify/amplify-cli/issues/3520)) ([6da2a63](https://github.com/aws-amplify/amplify-cli/commit/6da2a634548fdf48deb4b1144c67d1e1515abb80)), closes [#2914](https://github.com/aws-amplify/amplify-cli/issues/2914) -- **amplify-category-api:** support path parameters in REST APIs ([#3394](https://github.com/aws-amplify/amplify-cli/issues/3394)) ([fa7d07e](https://github.com/aws-amplify/amplify-cli/commit/fa7d07e1f6f54185a37851ea9d4c840b092501cc)) -- **amplify-category-function:** refactor to support runtime and template plugins ([#3517](https://github.com/aws-amplify/amplify-cli/issues/3517)) ([607ae21](https://github.com/aws-amplify/amplify-cli/commit/607ae21287941805f44ea8a9b78dd12d16d71f85)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) -- **cli:** new plugin platform ([#2254](https://github.com/aws-amplify/amplify-cli/issues/2254)) ([7ec29dd](https://github.com/aws-amplify/amplify-cli/commit/7ec29dd4f2da8c90727b36469eca646d289877b6)) -- **cli:** usage measurement ([#3641](https://github.com/aws-amplify/amplify-cli/issues/3641)) ([a755863](https://github.com/aws-amplify/amplify-cli/commit/a7558637fbb791dc22e0a91ae16f1b96fe4e99df)) -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- Delete all ([#2615](https://github.com/aws-amplify/amplify-cli/issues/2615)) ([5467679](https://github.com/aws-amplify/amplify-cli/commit/54676797b913d4a2c284c62244c8ccf8e55a44d8)) -- flow to add policies to access amplify resources from Lambda ([#1462](https://github.com/aws-amplify/amplify-cli/issues/1462)) ([fee247c](https://github.com/aws-amplify/amplify-cli/commit/fee247c74f54b050f7b7a6ea0733fbd08976f232)) -- headless mode for API category ([#4834](https://github.com/aws-amplify/amplify-cli/issues/4834)) ([c2e09d7](https://github.com/aws-amplify/amplify-cli/commit/c2e09d73fd1bb461eeace8f4a7addd70a63047ad)) -- implement multi-auth functionality ([#1916](https://github.com/aws-amplify/amplify-cli/issues/1916)) ([b99f58e](https://github.com/aws-amplify/amplify-cli/commit/b99f58e4a2b85cbe9f430838554ae3c277440132)) -- Lambda layers ([#4697](https://github.com/aws-amplify/amplify-cli/issues/4697)) ([4e97400](https://github.com/aws-amplify/amplify-cli/commit/4e974007d95c894ab4108a2dff8d5996e7e3ce25)) -- migration of API GW and Interactions ([a91ba9a](https://github.com/aws-amplify/amplify-cli/commit/a91ba9ae4de8a49c7ce8b8912e2962fd1a59824b)) -- migration of categories - s3,dynamo,lambda,appsync ([#495](https://github.com/aws-amplify/amplify-cli/issues/495)) ([1ef1d21](https://github.com/aws-amplify/amplify-cli/commit/1ef1d210b9accf8ba2571a42e3529ec24aa29bb3)) -- multi-environment support for API Gateway ([#418](https://github.com/aws-amplify/amplify-cli/issues/418)) ([24ddf83](https://github.com/aws-amplify/amplify-cli/commit/24ddf83066dc2c8e531e5f5e48e5145e2b6acf90)) -- multi-environment support for interactions category ([4ca2617](https://github.com/aws-amplify/amplify-cli/commit/4ca26177aef907f911c1f961f962b35ba07f4810)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe8925a4e73358b03ba927267a2df328b78)) -- support for provisioning Cognito Hosted UI and support CRUD operations in Storage and API categories ([729b0de](https://github.com/aws-amplify/amplify-cli/commit/729b0de411e5a576271f270d765cc31e4ee1424d)) -- support importing of auth resources ([#5591](https://github.com/aws-amplify/amplify-cli/issues/5591)) ([7903246](https://github.com/aws-amplify/amplify-cli/commit/790324680544fe18481f91390001f9f07a144203)) -- uplevel enabling of datastore and update of auth configs to top ([#3495](https://github.com/aws-amplify/amplify-cli/issues/3495)) ([f406bb2](https://github.com/aws-amplify/amplify-cli/commit/f406bb29957c98caf427a3cb46e2126f6dcf212f)) -- User Pool Groups, Admin Auth Support, Custom Group Role Policies ([#2443](https://github.com/aws-amplify/amplify-cli/issues/2443)) ([09aecfd](https://github.com/aws-amplify/amplify-cli/commit/09aecfd0cb3dae2c17d1c512946cc733c4fe3d4c)) - -### Reverts - -- Revert problematic PRs (#4803) ([f21a0f4](https://github.com/aws-amplify/amplify-cli/commit/f21a0f449a23c0c80a6f3280eef76bcbf3e9cb7c)), closes [#4803](https://github.com/aws-amplify/amplify-cli/issues/4803) [#4796](https://github.com/aws-amplify/amplify-cli/issues/4796) [#4576](https://github.com/aws-amplify/amplify-cli/issues/4576) [#4575](https://github.com/aws-amplify/amplify-cli/issues/4575) [#4610](https://github.com/aws-amplify/amplify-cli/issues/4610) -- Revert "Changing behavior so that the switch to PAY_PER_REQUEST billing is explicit. Users now set a parameter UsePayPerRequestBilling. This makes the migration steps occur much faster." ([e278fe1](https://github.com/aws-amplify/amplify-cli/commit/e278fe1f8edc85054a9684534c00225e4a79b242)) - -## [3.3.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@3.3.4...amplify-category-api@3.3.5) (2021-11-21) - -**Note:** Version bump only for package amplify-category-api - -## [3.3.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@3.3.3...amplify-category-api@3.3.4) (2021-11-20) - -### Bug Fixes - -- remove await from sync read cfn calls ([#8977](https://github.com/aws-amplify/amplify-cli/issues/8977)) ([7ef6fb7](https://github.com/aws-amplify/amplify-cli/commit/7ef6fb72739d4618d02dba689a927831b53cb098)) - -## [3.3.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@3.3.1...amplify-category-api@3.3.3) (2021-11-19) - -**Note:** Version bump only for package amplify-category-api - -## [3.3.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@3.3.1...amplify-category-api@3.3.2) (2021-11-19) - -**Note:** Version bump only for package amplify-category-api - -## [3.3.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@3.3.0...amplify-category-api@3.3.1) (2021-11-17) - -### Bug Fixes - -- **graphql:** detect resource update on graphql api auth mode change ([#8782](https://github.com/aws-amplify/amplify-cli/issues/8782)) ([714a122](https://github.com/aws-amplify/amplify-cli/commit/714a1221ec1ce72c88ba732172be6b8feab56a09)) -- **graphql:** refactor lambda authorizer code to use function category to create authorizer function ([#8784](https://github.com/aws-amplify/amplify-cli/issues/8784)) ([f529b54](https://github.com/aws-amplify/amplify-cli/commit/f529b541e2607eb4d2dd9e27810621fca141d6e2)) - -# [3.3.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.34.0...amplify-category-api@3.3.0) (2021-11-15) - -### Bug Fixes - -- asana bug fixes ([#8692](https://github.com/aws-amplify/amplify-cli/issues/8692)) ([c41d8b6](https://github.com/aws-amplify/amplify-cli/commit/c41d8b6442c48266f3fa074c9a9d33ce086ce1b9)) -- broken path on build-override ([798fd79](https://github.com/aws-amplify/amplify-cli/commit/798fd7988880f3c6617549e99b035e147e6d2137)) -- capitalization for filter, e2e test ([#8667](https://github.com/aws-amplify/amplify-cli/issues/8667)) ([4c5c869](https://github.com/aws-amplify/amplify-cli/commit/4c5c8699ca9261194ba0e6a5bfb958a0d95f412c)) -- pushing multiple APIs at a time ([#8663](https://github.com/aws-amplify/amplify-cli/issues/8663)) ([23c2c4b](https://github.com/aws-amplify/amplify-cli/commit/23c2c4bb8e970e86285b72c224c9a51b112bfc0f)) -- stack generation logic when multiple paths ref same Lambda ([#8673](https://github.com/aws-amplify/amplify-cli/issues/8673)) ([d4a04e6](https://github.com/aws-amplify/amplify-cli/commit/d4a04e61db325b65737a94f33f7dba77d8a07529)) - -### Features - -- extensibility for REST APIs ([#8598](https://github.com/aws-amplify/amplify-cli/issues/8598)) ([de19d23](https://github.com/aws-amplify/amplify-cli/commit/de19d231465c1f16bf7d1c7ccb8dba2f36d039d8)) - -# [3.0.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.33.2...amplify-category-api@3.0.0) (2021-11-13) - -### Bug Fixes - -- asana bug fixes ([#8692](https://github.com/aws-amplify/amplify-cli/issues/8692)) ([c41d8b6](https://github.com/aws-amplify/amplify-cli/commit/c41d8b6442c48266f3fa074c9a9d33ce086ce1b9)) -- broken path on build-override ([798fd79](https://github.com/aws-amplify/amplify-cli/commit/798fd7988880f3c6617549e99b035e147e6d2137)) -- capitalization for filter, e2e test ([#8667](https://github.com/aws-amplify/amplify-cli/issues/8667)) ([4c5c869](https://github.com/aws-amplify/amplify-cli/commit/4c5c8699ca9261194ba0e6a5bfb958a0d95f412c)) -- pushing multiple APIs at a time ([#8663](https://github.com/aws-amplify/amplify-cli/issues/8663)) ([23c2c4b](https://github.com/aws-amplify/amplify-cli/commit/23c2c4bb8e970e86285b72c224c9a51b112bfc0f)) -- stack generation logic when multiple paths ref same Lambda ([#8673](https://github.com/aws-amplify/amplify-cli/issues/8673)) ([d4a04e6](https://github.com/aws-amplify/amplify-cli/commit/d4a04e61db325b65737a94f33f7dba77d8a07529)) - -### Features - -- extensibility for REST APIs ([#8598](https://github.com/aws-amplify/amplify-cli/issues/8598)) ([de19d23](https://github.com/aws-amplify/amplify-cli/commit/de19d231465c1f16bf7d1c7ccb8dba2f36d039d8)) - -# 6.4.0 (2021-11-10) - -### Bug Fixes - -- **amplify-category-api:** change auth directive type and fix codegen bug ([#8639](https://github.com/aws-amplify/amplify-cli/issues/8639)) ([b8d838d](https://github.com/aws-amplify/amplify-cli/commit/b8d838ddfd332c0f6fb36ef52ab76da24b5d26ca)) -- expand region support for aurora serverless ([#8577](https://github.com/aws-amplify/amplify-cli/issues/8577)) ([ad0cd2b](https://github.com/aws-amplify/amplify-cli/commit/ad0cd2b7e0644986276aa295dd424976f5c3ab68)) -- **graphql-model-transformer:** fixed schema template options check for transformer version ([#8449](https://github.com/aws-amplify/amplify-cli/issues/8449)) ([aedcae3](https://github.com/aws-amplify/amplify-cli/commit/aedcae36f445c6e990bd94fd29d1b012e1b13787)) -- **graphql:** lambda auth label fix ([#8623](https://github.com/aws-amplify/amplify-cli/issues/8623)) ([6b4994d](https://github.com/aws-amplify/amplify-cli/commit/6b4994dd860015dd7f72b0f162314ffd580c727e)) -- **graphql:** minor api prompt fixes ([#8603](https://github.com/aws-amplify/amplify-cli/issues/8603)) ([b9aabe2](https://github.com/aws-amplify/amplify-cli/commit/b9aabe22705cc5d418e83fc8a957f2aac59e0693)) -- remove duplicate error messages ([#8651](https://github.com/aws-amplify/amplify-cli/issues/8651)) ([aad5de7](https://github.com/aws-amplify/amplify-cli/commit/aad5de7b56b9b077b6b689c5b37d51dbfd4b262d)) -- schema migrator utility as separate command ([#8720](https://github.com/aws-amplify/amplify-cli/issues/8720)) ([46e1ee6](https://github.com/aws-amplify/amplify-cli/commit/46e1ee6a49dd86bb682b182a37626bc3f2f966ea)) - -### Features - -- **amplify-provider-awscloudformation:** change global_auth_rule to globalAuthRule for global auth ([#8674](https://github.com/aws-amplify/amplify-cli/issues/8674)) ([7a06216](https://github.com/aws-amplify/amplify-cli/commit/7a06216c0a56d9ab886ebb16b2179394fc5e76d2)) -- **amplify-provider-awscloudformation:** change sandbox mode syntax in schema ([#8592](https://github.com/aws-amplify/amplify-cli/issues/8592)) ([a3bdd44](https://github.com/aws-amplify/amplify-cli/commit/a3bdd44fddd3414a39d561510092084a1b8e6e61)) -- flag to allow destructive schema changes ([#8273](https://github.com/aws-amplify/amplify-cli/issues/8273)) ([18de856](https://github.com/aws-amplify/amplify-cli/commit/18de856fb61bf2df8f73375e4e55a58c6159a232)) - -### Reverts - -- Revert "Lambda auth minor fixes (#8741)" (#8762) ([aa1096c](https://github.com/aws-amplify/amplify-cli/commit/aa1096ca504bdb7e6a2dca2963c546f957116f9d)), closes [#8741](https://github.com/aws-amplify/amplify-cli/issues/8741) [#8762](https://github.com/aws-amplify/amplify-cli/issues/8762) - -# [2.34.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.33.2...amplify-category-api@2.34.0) (2021-11-11) - -# 6.4.0 (2021-11-10) - -### Bug Fixes - -- **amplify-category-api:** change auth directive type and fix codegen bug ([#8639](https://github.com/aws-amplify/amplify-cli/issues/8639)) ([b8d838d](https://github.com/aws-amplify/amplify-cli/commit/b8d838ddfd332c0f6fb36ef52ab76da24b5d26ca)) -- expand region support for aurora serverless ([#8577](https://github.com/aws-amplify/amplify-cli/issues/8577)) ([ad0cd2b](https://github.com/aws-amplify/amplify-cli/commit/ad0cd2b7e0644986276aa295dd424976f5c3ab68)) -- **graphql-model-transformer:** fixed schema template options check for transformer version ([#8449](https://github.com/aws-amplify/amplify-cli/issues/8449)) ([aedcae3](https://github.com/aws-amplify/amplify-cli/commit/aedcae36f445c6e990bd94fd29d1b012e1b13787)) -- **graphql:** lambda auth label fix ([#8623](https://github.com/aws-amplify/amplify-cli/issues/8623)) ([6b4994d](https://github.com/aws-amplify/amplify-cli/commit/6b4994dd860015dd7f72b0f162314ffd580c727e)) -- **graphql:** minor api prompt fixes ([#8603](https://github.com/aws-amplify/amplify-cli/issues/8603)) ([b9aabe2](https://github.com/aws-amplify/amplify-cli/commit/b9aabe22705cc5d418e83fc8a957f2aac59e0693)) -- remove duplicate error messages ([#8651](https://github.com/aws-amplify/amplify-cli/issues/8651)) ([aad5de7](https://github.com/aws-amplify/amplify-cli/commit/aad5de7b56b9b077b6b689c5b37d51dbfd4b262d)) -- schema migrator utility as separate command ([#8720](https://github.com/aws-amplify/amplify-cli/issues/8720)) ([46e1ee6](https://github.com/aws-amplify/amplify-cli/commit/46e1ee6a49dd86bb682b182a37626bc3f2f966ea)) - -### Features - -- **amplify-provider-awscloudformation:** change global_auth_rule to globalAuthRule for global auth ([#8674](https://github.com/aws-amplify/amplify-cli/issues/8674)) ([7a06216](https://github.com/aws-amplify/amplify-cli/commit/7a06216c0a56d9ab886ebb16b2179394fc5e76d2)) -- **amplify-provider-awscloudformation:** change sandbox mode syntax in schema ([#8592](https://github.com/aws-amplify/amplify-cli/issues/8592)) ([a3bdd44](https://github.com/aws-amplify/amplify-cli/commit/a3bdd44fddd3414a39d561510092084a1b8e6e61)) -- flag to allow destructive schema changes ([#8273](https://github.com/aws-amplify/amplify-cli/issues/8273)) ([18de856](https://github.com/aws-amplify/amplify-cli/commit/18de856fb61bf2df8f73375e4e55a58c6159a232)) - -### Reverts - -- Revert "Lambda auth minor fixes (#8741)" (#8762) ([aa1096c](https://github.com/aws-amplify/amplify-cli/commit/aa1096ca504bdb7e6a2dca2963c546f957116f9d)), closes [#8741](https://github.com/aws-amplify/amplify-cli/issues/8741) [#8762](https://github.com/aws-amplify/amplify-cli/issues/8762) - -## [2.33.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.33.1...amplify-category-api@2.33.2) (2021-10-13) - -### Bug Fixes - -- api containers on repushing does not fail ([#8416](https://github.com/aws-amplify/amplify-cli/issues/8416)) ([eb64172](https://github.com/aws-amplify/amplify-cli/commit/eb641725febba88ebb7349c0e662d4ffc6cf7e97)) - -## [2.33.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.33.0...amplify-category-api@2.33.1) (2021-10-10) - -### Bug Fixes - -- **amplify-category-api:** fixed api to reference stack name and deployment bucket ([#8145](https://github.com/aws-amplify/amplify-cli/issues/8145)) ([4c7493a](https://github.com/aws-amplify/amplify-cli/commit/4c7493ac34fa89cab0c80e5c674bbeb102891a64)) - -# [2.33.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.32.0...amplify-category-api@2.33.0) (2021-10-06) - -### Features - -- Custom policies IAM Policies for Lambda and Containers ([#8068](https://github.com/aws-amplify/amplify-cli/issues/8068)) ([3e1ce0d](https://github.com/aws-amplify/amplify-cli/commit/3e1ce0de4d25ab239adcdcef778cc82f30b17a94)) - -# [2.32.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.23...amplify-category-api@2.32.0) (2021-09-27) - -### Bug Fixes - -- [#8223](https://github.com/aws-amplify/amplify-cli/issues/8223), conversion to typescript ([#8245](https://github.com/aws-amplify/amplify-cli/issues/8245)) ([096e6ca](https://github.com/aws-amplify/amplify-cli/commit/096e6ca19b94aa40ef249ea98d008380395afa16)) - -### Features - -- Flag to allow schema changes that require table replacement ([#8144](https://github.com/aws-amplify/amplify-cli/issues/8144)) ([2d4e65a](https://github.com/aws-amplify/amplify-cli/commit/2d4e65acfd034d33c6fa8ac1f5f8582e7e3bc399)) - -### Reverts - -- Revert "feat: Flag to allow schema changes that require table replacement (#8144)" (#8268) ([422dd04](https://github.com/aws-amplify/amplify-cli/commit/422dd04425c72aa7276e086d38ce4d5f4681f9f3)), closes [#8144](https://github.com/aws-amplify/amplify-cli/issues/8144) [#8268](https://github.com/aws-amplify/amplify-cli/issues/8268) - -## [2.31.23](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.22...amplify-category-api@2.31.23) (2021-09-18) - -**Note:** Version bump only for package amplify-category-api - -## [2.31.22](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.21...amplify-category-api@2.31.22) (2021-09-14) - -**Note:** Version bump only for package amplify-category-api - -## [2.31.21](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.20...amplify-category-api@2.31.21) (2021-09-09) - -**Note:** Version bump only for package amplify-category-api - -## [2.31.20](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.19...amplify-category-api@2.31.20) (2021-09-02) - -**Note:** Version bump only for package amplify-category-api - -## [2.31.19](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.18...amplify-category-api@2.31.19) (2021-08-24) - -**Note:** Version bump only for package amplify-category-api - -## [2.31.18](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.17...amplify-category-api@2.31.18) (2021-08-06) - -# 5.3.0 (2021-08-04) - -### Bug Fixes - -- **container-hosting:** ignore test cases ([#7895](https://github.com/aws-amplify/amplify-cli/issues/7895)) ([f051445](https://github.com/aws-amplify/amplify-cli/commit/f05144510311fd38f188fd2d86a9fb0c74219269)) -- **graphql-model-transformer:** model input fields transform ([#7857](https://github.com/aws-amplify/amplify-cli/issues/7857)) ([12ff663](https://github.com/aws-amplify/amplify-cli/commit/12ff663a94a4896bd9eacef3847be15b7631d8df)) -- multi-env container hosting ([#7009](https://github.com/aws-amplify/amplify-cli/issues/7009)) ([#7346](https://github.com/aws-amplify/amplify-cli/issues/7346)) ([6c33215](https://github.com/aws-amplify/amplify-cli/commit/6c33215d064029add6b93bb10cad96bb63f40101)) - -## [2.31.17](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.16...amplify-category-api@2.31.17) (2021-07-30) - -### Bug Fixes - -- lambda timeout should be an integer type ([#7699](https://github.com/aws-amplify/amplify-cli/issues/7699)) ([cbacf4d](https://github.com/aws-amplify/amplify-cli/commit/cbacf4d3e497421855c09825970e025550aacfd7)) - -## [2.31.16](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.15...amplify-category-api@2.31.16) (2021-07-27) - -**Note:** Version bump only for package amplify-category-api - -## [2.31.15](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.14...amplify-category-api@2.31.15) (2021-07-16) - -**Note:** Version bump only for package amplify-category-api - -## [2.31.14](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.13...amplify-category-api@2.31.14) (2021-07-12) - -**Note:** Version bump only for package amplify-category-api - -## [2.31.13](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.12...amplify-category-api@2.31.13) (2021-06-30) - -### Bug Fixes - -- api resource name case sensitivity failure ([#7452](https://github.com/aws-amplify/amplify-cli/issues/7452)) ([7bd5524](https://github.com/aws-amplify/amplify-cli/commit/7bd5524703a8ac963cf4d9ef6a1fbb031e42e3c4)) -- unique api name check works when no existing apis ([#7615](https://github.com/aws-amplify/amplify-cli/issues/7615)) ([8cef10f](https://github.com/aws-amplify/amplify-cli/commit/8cef10f051bea8428f3b16095137e14346218bb3)) - -## [2.31.12](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.11...amplify-category-api@2.31.12) (2021-06-24) - -### Bug Fixes - -- **graphql-transformer-common:** improve generated graphql pluralization ([#7258](https://github.com/aws-amplify/amplify-cli/issues/7258)) ([fc3ad0d](https://github.com/aws-amplify/amplify-cli/commit/fc3ad0dd5a12a7912c59ae12024f593b4cdf7f2d)), closes [#4224](https://github.com/aws-amplify/amplify-cli/issues/4224) -- support adding REST API paths in 'add api' ([#7229](https://github.com/aws-amplify/amplify-cli/issues/7229)) ([fa9404a](https://github.com/aws-amplify/amplify-cli/commit/fa9404afd1eedd342ea6ff2033fcbd143b33748a)) - -## [2.31.11](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.10...amplify-category-api@2.31.11) (2021-06-15) - -**Note:** Version bump only for package amplify-category-api - -## [2.31.10](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.9...amplify-category-api@2.31.10) (2021-06-02) - -**Note:** Version bump only for package amplify-category-api - -## [2.31.9](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.8...amplify-category-api@2.31.9) (2021-05-26) - -**Note:** Version bump only for package amplify-category-api - -## [2.31.8](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.7...amplify-category-api@2.31.8) (2021-05-18) - -### Bug Fixes - -- make ECR repository name validation more strict ([#7337](https://github.com/aws-amplify/amplify-cli/issues/7337)) ([188efdd](https://github.com/aws-amplify/amplify-cli/commit/188efdde6ded25a06c6fb52e0b2abe04981b0993)) - -## [2.31.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.6...amplify-category-api@2.31.7) (2021-05-14) - -### Bug Fixes - -- carry existing container secret config over ([#7224](https://github.com/aws-amplify/amplify-cli/issues/7224)) ([b2f3bf7](https://github.com/aws-amplify/amplify-cli/commit/b2f3bf7059ce3ca1e72cf6c451edd3e61699828a)) -- conditionally rebuild container apis on push ([#7175](https://github.com/aws-amplify/amplify-cli/issues/7175)) ([a27a033](https://github.com/aws-amplify/amplify-cli/commit/a27a033af0fe6a9db8becd15b713113c64e70eb3)) -- update overlapping REST path warning ([#7276](https://github.com/aws-amplify/amplify-cli/issues/7276)) ([3fc7534](https://github.com/aws-amplify/amplify-cli/commit/3fc75343ba228307080f3ef6a6cae4cf3387a007)) - -## [2.31.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.4...amplify-category-api@2.31.6) (2021-05-03) - -## 4.50.1 (2021-05-03) - -**Note:** Version bump only for package amplify-category-api - -## [2.31.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.4...amplify-category-api@2.31.5) (2021-05-03) - -**Note:** Version bump only for package amplify-category-api - -## [2.31.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.3...amplify-category-api@2.31.4) (2021-04-27) - -### Bug Fixes - -- consolidate REST API IAM policies ([#6904](https://github.com/aws-amplify/amplify-cli/issues/6904)) (ref [#2084](https://github.com/aws-amplify/amplify-cli/issues/2084)) ([5cfff17](https://github.com/aws-amplify/amplify-cli/commit/5cfff173d57ec9ab68984faf2d0f6474eccdcaae)) -- handle errors and provide better error message when adding data source ([#7117](https://github.com/aws-amplify/amplify-cli/issues/7117)) (ref [#4384](https://github.com/aws-amplify/amplify-cli/issues/4384)) ([888829b](https://github.com/aws-amplify/amplify-cli/commit/888829ba6f53209ca12d215ed510d5e201d025ee)) - -## [2.31.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.2...amplify-category-api@2.31.3) (2021-04-19) - -**Note:** Version bump only for package amplify-category-api - -## [2.31.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.1...amplify-category-api@2.31.2) (2021-04-14) - -**Note:** Version bump only for package amplify-category-api - -## [2.31.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.30.0...amplify-category-api@2.31.1) (2021-04-09) - -### Bug Fixes - -- **cli:** use more inclusive language ([#6919](https://github.com/aws-amplify/amplify-cli/issues/6919)) ([bb70464](https://github.com/aws-amplify/amplify-cli/commit/bb70464d6c24fa931c0eb80d234a496d936913f5)) - -# [2.30.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.29.5...amplify-category-api@2.30.0) (2021-03-23) - -### Bug Fixes - -- **amplify-category-api:** mantain ff in iam api policy ([#6723](https://github.com/aws-amplify/amplify-cli/issues/6723)) ([51e5e1b](https://github.com/aws-amplify/amplify-cli/commit/51e5e1b53514a05788dd824a48991c0db0b9705d)), closes [#6675](https://github.com/aws-amplify/amplify-cli/issues/6675) - -### Features - -- allows adding graphql datasource with an empty graphql schema file ([#4464](https://github.com/aws-amplify/amplify-cli/issues/4464)) ([2b71a2d](https://github.com/aws-amplify/amplify-cli/commit/2b71a2df31585ad06674417b7003dfb70d5b785d)) - -## [2.29.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.29.4...amplify-category-api@2.29.5) (2021-03-11) - -### Reverts - -- Revert "docs: add readme to vtl resolvers directory (#6718)" (#6845) ([1b67327](https://github.com/aws-amplify/amplify-cli/commit/1b67327f4885c611708c73256094456ab95b67ef)), closes [#6718](https://github.com/aws-amplify/amplify-cli/issues/6718) [#6845](https://github.com/aws-amplify/amplify-cli/issues/6845) - -## [2.29.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.29.3...amplify-category-api@2.29.4) (2021-03-05) - -### Bug Fixes - -- wording: Enable, instead of Configure, conflict detection ([#6708](https://github.com/aws-amplify/amplify-cli/issues/6708)) ([dac6ae9](https://github.com/aws-amplify/amplify-cli/commit/dac6ae94af47dd01da25ea4f61efd5442cb4c06b)) - -## [2.29.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.29.2...amplify-category-api@2.29.3) (2021-02-26) - -**Note:** Version bump only for package amplify-category-api - -## [2.29.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.29.1...amplify-category-api@2.29.2) (2021-02-24) - -**Note:** Version bump only for package amplify-category-api - -## [2.29.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.29.0...amplify-category-api@2.29.1) (2021-02-17) - -**Note:** Version bump only for package amplify-category-api - -# [2.29.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.28.3...amplify-category-api@2.29.0) (2021-02-11) - -### Bug Fixes - -- sets policy resource name in api update flow ([328abac](https://github.com/aws-amplify/amplify-cli/commit/328abacd81d03dbae8b0c0246536c465a7954c1e)) - -### Features - -- dont open urls when CLI is running in CI ([#6503](https://github.com/aws-amplify/amplify-cli/issues/6503)) ([27546a7](https://github.com/aws-amplify/amplify-cli/commit/27546a78159ea95c636dbbd094fe6a4f7fb8f8f4)), closes [#5973](https://github.com/aws-amplify/amplify-cli/issues/5973) - -## [2.28.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.28.2...amplify-category-api@2.28.3) (2021-02-10) - -### Bug Fixes - -- fix appsync permission assignment from functions ([#5342](https://github.com/aws-amplify/amplify-cli/issues/5342)) ([b2e2dd0](https://github.com/aws-amplify/amplify-cli/commit/b2e2dd0071c1a451ba032cf7f8cfe7cf6381a96e)) - -## [2.28.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.28.1...amplify-category-api@2.28.2) (2021-01-08) - -### Bug Fixes - -- remove process on next and await ([#6239](https://github.com/aws-amplify/amplify-cli/issues/6239)) ([59d4a0e](https://github.com/aws-amplify/amplify-cli/commit/59d4a0eb318d2b3ad97be34bda9dee756cf82d74)) - -## [2.28.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.28.0...amplify-category-api@2.28.1) (2020-12-16) - -### Bug Fixes - -- [#6123](https://github.com/aws-amplify/amplify-cli/issues/6123) - add missing amplify-cli-core dependencies to packages ([#6124](https://github.com/aws-amplify/amplify-cli/issues/6124)) ([e6519f2](https://github.com/aws-amplify/amplify-cli/commit/e6519f2dd81d2983b797f226d723a73a25967d25)) - -# [2.28.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.27.1...amplify-category-api@2.28.0) (2020-12-11) - -# 4.39.0 (2020-12-10) - -### Bug Fixes - -- containers - don't wait for pipeline on hosting ([#6137](https://github.com/aws-amplify/amplify-cli/issues/6137)) ([c75d694](https://github.com/aws-amplify/amplify-cli/commit/c75d69436104cb974684b0ed48c743294f70d556)) -- only ignore root src folder ([#6136](https://github.com/aws-amplify/amplify-cli/issues/6136)) ([6289f5d](https://github.com/aws-amplify/amplify-cli/commit/6289f5ddc803eecf4d048075d769153c978523ac)) - -### Features - -- container-based deployments([#5727](https://github.com/aws-amplify/amplify-cli/issues/5727)) ([fad6377](https://github.com/aws-amplify/amplify-cli/commit/fad6377bd384862ca4429cb1a83eee90efd62b58)) - -## [2.27.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.27.0...amplify-category-api@2.27.1) (2020-12-07) - -**Note:** Version bump only for package amplify-category-api - -# [2.27.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.26.2...amplify-category-api@2.27.0) (2020-11-30) - -### Features - -- pre-deploy pull, new login mechanism and pkg cli updates ([#5941](https://github.com/aws-amplify/amplify-cli/issues/5941)) ([7274251](https://github.com/aws-amplify/amplify-cli/commit/7274251faadc1035acce5f44699b172e10e2e67d)) - -## [2.26.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.26.1...amplify-category-api@2.26.2) (2020-11-24) - -**Note:** Version bump only for package amplify-category-api - -## [2.26.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.25.4...amplify-category-api@2.26.1) (2020-11-22) - -**Note:** Version bump only for package amplify-category-api - -# [2.26.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.7.11...amplify-category-api@2.26.0) (2020-11-22) - -### Bug Fixes - -- add support for mobile hub migrated resources ([#5407](https://github.com/aws-amplify/amplify-cli/issues/5407)) ([5dfe287](https://github.com/aws-amplify/amplify-cli/commit/5dfe2872c153047ebdc56bc4f671fd57c12379d9)) -- added exit code on remove ([#5427](https://github.com/aws-amplify/amplify-cli/issues/5427)) ([33132f7](https://github.com/aws-amplify/amplify-cli/commit/33132f764b290cafd345720409a5db8ea6088069)) -- checking undefined auth config ([#5313](https://github.com/aws-amplify/amplify-cli/issues/5313)) ([42810c9](https://github.com/aws-amplify/amplify-cli/commit/42810c98b0015f12119f3387749889a6bf6abe9b)) -- data inconsitency ([#5344](https://github.com/aws-amplify/amplify-cli/issues/5344)) ([bfe1903](https://github.com/aws-amplify/amplify-cli/commit/bfe19038b5b676056f45d7ffcc4c2460057936d8)) -- incorrect type on graphql boilerplate schema ([#4070](https://github.com/aws-amplify/amplify-cli/issues/4070)) ([d96171a](https://github.com/aws-amplify/amplify-cli/commit/d96171a7461ecbb610c3cbcbcb05cdf5492dc8e5)) -- populate API_KEY env var when present ([#4923](https://github.com/aws-amplify/amplify-cli/issues/4923)) ([81231f9](https://github.com/aws-amplify/amplify-cli/commit/81231f98305dd9e37bb64eb30a9c7307bb471ad9)) -- refactor mobile hub migration checks ([#5632](https://github.com/aws-amplify/amplify-cli/issues/5632)) ([b796eb8](https://github.com/aws-amplify/amplify-cli/commit/b796eb8303bb903f5f531506254441a63eba2962)) -- remove mutableParametersState from stored function-params ([#4897](https://github.com/aws-amplify/amplify-cli/issues/4897)) ([c608166](https://github.com/aws-amplify/amplify-cli/commit/c6081668798e94165ede40bb06439075946e3e86)) -- removes duplicate auth types ([#5272](https://github.com/aws-amplify/amplify-cli/issues/5272)) ([8747911](https://github.com/aws-amplify/amplify-cli/commit/8747911ff5a515e86971af7d5ad15681c64eb532)) -- return undefined for empty conflict resolution ([#4982](https://github.com/aws-amplify/amplify-cli/issues/4982)) ([7c5bf1a](https://github.com/aws-amplify/amplify-cli/commit/7c5bf1a36078a345d80ecbf2cea3a067ae1137e1)), closes [#4965](https://github.com/aws-amplify/amplify-cli/issues/4965) -- sub \* for path parms in CFN policy ([#5092](https://github.com/aws-amplify/amplify-cli/issues/5092)) ([2942688](https://github.com/aws-amplify/amplify-cli/commit/29426884968314122b65a24b2f9658a618bf9120)) -- **amplify-category-api:** add config check in writeResolverConfig ([bed4929](https://github.com/aws-amplify/amplify-cli/commit/bed49295c22f372511abb94f7227ba686cccf214)) -- **amplify-category-api:** added check to read schema in schema dir ([#3871](https://github.com/aws-amplify/amplify-cli/issues/3871)) ([21bd229](https://github.com/aws-amplify/amplify-cli/commit/21bd229b5c15e4ce837da604ec73e7f40076170f)), closes [fixes#3082](https://github.com/fixes/issues/3082) -- **amplify-category-api:** edit auth workflow if cognito is not used ([#3232](https://github.com/aws-amplify/amplify-cli/issues/3232)) ([f9473cf](https://github.com/aws-amplify/amplify-cli/commit/f9473cf50bbcf43a701f1f44b6f4d451dc2be237)), closes [#2967](https://github.com/aws-amplify/amplify-cli/issues/2967) -- **amplify-category-api:** Fix [#2498](https://github.com/aws-amplify/amplify-cli/issues/2498) ([#2503](https://github.com/aws-amplify/amplify-cli/issues/2503)) ([35aab06](https://github.com/aws-amplify/amplify-cli/commit/35aab06c1ac9d3081f4f2e06ae18c14ef212aa43)) -- **amplify-category-api:** fix api add-graphql-datasource command ([#2320](https://github.com/aws-amplify/amplify-cli/issues/2320)) ([a9c829d](https://github.com/aws-amplify/amplify-cli/commit/a9c829d79e91246d2bb9a707ccfe886502ceebe2)) -- **amplify-category-api:** fix conflict resolution learn more ([#2954](https://github.com/aws-amplify/amplify-cli/issues/2954)) ([5b0825a](https://github.com/aws-amplify/amplify-cli/commit/5b0825a44ad0b64180eb5cc373944ef82829eb06)) -- **amplify-category-api:** include userpool id in parameter.json ([#2238](https://github.com/aws-amplify/amplify-cli/issues/2238)) ([143b847](https://github.com/aws-amplify/amplify-cli/commit/143b84739d754f09f29f73678fd5a60674fd9304)) -- **amplify-category-api:** plumb api id to resources that require it ([#3464](https://github.com/aws-amplify/amplify-cli/issues/3464)) ([2b2d52f](https://github.com/aws-amplify/amplify-cli/commit/2b2d52f05edc1190953965ca0f3ecd880ec66a63)), closes [#3431](https://github.com/aws-amplify/amplify-cli/issues/3431) [#3386](https://github.com/aws-amplify/amplify-cli/issues/3386) -- **amplify-category-api:** safeguard prompt with empty options ([#2430](https://github.com/aws-amplify/amplify-cli/issues/2430)) ([cb8f6dd](https://github.com/aws-amplify/amplify-cli/commit/cb8f6dddefb7f7e7f8159988563fc076f470ee79)), closes [#2423](https://github.com/aws-amplify/amplify-cli/issues/2423) -- **amplify-category-api:** toggle datastore in update ([#4276](https://github.com/aws-amplify/amplify-cli/issues/4276)) ([4f02a62](https://github.com/aws-amplify/amplify-cli/commit/4f02a62f5c8929cabe914e2e38fb28dc535d2d61)), closes [#4058](https://github.com/aws-amplify/amplify-cli/issues/4058) -- **amplify-category-api:** use standard json read ([#2581](https://github.com/aws-amplify/amplify-cli/issues/2581)) ([3adc395](https://github.com/aws-amplify/amplify-cli/commit/3adc395a5e4ccf3673735f8091db63923a46c501)) -- **amplify-provider-awscloudformation:** apigw unauth access ([#1906](https://github.com/aws-amplify/amplify-cli/issues/1906)) ([bcd0d02](https://github.com/aws-amplify/amplify-cli/commit/bcd0d02a229d3dab2e5babc40b68ac9090aa5f15)) -- **cli:** add console command in the help message ([#2494](https://github.com/aws-amplify/amplify-cli/issues/2494)) ([cf0eddd](https://github.com/aws-amplify/amplify-cli/commit/cf0eddd1ba27b1126b0745cc068f205b2c2c8343)), closes [#1607](https://github.com/aws-amplify/amplify-cli/issues/1607) -- **cli:** deleting the amplify app on delete ([#3568](https://github.com/aws-amplify/amplify-cli/issues/3568)) ([f39bbcb](https://github.com/aws-amplify/amplify-cli/commit/f39bbcb715875eeeb612bcbc40b275b33f85eaf6)), closes [#3239](https://github.com/aws-amplify/amplify-cli/issues/3239) -- **cli:** remove unnecessary stack trace log when adding services ([#4610](https://github.com/aws-amplify/amplify-cli/issues/4610)) ([56efb32](https://github.com/aws-amplify/amplify-cli/commit/56efb32b79c47839cb9506a9300d40a01875a9fc)) -- **graphql-auth-transformer:** add a time delay when creating apiKey ([#4493](https://github.com/aws-amplify/amplify-cli/issues/4493)) ([3f544e7](https://github.com/aws-amplify/amplify-cli/commit/3f544e7f421f66f3d4e920cdd89ddb926c412241)) -- [#429](https://github.com/aws-amplify/amplify-cli/issues/429) - Editor hanging bug ([#2086](https://github.com/aws-amplify/amplify-cli/issues/2086)) ([6767445](https://github.com/aws-amplify/amplify-cli/commit/676744549f903fa3a4804d814eb325301ed462ba)) -- change default length for api key back to 7 days ([#2507](https://github.com/aws-amplify/amplify-cli/issues/2507)) ([6a7e61f](https://github.com/aws-amplify/amplify-cli/commit/6a7e61fc7315f5e732ad7b36b5c0ae88ea36b628)) -- move test package dependencies to devDependencies ([#2034](https://github.com/aws-amplify/amplify-cli/issues/2034)) ([f5623d0](https://github.com/aws-amplify/amplify-cli/commit/f5623d04a43e685901f4f1cd96e2a227164c71ee)) -- update graphql schema to match docs ([#3652](https://github.com/aws-amplify/amplify-cli/issues/3652)) ([dc3c866](https://github.com/aws-amplify/amplify-cli/commit/dc3c8661066be6bfdbb404b81a73bfed1fcf0095)), closes [#3513](https://github.com/aws-amplify/amplify-cli/issues/3513) -- validatePathName_validPath matcher ([#4559](https://github.com/aws-amplify/amplify-cli/issues/4559)) ([94c00c4](https://github.com/aws-amplify/amplify-cli/commit/94c00c43e912e94a03ab10acbd93ad3dc5d2c18c)) -- **graphql-elasticsearch-transformer:** fix duplicate records in es lambda ([#3712](https://github.com/aws-amplify/amplify-cli/issues/3712)) ([dd9f7e0](https://github.com/aws-amplify/amplify-cli/commit/dd9f7e0031a0dc68a9027de02f60bbe69d315c3d)), closes [#3602](https://github.com/aws-amplify/amplify-cli/issues/3602) [#3705](https://github.com/aws-amplify/amplify-cli/issues/3705) - -### Features - -- support importing of auth resources ([#5591](https://github.com/aws-amplify/amplify-cli/issues/5591)) ([7903246](https://github.com/aws-amplify/amplify-cli/commit/790324680544fe18481f91390001f9f07a144203)) -- **amplify-category-api:** add rds support for new regions ([#5360](https://github.com/aws-amplify/amplify-cli/issues/5360)) ([4f65ed1](https://github.com/aws-amplify/amplify-cli/commit/4f65ed1ba6ab76f7d018b998525b73aa1e47fbcd)), closes [#4739](https://github.com/aws-amplify/amplify-cli/issues/4739) -- allow creation of REST API endpoint at root path (/) ([#4649](https://github.com/aws-amplify/amplify-cli/issues/4649)) ([49d8121](https://github.com/aws-amplify/amplify-cli/commit/49d8121ade1f06bf23d511523b88e9dd6c289073)), closes [#3868](https://github.com/aws-amplify/amplify-cli/issues/3868) [#4834](https://github.com/aws-amplify/amplify-cli/issues/4834) -- headless mode for API category ([#4834](https://github.com/aws-amplify/amplify-cli/issues/4834)) ([c2e09d7](https://github.com/aws-amplify/amplify-cli/commit/c2e09d73fd1bb461eeace8f4a7addd70a63047ad)) -- Lambda layers ([#4697](https://github.com/aws-amplify/amplify-cli/issues/4697)) ([4e97400](https://github.com/aws-amplify/amplify-cli/commit/4e974007d95c894ab4108a2dff8d5996e7e3ce25)) -- **amplify-category-api:** allow minified CF stack templates ([#3520](https://github.com/aws-amplify/amplify-cli/issues/3520)) ([6da2a63](https://github.com/aws-amplify/amplify-cli/commit/6da2a634548fdf48deb4b1144c67d1e1515abb80)), closes [#2914](https://github.com/aws-amplify/amplify-cli/issues/2914) -- **amplify-category-api:** support path parameters in REST APIs ([#3394](https://github.com/aws-amplify/amplify-cli/issues/3394)) ([fa7d07e](https://github.com/aws-amplify/amplify-cli/commit/fa7d07e1f6f54185a37851ea9d4c840b092501cc)) -- **amplify-category-function:** refactor to support runtime and template plugins ([#3517](https://github.com/aws-amplify/amplify-cli/issues/3517)) ([607ae21](https://github.com/aws-amplify/amplify-cli/commit/607ae21287941805f44ea8a9b78dd12d16d71f85)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) -- **cli:** usage measurement ([#3641](https://github.com/aws-amplify/amplify-cli/issues/3641)) ([a755863](https://github.com/aws-amplify/amplify-cli/commit/a7558637fbb791dc22e0a91ae16f1b96fe4e99df)) -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c1927da10f8c54f38a523021187361131c)) -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- Delete all ([#2615](https://github.com/aws-amplify/amplify-cli/issues/2615)) ([5467679](https://github.com/aws-amplify/amplify-cli/commit/54676797b913d4a2c284c62244c8ccf8e55a44d8)) -- implement multi-auth functionality ([#1916](https://github.com/aws-amplify/amplify-cli/issues/1916)) ([b99f58e](https://github.com/aws-amplify/amplify-cli/commit/b99f58e4a2b85cbe9f430838554ae3c277440132)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe8925a4e73358b03ba927267a2df328b78)) -- uplevel enabling of datastore and update of auth configs to top ([#3495](https://github.com/aws-amplify/amplify-cli/issues/3495)) ([f406bb2](https://github.com/aws-amplify/amplify-cli/commit/f406bb29957c98caf427a3cb46e2126f6dcf212f)) -- User Pool Groups, Admin Auth Support, Custom Group Role Policies ([#2443](https://github.com/aws-amplify/amplify-cli/issues/2443)) ([09aecfd](https://github.com/aws-amplify/amplify-cli/commit/09aecfd0cb3dae2c17d1c512946cc733c4fe3d4c)) -- **cli:** new plugin platform ([#2254](https://github.com/aws-amplify/amplify-cli/issues/2254)) ([7ec29dd](https://github.com/aws-amplify/amplify-cli/commit/7ec29dd4f2da8c90727b36469eca646d289877b6)) - -### Reverts - -- Revert problematic PRs (#4803) ([f21a0f4](https://github.com/aws-amplify/amplify-cli/commit/f21a0f449a23c0c80a6f3280eef76bcbf3e9cb7c)), closes [#4803](https://github.com/aws-amplify/amplify-cli/issues/4803) [#4796](https://github.com/aws-amplify/amplify-cli/issues/4796) [#4576](https://github.com/aws-amplify/amplify-cli/issues/4576) [#4575](https://github.com/aws-amplify/amplify-cli/issues/4575) [#4610](https://github.com/aws-amplify/amplify-cli/issues/4610) - -## [2.25.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.25.4...amplify-category-api@2.25.7) (2020-11-20) - -**Note:** Version bump only for package amplify-category-api - -## [2.25.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.25.4...amplify-category-api@2.25.6) (2020-11-20) - -**Note:** Version bump only for package amplify-category-api - -## [2.25.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.25.4...amplify-category-api@2.25.5) (2020-11-19) - -**Note:** Version bump only for package amplify-category-api - -## [2.25.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.25.3...amplify-category-api@2.25.4) (2020-11-08) - -**Note:** Version bump only for package amplify-category-api - -## [2.25.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.25.2...amplify-category-api@2.25.3) (2020-10-30) - -**Note:** Version bump only for package amplify-category-api - -## [2.25.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.25.1...amplify-category-api@2.25.2) (2020-10-27) - -**Note:** Version bump only for package amplify-category-api - -## [2.25.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.25.0...amplify-category-api@2.25.1) (2020-10-22) - -### Bug Fixes - -- refactor mobile hub migration checks ([#5632](https://github.com/aws-amplify/amplify-cli/issues/5632)) ([b796eb8](https://github.com/aws-amplify/amplify-cli/commit/b796eb8303bb903f5f531506254441a63eba2962)) - -# [2.25.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.24.1...amplify-category-api@2.25.0) (2020-10-17) - -### Features - -- support importing of auth resources ([#5591](https://github.com/aws-amplify/amplify-cli/issues/5591)) ([7903246](https://github.com/aws-amplify/amplify-cli/commit/790324680544fe18481f91390001f9f07a144203)) - -## [2.24.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.24.0...amplify-category-api@2.24.1) (2020-10-07) - -**Note:** Version bump only for package amplify-category-api - -# [2.24.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.23.9...amplify-category-api@2.24.0) (2020-10-01) - -### Bug Fixes - -- add support for mobile hub migrated resources ([#5407](https://github.com/aws-amplify/amplify-cli/issues/5407)) ([5dfe287](https://github.com/aws-amplify/amplify-cli/commit/5dfe2872c153047ebdc56bc4f671fd57c12379d9)) -- added exit code on remove ([#5427](https://github.com/aws-amplify/amplify-cli/issues/5427)) ([33132f7](https://github.com/aws-amplify/amplify-cli/commit/33132f764b290cafd345720409a5db8ea6088069)) - -### Features - -- **amplify-category-api:** add rds support for new regions ([#5360](https://github.com/aws-amplify/amplify-cli/issues/5360)) ([4f65ed1](https://github.com/aws-amplify/amplify-cli/commit/4f65ed1ba6ab76f7d018b998525b73aa1e47fbcd)), closes [#4739](https://github.com/aws-amplify/amplify-cli/issues/4739) - -## [2.23.9](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.23.8...amplify-category-api@2.23.9) (2020-09-25) - -### Bug Fixes - -- data inconsitency ([#5344](https://github.com/aws-amplify/amplify-cli/issues/5344)) ([bfe1903](https://github.com/aws-amplify/amplify-cli/commit/bfe19038b5b676056f45d7ffcc4c2460057936d8)) - -## [2.23.8](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.23.7...amplify-category-api@2.23.8) (2020-09-16) - -### Bug Fixes - -- checking undefined auth config ([#5313](https://github.com/aws-amplify/amplify-cli/issues/5313)) ([42810c9](https://github.com/aws-amplify/amplify-cli/commit/42810c98b0015f12119f3387749889a6bf6abe9b)) -- removes duplicate auth types ([#5272](https://github.com/aws-amplify/amplify-cli/issues/5272)) ([8747911](https://github.com/aws-amplify/amplify-cli/commit/8747911ff5a515e86971af7d5ad15681c64eb532)) - -## [2.23.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.23.6...amplify-category-api@2.23.7) (2020-09-09) - -**Note:** Version bump only for package amplify-category-api - -## [2.23.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.23.5...amplify-category-api@2.23.6) (2020-09-03) - -**Note:** Version bump only for package amplify-category-api - -## [2.23.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.23.4...amplify-category-api@2.23.5) (2020-09-03) - -**Note:** Version bump only for package amplify-category-api - -## [2.23.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.23.3...amplify-category-api@2.23.4) (2020-08-31) - -### Bug Fixes - -- sub \* for path parms in CFN policy ([#5092](https://github.com/aws-amplify/amplify-cli/issues/5092)) ([2942688](https://github.com/aws-amplify/amplify-cli/commit/29426884968314122b65a24b2f9658a618bf9120)) - -## [2.23.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.23.2...amplify-category-api@2.23.3) (2020-08-20) - -**Note:** Version bump only for package amplify-category-api - -## [2.23.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.23.1...amplify-category-api@2.23.2) (2020-08-14) - -**Note:** Version bump only for package amplify-category-api - -## [2.23.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.23.0...amplify-category-api@2.23.1) (2020-08-11) - -**Note:** Version bump only for package amplify-category-api - -# [2.23.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.22.0...amplify-category-api@2.23.0) (2020-08-06) - -### Bug Fixes - -- **amplify-category-api:** added check to read schema in schema dir ([#3871](https://github.com/aws-amplify/amplify-cli/issues/3871)) ([21bd229](https://github.com/aws-amplify/amplify-cli/commit/21bd229b5c15e4ce837da604ec73e7f40076170f)), closes [fixes#3082](https://github.com/fixes/issues/3082) -- return undefined for empty conflict resolution ([#4982](https://github.com/aws-amplify/amplify-cli/issues/4982)) ([7c5bf1a](https://github.com/aws-amplify/amplify-cli/commit/7c5bf1a36078a345d80ecbf2cea3a067ae1137e1)), closes [#4965](https://github.com/aws-amplify/amplify-cli/issues/4965) - -### Features - -- allow creation of REST API endpoint at root path (/) ([#4649](https://github.com/aws-amplify/amplify-cli/issues/4649)) ([49d8121](https://github.com/aws-amplify/amplify-cli/commit/49d8121ade1f06bf23d511523b88e9dd6c289073)), closes [#3868](https://github.com/aws-amplify/amplify-cli/issues/3868) [#4834](https://github.com/aws-amplify/amplify-cli/issues/4834) - -# [2.22.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.20.5...amplify-category-api@2.22.0) (2020-07-29) - -### Bug Fixes - -- populate API_KEY env var when present ([#4923](https://github.com/aws-amplify/amplify-cli/issues/4923)) ([81231f9](https://github.com/aws-amplify/amplify-cli/commit/81231f98305dd9e37bb64eb30a9c7307bb471ad9)) -- remove mutableParametersState from stored function-params ([#4897](https://github.com/aws-amplify/amplify-cli/issues/4897)) ([c608166](https://github.com/aws-amplify/amplify-cli/commit/c6081668798e94165ede40bb06439075946e3e86)) - -### Features - -- headless mode for API category ([#4834](https://github.com/aws-amplify/amplify-cli/issues/4834)) ([c2e09d7](https://github.com/aws-amplify/amplify-cli/commit/c2e09d73fd1bb461eeace8f4a7addd70a63047ad)) - -# [2.21.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.20.5...amplify-category-api@2.21.0) (2020-07-23) - -### Bug Fixes - -- remove mutableParametersState from stored function-params ([#4897](https://github.com/aws-amplify/amplify-cli/issues/4897)) ([6e379fa](https://github.com/aws-amplify/amplify-cli/commit/6e379fabd9f5ea2316ce91f03c3e7cb3aa39fe08)) - -### Features - -- headless mode for API category ([#4834](https://github.com/aws-amplify/amplify-cli/issues/4834)) ([b729266](https://github.com/aws-amplify/amplify-cli/commit/b729266b9bb519738ef88125784d72ac428f47e1)) - -## [2.20.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.20.4...amplify-category-api@2.20.5) (2020-07-18) - -**Note:** Version bump only for package amplify-category-api - -## [2.20.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.20.3...amplify-category-api@2.20.4) (2020-07-15) - -### Bug Fixes - -- **graphql-auth-transformer:** add a time delay when creating apiKey ([#4493](https://github.com/aws-amplify/amplify-cli/issues/4493)) ([1d56b40](https://github.com/aws-amplify/amplify-cli/commit/1d56b40d673b257e07905d9bc1830e8f9c8495a1)) - -## [2.20.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.20.2...amplify-category-api@2.20.3) (2020-07-14) - -**Note:** Version bump only for package amplify-category-api - -## [2.20.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.20.1...amplify-category-api@2.20.2) (2020-07-11) - -### Bug Fixes - -- **cli:** remove unnecessary stack trace log when adding services ([#4610](https://github.com/aws-amplify/amplify-cli/issues/4610)) ([5bee574](https://github.com/aws-amplify/amplify-cli/commit/5bee574bbcd956c032e7714b0813aedd7914a6cb)) - -### Reverts - -- Revert problematic PRs (#4803) ([7f38d81](https://github.com/aws-amplify/amplify-cli/commit/7f38d81ef2f890c25d39b02407c5255c8760c511)), closes [#4803](https://github.com/aws-amplify/amplify-cli/issues/4803) [#4796](https://github.com/aws-amplify/amplify-cli/issues/4796) [#4576](https://github.com/aws-amplify/amplify-cli/issues/4576) [#4575](https://github.com/aws-amplify/amplify-cli/issues/4575) [#4610](https://github.com/aws-amplify/amplify-cli/issues/4610) - -## [2.20.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.20.0...amplify-category-api@2.20.1) (2020-07-09) - -### Bug Fixes - -- validatePathName_validPath matcher ([#4559](https://github.com/aws-amplify/amplify-cli/issues/4559)) ([3cf5f91](https://github.com/aws-amplify/amplify-cli/commit/3cf5f914024e55904da0f782ea71bd62bfca40e3)) - -# [2.20.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.19.8...amplify-category-api@2.20.0) (2020-07-07) - -### Features - -- **cli:** usage measurement ([#3641](https://github.com/aws-amplify/amplify-cli/issues/3641)) ([30a7fe7](https://github.com/aws-amplify/amplify-cli/commit/30a7fe70f5838a766631befcc720a721e801bc5f)) -- Lambda layers ([#4697](https://github.com/aws-amplify/amplify-cli/issues/4697)) ([c55b2e0](https://github.com/aws-amplify/amplify-cli/commit/c55b2e0c3377127aaf887591d7bc20d7240ef11d)) - -## [2.19.8](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.19.7...amplify-category-api@2.19.8) (2020-06-25) - -**Note:** Version bump only for package amplify-category-api - -## [2.19.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.19.6...amplify-category-api@2.19.7) (2020-06-18) - -**Note:** Version bump only for package amplify-category-api - -## [2.19.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.19.5...amplify-category-api@2.19.6) (2020-06-11) - -**Note:** Version bump only for package amplify-category-api - -## [2.19.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.19.4...amplify-category-api@2.19.5) (2020-06-10) - -**Note:** Version bump only for package amplify-category-api - -## [2.19.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.19.3...amplify-category-api@2.19.4) (2020-06-02) - -**Note:** Version bump only for package amplify-category-api - -## [2.19.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.19.2...amplify-category-api@2.19.3) (2020-05-26) - -### Bug Fixes - -- **amplify-category-api:** toggle datastore in update ([#4276](https://github.com/aws-amplify/amplify-cli/issues/4276)) ([c522f29](https://github.com/aws-amplify/amplify-cli/commit/c522f295304410aeb1d6f60aaba9b466d3304ee1)), closes [#4058](https://github.com/aws-amplify/amplify-cli/issues/4058) - -## [2.19.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.19.1...amplify-category-api@2.19.2) (2020-05-15) - -**Note:** Version bump only for package amplify-category-api - -## [2.19.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.19.0...amplify-category-api@2.19.1) (2020-05-08) - -### Bug Fixes - -- incorrect type on graphql boilerplate schema ([#4070](https://github.com/aws-amplify/amplify-cli/issues/4070)) ([d96171a](https://github.com/aws-amplify/amplify-cli/commit/d96171a7461ecbb610c3cbcbcb05cdf5492dc8e5)) - -# [2.19.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.18.0...amplify-category-api@2.19.0) (2020-04-23) - -### Features - -- **amplify-category-api:** allow minified CF stack templates ([#3520](https://github.com/aws-amplify/amplify-cli/issues/3520)) ([6da2a63](https://github.com/aws-amplify/amplify-cli/commit/6da2a634548fdf48deb4b1144c67d1e1515abb80)), closes [#2914](https://github.com/aws-amplify/amplify-cli/issues/2914) - -# [2.18.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.17.1...amplify-category-api@2.18.0) (2020-04-06) - -### Features - -- uplevel enabling of datastore and update of auth configs to top ([#3495](https://github.com/aws-amplify/amplify-cli/issues/3495)) ([f406bb2](https://github.com/aws-amplify/amplify-cli/commit/f406bb29957c98caf427a3cb46e2126f6dcf212f)) - -## [2.17.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.17.0...amplify-category-api@2.17.1) (2020-03-26) - -**Note:** Version bump only for package amplify-category-api - -# [2.17.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.16.1...amplify-category-api@2.17.0) (2020-03-22) - -### Bug Fixes - -- **cli:** deleting the amplify app on delete ([#3568](https://github.com/aws-amplify/amplify-cli/issues/3568)) ([f39bbcb](https://github.com/aws-amplify/amplify-cli/commit/f39bbcb715875eeeb612bcbc40b275b33f85eaf6)), closes [#3239](https://github.com/aws-amplify/amplify-cli/issues/3239) -- update graphql schema to match docs ([#3652](https://github.com/aws-amplify/amplify-cli/issues/3652)) ([dc3c866](https://github.com/aws-amplify/amplify-cli/commit/dc3c8661066be6bfdbb404b81a73bfed1fcf0095)), closes [#3513](https://github.com/aws-amplify/amplify-cli/issues/3513) -- **graphql-elasticsearch-transformer:** fix duplicate records in es lambda ([#3712](https://github.com/aws-amplify/amplify-cli/issues/3712)) ([dd9f7e0](https://github.com/aws-amplify/amplify-cli/commit/dd9f7e0031a0dc68a9027de02f60bbe69d315c3d)), closes [#3602](https://github.com/aws-amplify/amplify-cli/issues/3602) [#3705](https://github.com/aws-amplify/amplify-cli/issues/3705) - -### Features - -- **amplify-category-function:** refactor to support runtime and template plugins ([#3517](https://github.com/aws-amplify/amplify-cli/issues/3517)) ([607ae21](https://github.com/aws-amplify/amplify-cli/commit/607ae21287941805f44ea8a9b78dd12d16d71f85)) - -## [2.16.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.16.0...amplify-category-api@2.16.1) (2020-03-10) - -**Note:** Version bump only for package amplify-category-api - -# [2.16.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.13.3...amplify-category-api@2.16.0) (2020-03-07) - -### Bug Fixes - -- **amplify-category-api:** plumb api id to resources that require it ([#3464](https://github.com/aws-amplify/amplify-cli/issues/3464)) ([2b2d52f](https://github.com/aws-amplify/amplify-cli/commit/2b2d52f05edc1190953965ca0f3ecd880ec66a63)), closes [#3431](https://github.com/aws-amplify/amplify-cli/issues/3431) [#3386](https://github.com/aws-amplify/amplify-cli/issues/3386) - -### Features - -- **amplify-category-api:** support path parameters in REST APIs ([#3394](https://github.com/aws-amplify/amplify-cli/issues/3394)) ([fa7d07e](https://github.com/aws-amplify/amplify-cli/commit/fa7d07e1f6f54185a37851ea9d4c840b092501cc)) - -## [2.14.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.13.5-beta.0...amplify-category-api@2.14.1) (2020-03-05) - -**Note:** Version bump only for package amplify-category-api - -## [2.13.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.13.2...amplify-category-api@2.13.3) (2020-02-13) - -**Note:** Version bump only for package amplify-category-api - -## [2.13.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.13.1...amplify-category-api@2.13.2) (2020-02-07) - -**Note:** Version bump only for package amplify-category-api - -## [2.13.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.13.0...amplify-category-api@2.13.1) (2020-01-24) - -### Bug Fixes - -- **amplify-category-api:** edit auth workflow if cognito is not used ([#3232](https://github.com/aws-amplify/amplify-cli/issues/3232)) ([f9473cf](https://github.com/aws-amplify/amplify-cli/commit/f9473cf50bbcf43a701f1f44b6f4d451dc2be237)), closes [#2967](https://github.com/aws-amplify/amplify-cli/issues/2967) - -# [2.13.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.30.0...amplify-category-api@2.13.0) (2020-01-23) - -### Bug Fixes - -- **amplify-category-api:** add config check in writeResolverConfig ([bed4929](https://github.com/aws-amplify/amplify-cli/commit/bed49295c22f372511abb94f7227ba686cccf214)) -- **amplify-category-api:** fix conflict resolution learn more ([#2954](https://github.com/aws-amplify/amplify-cli/issues/2954)) ([5b0825a](https://github.com/aws-amplify/amplify-cli/commit/5b0825a44ad0b64180eb5cc373944ef82829eb06)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- Delete all ([#2615](https://github.com/aws-amplify/amplify-cli/issues/2615)) ([5467679](https://github.com/aws-amplify/amplify-cli/commit/54676797b913d4a2c284c62244c8ccf8e55a44d8)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.12.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.30.0...amplify-category-api@2.12.0) (2020-01-09) - -### Bug Fixes - -- **amplify-category-api:** add config check in writeResolverConfig ([bed4929](https://github.com/aws-amplify/amplify-cli/commit/bed49295c22f372511abb94f7227ba686cccf214)) -- **amplify-category-api:** fix conflict resolution learn more ([#2954](https://github.com/aws-amplify/amplify-cli/issues/2954)) ([5b0825a](https://github.com/aws-amplify/amplify-cli/commit/5b0825a44ad0b64180eb5cc373944ef82829eb06)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- Delete all ([#2615](https://github.com/aws-amplify/amplify-cli/issues/2615)) ([5467679](https://github.com/aws-amplify/amplify-cli/commit/54676797b913d4a2c284c62244c8ccf8e55a44d8)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.11.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.30.0...amplify-category-api@2.11.0) (2019-12-31) - -### Bug Fixes - -- **amplify-category-api:** add config check in writeResolverConfig ([bed4929](https://github.com/aws-amplify/amplify-cli/commit/bed49295c22f372511abb94f7227ba686cccf214)) -- **amplify-category-api:** fix conflict resolution learn more ([#2954](https://github.com/aws-amplify/amplify-cli/issues/2954)) ([5b0825a](https://github.com/aws-amplify/amplify-cli/commit/5b0825a44ad0b64180eb5cc373944ef82829eb06)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- Delete all ([#2615](https://github.com/aws-amplify/amplify-cli/issues/2615)) ([5467679](https://github.com/aws-amplify/amplify-cli/commit/54676797b913d4a2c284c62244c8ccf8e55a44d8)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.10.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.30.0...amplify-category-api@2.10.0) (2019-12-28) - -### Bug Fixes - -- **amplify-category-api:** add config check in writeResolverConfig ([bed4929](https://github.com/aws-amplify/amplify-cli/commit/bed49295c22f372511abb94f7227ba686cccf214)) -- **amplify-category-api:** fix conflict resolution learn more ([#2954](https://github.com/aws-amplify/amplify-cli/issues/2954)) ([5b0825a](https://github.com/aws-amplify/amplify-cli/commit/5b0825a44ad0b64180eb5cc373944ef82829eb06)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- Delete all ([#2615](https://github.com/aws-amplify/amplify-cli/issues/2615)) ([5467679](https://github.com/aws-amplify/amplify-cli/commit/54676797b913d4a2c284c62244c8ccf8e55a44d8)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.9.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.30.0...amplify-category-api@2.9.0) (2019-12-26) - -### Bug Fixes - -- **amplify-category-api:** add config check in writeResolverConfig ([bed4929](https://github.com/aws-amplify/amplify-cli/commit/bed49295c22f372511abb94f7227ba686cccf214)) -- **amplify-category-api:** fix conflict resolution learn more ([#2954](https://github.com/aws-amplify/amplify-cli/issues/2954)) ([5b0825a](https://github.com/aws-amplify/amplify-cli/commit/5b0825a44ad0b64180eb5cc373944ef82829eb06)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- Delete all ([#2615](https://github.com/aws-amplify/amplify-cli/issues/2615)) ([5467679](https://github.com/aws-amplify/amplify-cli/commit/54676797b913d4a2c284c62244c8ccf8e55a44d8)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.8.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.30.0...amplify-category-api@2.8.0) (2019-12-25) - -### Bug Fixes - -- **amplify-category-api:** add config check in writeResolverConfig ([bed4929](https://github.com/aws-amplify/amplify-cli/commit/bed49295c22f372511abb94f7227ba686cccf214)) -- **amplify-category-api:** fix conflict resolution learn more ([#2954](https://github.com/aws-amplify/amplify-cli/issues/2954)) ([5b0825a](https://github.com/aws-amplify/amplify-cli/commit/5b0825a44ad0b64180eb5cc373944ef82829eb06)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- Delete all ([#2615](https://github.com/aws-amplify/amplify-cli/issues/2615)) ([5467679](https://github.com/aws-amplify/amplify-cli/commit/54676797b913d4a2c284c62244c8ccf8e55a44d8)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.7.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.30.0...amplify-category-api@2.7.0) (2019-12-20) - -### Bug Fixes - -- **amplify-category-api:** add config check in writeResolverConfig ([bed4929](https://github.com/aws-amplify/amplify-cli/commit/bed49295c22f372511abb94f7227ba686cccf214)) -- **amplify-category-api:** fix conflict resolution learn more ([#2954](https://github.com/aws-amplify/amplify-cli/issues/2954)) ([5b0825a](https://github.com/aws-amplify/amplify-cli/commit/5b0825a44ad0b64180eb5cc373944ef82829eb06)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- Delete all ([#2615](https://github.com/aws-amplify/amplify-cli/issues/2615)) ([5467679](https://github.com/aws-amplify/amplify-cli/commit/54676797b913d4a2c284c62244c8ccf8e55a44d8)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.6.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.30.0...amplify-category-api@2.6.0) (2019-12-10) - -### Bug Fixes - -- **amplify-category-api:** fix conflict resolution learn more ([#2954](https://github.com/aws-amplify/amplify-cli/issues/2954)) ([5b0825a](https://github.com/aws-amplify/amplify-cli/commit/5b0825a44ad0b64180eb5cc373944ef82829eb06)) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- Delete all ([#2615](https://github.com/aws-amplify/amplify-cli/issues/2615)) ([5467679](https://github.com/aws-amplify/amplify-cli/commit/54676797b913d4a2c284c62244c8ccf8e55a44d8)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.4.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.30.0...amplify-category-api@2.4.0) (2019-12-03) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- Delete all ([#2615](https://github.com/aws-amplify/amplify-cli/issues/2615)) ([5467679](https://github.com/aws-amplify/amplify-cli/commit/54676797b913d4a2c284c62244c8ccf8e55a44d8)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.3.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.30.0...amplify-category-api@2.3.0) (2019-12-01) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- Delete all ([#2615](https://github.com/aws-amplify/amplify-cli/issues/2615)) ([5467679](https://github.com/aws-amplify/amplify-cli/commit/54676797b913d4a2c284c62244c8ccf8e55a44d8)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.2.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.30.0...amplify-category-api@2.2.0) (2019-11-27) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- Delete all ([#2615](https://github.com/aws-amplify/amplify-cli/issues/2615)) ([5467679](https://github.com/aws-amplify/amplify-cli/commit/54676797b913d4a2c284c62244c8ccf8e55a44d8)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [2.1.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.30.0...amplify-category-api@2.1.0) (2019-11-27) - -### Features - -- conditions update ([#2789](https://github.com/aws-amplify/amplify-cli/issues/2789)) ([3fae391](https://github.com/aws-amplify/amplify-cli/commit/3fae391340d5fd151e1c43286c90142b5ab0eab0)) -- Delete all ([#2615](https://github.com/aws-amplify/amplify-cli/issues/2615)) ([5467679](https://github.com/aws-amplify/amplify-cli/commit/54676797b913d4a2c284c62244c8ccf8e55a44d8)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [1.13.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.7.11...amplify-category-api@1.13.0) (2019-08-30) - -### Bug Fixes - -- **amplify-provider-awscloudformation:** apigw unauth access ([#1906](https://github.com/aws-amplify/amplify-cli/issues/1906)) ([bcd0d02](https://github.com/aws-amplify/amplify-cli/commit/bcd0d02)) -- [#429](https://github.com/aws-amplify/amplify-cli/issues/429) - Editor hanging bug ([#2086](https://github.com/aws-amplify/amplify-cli/issues/2086)) ([6767445](https://github.com/aws-amplify/amplify-cli/commit/6767445)) -- move test package dependencies to devDependencies ([#2034](https://github.com/aws-amplify/amplify-cli/issues/2034)) ([f5623d0](https://github.com/aws-amplify/amplify-cli/commit/f5623d0)) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [1.12.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.7.11...amplify-category-api@1.12.0) (2019-08-28) - -### Bug Fixes - -- **amplify-provider-awscloudformation:** apigw unauth access ([#1906](https://github.com/aws-amplify/amplify-cli/issues/1906)) ([bcd0d02](https://github.com/aws-amplify/amplify-cli/commit/bcd0d02)) -- [#429](https://github.com/aws-amplify/amplify-cli/issues/429) - Editor hanging bug ([#2086](https://github.com/aws-amplify/amplify-cli/issues/2086)) ([6767445](https://github.com/aws-amplify/amplify-cli/commit/6767445)) -- move test package dependencies to devDependencies ([#2034](https://github.com/aws-amplify/amplify-cli/issues/2034)) ([f5623d0](https://github.com/aws-amplify/amplify-cli/commit/f5623d0)) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [1.11.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.7.11...amplify-category-api@1.11.0) (2019-08-13) - -### Bug Fixes - -- **amplify-provider-awscloudformation:** apigw unauth access ([#1906](https://github.com/aws-amplify/amplify-cli/issues/1906)) ([bcd0d02](https://github.com/aws-amplify/amplify-cli/commit/bcd0d02)) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [1.10.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.7.11...amplify-category-api@1.10.0) (2019-08-07) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [1.9.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.7.11...amplify-category-api@1.9.0) (2019-08-02) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -# [1.8.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.7.11...amplify-category-api@1.8.0) (2019-07-31) - -### Features - -- adding amplify cli predictions category ([#1936](https://github.com/aws-amplify/amplify-cli/issues/1936)) ([b7b7c2c](https://github.com/aws-amplify/amplify-cli/commit/b7b7c2c)) -- sanity check ([#1815](https://github.com/aws-amplify/amplify-cli/issues/1815)) ([54a8dbe](https://github.com/aws-amplify/amplify-cli/commit/54a8dbe)) - -## [1.7.11](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.7.10...amplify-category-api@1.7.11) (2019-07-24) - -**Note:** Version bump only for package amplify-category-api - -## [1.7.10](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.7.8...amplify-category-api@1.7.10) (2019-07-23) - -**Note:** Version bump only for package amplify-category-api - -## [1.7.8](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.7.7...amplify-category-api@1.7.8) (2019-07-10) - -**Note:** Version bump only for package amplify-category-api - -## [1.7.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.7.6...amplify-category-api@1.7.7) (2019-07-09) - -**Note:** Version bump only for package amplify-category-api - -## [1.7.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.7.4...amplify-category-api@1.7.6) (2019-06-30) - -**Note:** Version bump only for package amplify-category-api - -## [1.7.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.7.3...amplify-category-api@1.7.4) (2019-06-26) - -### Bug Fixes - -- **amplify-category-api:** fix init env bug ([#1715](https://github.com/aws-amplify/amplify-cli/issues/1715)) ([1e21371](https://github.com/aws-amplify/amplify-cli/commit/1e21371)), closes [#1713](https://github.com/aws-amplify/amplify-cli/issues/1713) - -## [1.7.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.7.2...amplify-category-api@1.7.3) (2019-06-20) - -### Bug Fixes - -- **cli:** fix inquirer version ([#1690](https://github.com/aws-amplify/amplify-cli/issues/1690)) ([9246032](https://github.com/aws-amplify/amplify-cli/commit/9246032)), closes [#1688](https://github.com/aws-amplify/amplify-cli/issues/1688) - -## [1.7.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.7.1...amplify-category-api@1.7.2) (2019-06-18) - -**Note:** Version bump only for package amplify-category-api - -## [1.7.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.7.0...amplify-category-api@1.7.1) (2019-06-12) - -**Note:** Version bump only for package amplify-category-api - -# [1.7.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.6.1...amplify-category-api@1.7.0) (2019-06-11) - -### Bug Fixes - -- fixing the IAM policies for AppSync API ([#1634](https://github.com/aws-amplify/amplify-cli/issues/1634)) ([9fb2fa9](https://github.com/aws-amplify/amplify-cli/commit/9fb2fa9)) - -### Features - -- add graphQLEndpoint as an env var to lambda functions ([#1641](https://github.com/aws-amplify/amplify-cli/issues/1641)) ([ae825a6](https://github.com/aws-amplify/amplify-cli/commit/ae825a6)), closes [#1620](https://github.com/aws-amplify/amplify-cli/issues/1620) - -## [1.6.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.6.0...amplify-category-api@1.6.1) (2019-06-06) - -**Note:** Version bump only for package amplify-category-api - -# [1.6.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.5.10...amplify-category-api@1.6.0) (2019-05-29) - -### Features - -- flow to add policies to access amplify resources from Lambda ([#1462](https://github.com/aws-amplify/amplify-cli/issues/1462)) ([fee247c](https://github.com/aws-amplify/amplify-cli/commit/fee247c)) - -## [1.5.10](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.5.9...amplify-category-api@1.5.10) (2019-05-24) - -**Note:** Version bump only for package amplify-category-api - -## [1.5.9](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.5.8...amplify-category-api@1.5.9) (2019-05-21) - -**Note:** Version bump only for package amplify-category-api - -## [1.5.8](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.5.7...amplify-category-api@1.5.8) (2019-05-17) - -**Note:** Version bump only for package amplify-category-api - -## [1.5.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.5.6...amplify-category-api@1.5.7) (2019-05-07) - -**Note:** Version bump only for package amplify-category-api - -## [1.5.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.5.5...amplify-category-api@1.5.6) (2019-04-30) - -### Bug Fixes - -- update CLI to handle UTF8 BOM ([#1357](https://github.com/aws-amplify/amplify-cli/issues/1357)) ([b0afa07](https://github.com/aws-amplify/amplify-cli/commit/b0afa07)), closes [#1355](https://github.com/aws-amplify/amplify-cli/issues/1355) [#1122](https://github.com/aws-amplify/amplify-cli/issues/1122) - -## [1.5.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.5.4...amplify-category-api@1.5.5) (2019-04-25) - -**Note:** Version bump only for package amplify-category-api - -## [1.5.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.5.3...amplify-category-api@1.5.4) (2019-04-24) - -**Note:** Version bump only for package amplify-category-api - -## [1.5.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.5.2...amplify-category-api@1.5.3) (2019-04-16) - -**Note:** Version bump only for package amplify-category-api - -## [1.5.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.5.1...amplify-category-api@1.5.2) (2019-04-16) - -**Note:** Version bump only for package amplify-category-api - -## [1.5.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.4.0...amplify-category-api@1.5.1) (2019-04-09) - -**Note:** Version bump only for package amplify-category-api - -# [1.4.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.0.8...amplify-category-api@1.4.0) (2019-04-03) - -### Features - -- support for provisioning Cognito Hosted UI and support CRUD operations in Storage and API categories ([729b0de](https://github.com/aws-amplify/amplify-cli/commit/729b0de)) - -## [1.0.8](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.0.7...amplify-category-api@1.0.8) (2019-03-22) - -**Note:** Version bump only for package amplify-category-api - -## [1.0.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.0.6...amplify-category-api@1.0.7) (2019-02-26) - -**Note:** Version bump only for package amplify-category-api - -## [1.0.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.0.5...amplify-category-api@1.0.6) (2019-02-22) - -### Bug Fixes - -- **amplify-category-api:** add check for provider during migration ([3207e41](https://github.com/aws-amplify/amplify-cli/commit/3207e41)), closes [#918](https://github.com/aws-amplify/amplify-cli/issues/918) - -## [1.0.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.0.3-beta.0...amplify-category-api@1.0.5) (2019-02-11) - -**Note:** Version bump only for package amplify-category-api - -## [1.0.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.0.3-beta.0...amplify-category-api@1.0.3) (2019-02-11) - -**Note:** Version bump only for package amplify-category-api - -## [1.0.3-beta.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@1.0.2...amplify-category-api@1.0.3-beta.0) (2019-02-11) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.2.1-multienv.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.2.1-multienv.5...amplify-category-api@0.2.1-multienv.7) (2019-01-30) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.2.1-multienv.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.2.1-multienv.5...amplify-category-api@0.2.1-multienv.6) (2019-01-16) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.2.1-multienv.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.2.1-multienv.4...amplify-category-api@0.2.1-multienv.5) (2018-12-28) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.2.1-multienv.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.2.1-multienv.3...amplify-category-api@0.2.1-multienv.4) (2018-12-21) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.2.1-multienv.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.2.1-multienv.2...amplify-category-api@0.2.1-multienv.3) (2018-12-05) - -### Bug Fixes - -- **cli:** remove calls to gluegun's prompt.confirm ([#546](https://github.com/aws-amplify/amplify-cli/issues/546)) ([0080ddb](https://github.com/aws-amplify/amplify-cli/commit/0080ddb)) - - - -## [0.2.1-multienv.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.2.1-multienv.1...amplify-category-api@0.2.1-multienv.2) (2018-12-04) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.2.1-multienv.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.2.1-multienv.0...amplify-category-api@0.2.1-multienv.1) (2018-11-28) - -### Features - -- add a warning on migration and force compile gql schema ([77fb557](https://github.com/aws-amplify/amplify-cli/commit/77fb557)) -- migration of API GW and Interactions ([a91ba9a](https://github.com/aws-amplify/amplify-cli/commit/a91ba9a)) -- migration of categories - s3,dynamo,lambda,appsync ([#495](https://github.com/aws-amplify/amplify-cli/issues/495)) ([1ef1d21](https://github.com/aws-amplify/amplify-cli/commit/1ef1d21)) - - - -## [0.2.1-multienv.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.34-multienv.2...amplify-category-api@0.2.1-multienv.0) (2018-11-21) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.34-multienv.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.34-multienv.1...amplify-category-api@0.1.34-multienv.2) (2018-11-19) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.34-multienv.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.34-multienv.0...amplify-category-api@0.1.34-multienv.1) (2018-11-19) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.34-multienv.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.33...amplify-category-api@0.1.34-multienv.0) (2018-11-16) - -### Features - -- multi-environment support for API Gateway ([#418](https://github.com/aws-amplify/amplify-cli/issues/418)) ([24ddf83](https://github.com/aws-amplify/amplify-cli/commit/24ddf83)) -- multi-environment support for interactions category ([4ca2617](https://github.com/aws-amplify/amplify-cli/commit/4ca2617)) - - - -## [0.1.33](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.33-beta.0...amplify-category-api@0.1.33) (2018-11-09) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.33-beta.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.13...amplify-category-api@0.1.33-beta.0) (2018-11-09) - -### Features - -- add option to open AppSync console using the CLI ([#386](https://github.com/aws-amplify/amplify-cli/issues/386)) ([3874a57](https://github.com/aws-amplify/amplify-cli/commit/3874a57)) - - - -## [0.1.32](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.32-beta.0...amplify-category-api@0.1.32) (2018-11-05) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.32-beta.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.13...amplify-category-api@0.1.32-beta.0) (2018-11-05) - -### Features - -- add option to open AppSync console using the CLI ([#386](https://github.com/aws-amplify/amplify-cli/issues/386)) ([3874a57](https://github.com/aws-amplify/amplify-cli/commit/3874a57)) - - - -## [0.1.31](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.13...amplify-category-api@0.1.31) (2018-11-02) - -### Features - -- add option to open AppSync console using the CLI ([#386](https://github.com/aws-amplify/amplify-cli/issues/386)) ([3874a57](https://github.com/aws-amplify/amplify-cli/commit/3874a57)) - - - -## [0.1.30](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.30-beta.0...amplify-category-api@0.1.30) (2018-11-02) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.30-beta.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.13...amplify-category-api@0.1.30-beta.0) (2018-11-02) - -### Features - -- add option to open AppSync console using the CLI ([#386](https://github.com/aws-amplify/amplify-cli/issues/386)) ([3874a57](https://github.com/aws-amplify/amplify-cli/commit/3874a57)) - - - -## [0.1.29](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.29-beta.0...amplify-category-api@0.1.29) (2018-10-23) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.29-beta.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.13...amplify-category-api@0.1.29-beta.0) (2018-10-23) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.28](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.28-beta.0...amplify-category-api@0.1.28) (2018-10-18) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.28-beta.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.13...amplify-category-api@0.1.28-beta.0) (2018-10-12) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.13](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.12...amplify-category-api@0.1.13) (2018-08-23) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.12](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.11...amplify-category-api@0.1.12) (2018-08-23) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.11](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.9...amplify-category-api@0.1.11) (2018-08-23) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.10](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.9...amplify-category-api@0.1.10) (2018-08-23) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.9](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.8...amplify-category-api@0.1.9) (2018-08-23) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.8](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.7...amplify-category-api@0.1.8) (2018-08-23) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.6...amplify-category-api@0.1.7) (2018-08-23) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.5...amplify-category-api@0.1.6) (2018-08-23) - -**Note:** Version bump only for package amplify-category-api - - - -## [0.1.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@0.1.4...amplify-category-api@0.1.5) (2018-08-23) - -**Note:** Version bump only for package amplify-category-api - - - -## 0.1.4 (2018-08-23) - -**Note:** Version bump only for package amplify-category-api - - - -## 0.1.3 (2018-08-23) - -**Note:** Version bump only for package amplify-category-api - - - -## 0.1.2 (2018-08-23) - -**Note:** Version bump only for package amplify-category-api - - - -## 0.1.1 (2018-08-23) - -**Note:** Version bump only for package amplify-category-api diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json deleted file mode 100644 index 8be24977fe..0000000000 --- a/packages/amplify-category-api/package.json +++ /dev/null @@ -1,126 +0,0 @@ -{ - "name": "@aws-amplify/amplify-category-api", - "version": "5.12.6", - "description": "Amplify CLI API Category Plugin", - "repository": { - "type": "git", - "url": "https://github.com/aws-amplify/amplify-category-api.git", - "directory": "packages/amplify-category-api" - }, - "author": "Amazon Web Services", - "license": "Apache-2.0", - "main": "lib/index.js", - "scripts": { - "build": "tsc", - "watch": "tsc -w", - "clean": "rimraf lib tsconfig.tsbuildinfo node_modules", - "test": "jest", - "generateSchemas": "ts-node ./scripts/generateApiSchemas.ts", - "extract-api": "ts-node ../../scripts/extract-api.ts" - }, - "keywords": [ - "graphql", - "cloudformation", - "aws", - "amplify", - "api" - ], - "publishConfig": { - "access": "public" - }, - "dependencies": { - "@aws-amplify/graphql-auth-transformer": "3.6.5", - "@aws-amplify/graphql-schema-generator": "0.9.4", - "@aws-amplify/graphql-transformer": "1.6.5", - "@aws-amplify/graphql-transformer-core": "2.9.3", - "@aws-amplify/graphql-transformer-interfaces": "3.10.1", - "@aws-amplify/graphql-transformer-migrator": "2.2.27", - "@aws-cdk/aws-apigatewayv2-alpha": "~2.114.1-alpha.0", - "@aws-sdk/client-ec2": "3.624.0", - "@aws-sdk/client-iam": "3.624.0", - "@aws-sdk/client-lambda": "3.624.0", - "@graphql-tools/merge": "^6.0.18", - "@octokit/rest": "^18.0.9", - "aws-sdk": "^2.1113.0", - "chalk": "^4.1.1", - "cloudform-types": "^4.2.0", - "fs-extra": "^8.1.0", - "graphql": "^15.5.0", - "graphql-auth-transformer": "7.2.82", - "graphql-connection-transformer": "5.2.80", - "graphql-dynamodb-transformer": "7.2.80", - "graphql-elasticsearch-transformer": "5.2.81", - "graphql-function-transformer": "3.3.71", - "graphql-http-transformer": "5.2.80", - "graphql-key-transformer": "3.2.80", - "graphql-predictions-transformer": "3.2.80", - "graphql-relational-schema-transformer": "2.21.34", - "graphql-transformer-common": "4.31.1", - "graphql-transformer-core": "8.2.13", - "graphql-versioned-transformer": "5.2.80", - "import-from": "^3.0.0", - "import-global": "^0.1.0", - "inquirer": "^7.3.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.21", - "node-fetch": "^2.6.7", - "ora": "^4.0.3", - "rimraf": "^3.0.0", - "uuid": "^8.3.2" - }, - "peerDependencies": { - "@aws-amplify/amplify-cli-core": "^4.3.9", - "@aws-amplify/amplify-environment-parameters": "^1.9.14", - "@aws-amplify/amplify-prompts": "^2.8.6", - "@aws-amplify/amplify-provider-awscloudformation": "^8.10.11", - "amplify-headless-interface": "^1.17.7", - "amplify-util-headless-input": "^1.9.18", - "aws-cdk-lib": "^2.129.0", - "constructs": "^10.3.0" - }, - "devDependencies": { - "@aws-amplify/graphql-transformer-test-utils": "0.5.6", - "@types/js-yaml": "^4.0.0", - "@types/node": "^12.12.6", - "amplify-util-headless-input": "^1.9.18", - "ts-jest": "26.4.4" - }, - "jest": { - "testURL": "http://localhost", - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, - "testRegex": "((\\.|/)(test|spec))\\.(jsx?|tsx?)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], - "collectCoverage": true, - "coverageProvider": "v8", - "coverageThreshold": { - "global": { - "branches": 68, - "functions": 42, - "lines": 40 - } - }, - "coverageReporters": [ - "clover", - "text" - ], - "moduleNameMapper": { - "^csv-parse/sync": "/../../node_modules/csv-parse/dist/cjs/sync.cjs" - }, - "testEnvironment": "../../FixJestEnvironment.js", - "collectCoverageFrom": [ - "src/**/*.ts" - ], - "coveragePathIgnorePatterns": [ - "/__tests__/" - ] - } -} diff --git a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/package.json b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/package.json deleted file mode 100644 index eb964ab1b4..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "express-lasagna", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": {}, - "keywords": [], - "author": "", - "license": "ISC", - "dependencies": { - "@aws-sdk/lib-dynamodb": "^3.624.0", - "@aws-sdk/client-dynamodb": "^3.624.0", - "axios": "^1.6.0", - "body-parser": "^1.19.0", - "express": "^4.17.1", - "redis": "^3.0.2" - } -} diff --git a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/package.json b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/package.json deleted file mode 100644 index d0b0d28a80..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "express-lasagna", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - }, - "keywords": [], - "author": "", - "license": "ISC", - "dependencies": { - "@aws-sdk/lib-dynamodb": "^3.624.0", - "@aws-sdk/client-dynamodb": "^3.624.0", - "body-parser": "^1.19.0", - "express": "^4.17.1" - } - } diff --git a/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/package.json b/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/package.json deleted file mode 100644 index 098b3e2568..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "graphql", - "version": "1.0.0", - "description": "Sample GraphQL server for Fargate", - "main": "index.js", - "scripts": {}, - "author": "", - "license": "ISC", - "dependencies": { - "@aws-sdk/lib-dynamodb": "^3.624.0", - "@aws-sdk/client-dynamodb": "^3.624.0", - "express": "^4.17.1", - "express-graphql": "^0.11.0", - "graphql": "^15.4.0" - } -} diff --git a/packages/amplify-schema-validator/API.md b/packages/amplify-schema-validator/API.md deleted file mode 100644 index 5ef0d8aa37..0000000000 --- a/packages/amplify-schema-validator/API.md +++ /dev/null @@ -1,17 +0,0 @@ -## API Report File for "@aws-amplify/graphql-schema-validation" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -// @public (undocumented) -export const validateSchema: (schemaString: string) => void; - -// Warning: (ae-forgotten-export) The symbol "ValidateSchemaProps" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export const validateSchemaWithContext: (schemaString: string, props: ValidateSchemaProps) => void; - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/amplify-schema-validator/CHANGELOG.md b/packages/amplify-schema-validator/CHANGELOG.md deleted file mode 100644 index 7fbaee285c..0000000000 --- a/packages/amplify-schema-validator/CHANGELOG.md +++ /dev/null @@ -1,88 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [0.3.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-schema-validation@0.3.1...@aws-amplify/graphql-schema-validation@0.3.2) (2024-06-04) - -### Bug Fixes - -- added [@default](https://github.com/default) schema validations ([#2541](https://github.com/aws-amplify/amplify-category-api/issues/2541)) ([26ad761](https://github.com/aws-amplify/amplify-category-api/commit/26ad761d3e5936036a85d6d9ce574fd27a17ee4b)) - -## [0.3.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-schema-validation@0.3.0...@aws-amplify/graphql-schema-validation@0.3.1) (2024-02-28) - -**Note:** Version bump only for package @aws-amplify/graphql-schema-validation - -# [0.3.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-schema-validation@0.2.10...@aws-amplify/graphql-schema-validation@0.3.0) (2024-01-22) - -### Features - -- add Schema validations ([#2129](https://github.com/aws-amplify/amplify-category-api/issues/2129)) ([4b1a71f](https://github.com/aws-amplify/amplify-category-api/commit/4b1a71fd4f23e2895b2db794892f89339700fbbb)) - -## [0.2.10](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-schema-validation@0.2.9...@aws-amplify/graphql-schema-validation@0.2.10) (2023-12-18) - -**Note:** Version bump only for package @aws-amplify/graphql-schema-validation - -## [0.2.9](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-schema-validation@0.2.8...@aws-amplify/graphql-schema-validation@0.2.9) (2023-12-06) - -**Note:** Version bump only for package @aws-amplify/graphql-schema-validation - -## [0.2.8](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-schema-validation@0.2.7...@aws-amplify/graphql-schema-validation@0.2.8) (2023-11-15) - -**Note:** Version bump only for package @aws-amplify/graphql-schema-validation - -## [0.2.7](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-schema-validation@0.2.6...@aws-amplify/graphql-schema-validation@0.2.7) (2023-08-28) - -### Bug Fixes - -- **graphql-schema-validation:** relationship names not unique ([#1819](https://github.com/aws-amplify/amplify-category-api/issues/1819)) ([275affc](https://github.com/aws-amplify/amplify-category-api/commit/275affc821a0981cbba167d894bc5d9e47816046)) - -## [0.2.6](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-schema-validation@0.2.5...@aws-amplify/graphql-schema-validation@0.2.6) (2023-08-09) - -**Note:** Version bump only for package @aws-amplify/graphql-schema-validation - -## [0.2.5](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-schema-validation@0.2.4...@aws-amplify/graphql-schema-validation@0.2.5) (2023-07-21) - -**Note:** Version bump only for package @aws-amplify/graphql-schema-validation - -## [0.2.4](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-schema-validation@0.2.3...@aws-amplify/graphql-schema-validation@0.2.4) (2023-07-17) - -**Note:** Version bump only for package @aws-amplify/graphql-schema-validation - -## [0.2.3](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-schema-validation@0.2.2...@aws-amplify/graphql-schema-validation@0.2.3) (2023-04-25) - -### Bug Fixes - -- fixed existing schema validation ([36d583d](https://github.com/aws-amplify/amplify-category-api/commit/36d583d7256c6847bd757568ba98932a533daa66)) - -## [0.2.2](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-schema-validation@0.2.1...@aws-amplify/graphql-schema-validation@0.2.2) (2023-03-30) - -**Note:** Version bump only for package @aws-amplify/graphql-schema-validation - -## [0.2.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-schema-validation@0.2.0...@aws-amplify/graphql-schema-validation@0.2.1) (2023-03-15) - -**Note:** Version bump only for package @aws-amplify/graphql-schema-validation - -# [0.2.0](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-schema-validation@0.1.1...@aws-amplify/graphql-schema-validation@0.2.0) (2023-02-27) - -### Bug Fixes - -- fixed coverage ([cb12702](https://github.com/aws-amplify/amplify-category-api/commit/cb127021105e4a114cb862c29a22ca84491aab88)) -- fixed index should be non scalar case for list type ([6ed2359](https://github.com/aws-amplify/amplify-category-api/commit/6ed2359b146d5ce24595c46acefcc1c10b12b10a)) -- minor refactoring ([9d99b6c](https://github.com/aws-amplify/amplify-category-api/commit/9d99b6c9cb2068512aa0bac6b2c8545ad0b5c57e)) - -### Features - -- added schema validators ([2c8c136](https://github.com/aws-amplify/amplify-category-api/commit/2c8c1362fa7410d8fd0e67bbe8c7af61f456c2c9)) - -## [0.1.1](https://github.com/aws-amplify/amplify-category-api/compare/@aws-amplify/graphql-schema-validation@0.1.0...@aws-amplify/graphql-schema-validation@0.1.1) (2023-02-10) - -### Bug Fixes - -- update belongs to relation required logic to handle nested schemas ([9a9b5e9](https://github.com/aws-amplify/amplify-category-api/commit/9a9b5e929de8126da2c6c058bbf93b79bf8db81c)) - -# 0.1.0 (2023-01-26) - -### Features - -- add amplify-schema-validator package ([d92ba6d](https://github.com/aws-amplify/amplify-category-api/commit/d92ba6db6d0b33e88fbe37e95bc240b42c888a9e)) diff --git a/packages/amplify-schema-validator/README.md b/packages/amplify-schema-validator/README.md deleted file mode 100644 index 410bbb6f60..0000000000 --- a/packages/amplify-schema-validator/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Amplify GraphQL Schema Validator - -This package contains logic used by AWS Amplify development teams to validate -that customer's `schema.graphql` for their Amplify app is valid. - -## Contributing - -To add a validator, simply create a new `*.ts` file under `src/validators` -exporting a function named `validate` that takes a `DocumentNode` object and -returns void if successful, and returns an array of actionable `ValidationError` objects if not. - -Validators should be pure functions that do not depend on or mutate state. - -Once your validator is ready, update `src/index.ts` and import your validator -there. - -Ensure your validator is tested and conforms to our coverage standards. diff --git a/packages/amplify-schema-validator/api-extractor.json b/packages/amplify-schema-validator/api-extractor.json deleted file mode 100644 index 6fe5181061..0000000000 --- a/packages/amplify-schema-validator/api-extractor.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "/dist/index.d.ts", - "bundledPackages": [], - "newlineKind": "lf", - - "apiReport": { - "enabled": true, - "reportFileName": "API.md", - "reportFolder": "/" - }, - - "docModel": { - "enabled": false - }, - - "dtsRollup": { - "enabled": false - }, - - "tsdocMetadata": { - "enabled": false - }, - - "messages": { - "compilerMessageReporting": { - "default": { - "logLevel": "none" - } - }, - - "extractorMessageReporting": { - "default": { - "logLevel": "none" - } - }, - - "tsdocMessageReporting": { - "default": { - "logLevel": "none" - } - } - } -} diff --git a/packages/amplify-schema-validator/jest.config.js b/packages/amplify-schema-validator/jest.config.js deleted file mode 100644 index 453df6233e..0000000000 --- a/packages/amplify-schema-validator/jest.config.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - preset: 'ts-jest', - collectCoverage: true, - coverageProvider: 'v8', - collectCoverageFrom: ['/src/**/*.{ts,js}'], - coveragePathIgnorePatterns: ['/__tests__/'], - coverageReporters: ['cobertura', 'lcov', 'text', 'clover'], - testPathIgnorePatterns: ['/node_modules/', '/dist/', '/src/__tests__/helpers/'], - testEnvironment: 'jsdom', - coverageThreshold: { - global: { - lines: 90, - functions: 90, - branches: 65, - }, - }, -}; diff --git a/packages/amplify-schema-validator/package.json b/packages/amplify-schema-validator/package.json deleted file mode 100644 index 6d4cf4ef10..0000000000 --- a/packages/amplify-schema-validator/package.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "@aws-amplify/graphql-schema-validation", - "main": "./dist/index.js", - "private": true, - "types": "./dist/index.d.ts", - "version": "0.3.2", - "files": [ - "dist", - "!**/__tests__/**/*" - ], - "scripts": { - "build": "tsc && yarn size", - "clean": "rimraf -rf build node_modules dist coverage", - "test": "jest --coverage", - "size": "size-limit", - "extract-api": "ts-node ../../scripts/extract-api.ts" - }, - "devDependencies": { - "@size-limit/preset-small-lib": "6.0.4", - "@types/jest": "^24.0.18", - "fs-extra": "^11.1.0", - "jest": "^29.0.0", - "jest-environment-jsdom": "^29.3.1", - "lint-staged": "^9.2.5", - "rimraf": "^3.0.0", - "size-limit": "6.0.4", - "ts-jest": "^29.0.2", - "ts-node": "^8.5.0" - }, - "dependencies": { - "graphql": "^15.5.0" - }, - "size-limit": [ - { - "path": "./dist/index.js", - "limit": "6 KB", - "ignore": [ - "graphql" - ] - } - ] -} diff --git a/packages/amplify-schema-validator/src/__tests__/helpers/readSchema.ts b/packages/amplify-schema-validator/src/__tests__/helpers/readSchema.ts deleted file mode 100644 index 649ed5c759..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/helpers/readSchema.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Basic help to reduce duplication in test files - */ -import fs from 'fs'; -import path from 'path'; - -const schemaDir = path.join(__dirname, '..', 'schemas'); -export const readSchema = (schemaName: string): string => fs.readFileSync(path.join(schemaDir, schemaName)).toString(); diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-auth-must-be-annotated-with-model.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-auth-must-be-annotated-with-model.graphql deleted file mode 100644 index 413980acdb..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-auth-must-be-annotated-with-model.graphql +++ /dev/null @@ -1,7 +0,0 @@ -type Post @auth(rules: [{ allow: groups, groupsField: "groups" }]) { - id: ID! - title: String! - group: String - createdAt: String - updatedAt: String -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-fields-match-related-type-primary-key1.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-fields-match-related-type-primary-key1.graphql deleted file mode 100644 index 4cbfa90f09..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-fields-match-related-type-primary-key1.graphql +++ /dev/null @@ -1,13 +0,0 @@ -type Test @model { - id: ID! - email: String! - testObj: Test1 @belongsTo(fields: ["email"]) -} - -type Test1 @model { - id: ID! - friendID: ID! - name: String! - email: String! - test: Test @hasOne -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-fields-match-related-type-primary-key2.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-fields-match-related-type-primary-key2.graphql deleted file mode 100644 index 98a4cd8455..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-fields-match-related-type-primary-key2.graphql +++ /dev/null @@ -1,13 +0,0 @@ -type Test @model { - id: ID! - email: String! - testObj: Test1 @belongsTo(fields: ["email"]) -} - -type Test1 @model { - id: ID! @primaryKey - friendID: ID! - name: String! - email: String! - test: Test @hasOne -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-fields-match-related-type-primary-key3.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-fields-match-related-type-primary-key3.graphql deleted file mode 100644 index 08b62c178f..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-fields-match-related-type-primary-key3.graphql +++ /dev/null @@ -1,13 +0,0 @@ -type Test @model { - id: ID! - email: String! - testObj: Test1 @belongsTo(fields: ["email"]) -} - -type Test1 @model { - id: ID! @primaryKey(fields: ["email"]) - friendID: ID! - name: String! - email: String! - test: Test @hasOne -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-fields-match-related-type-primary-key4.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-fields-match-related-type-primary-key4.graphql deleted file mode 100644 index e9aa4d8f7b..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-fields-match-related-type-primary-key4.graphql +++ /dev/null @@ -1,14 +0,0 @@ -type Test @model { - id: ID! - email: String! - name: String! - testObj: Test1 @belongsTo(fields: ["email", "name"]) -} - -type Test1 @model { - id: ID! @primaryKey(sortKeyFields: ["friendID"]) - friendID: ID! - name: String! - email: String! - test: Test @hasOne -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-wrong-field.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-wrong-field.graphql deleted file mode 100644 index 62d72cdb17..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to-wrong-field.graphql +++ /dev/null @@ -1,11 +0,0 @@ -type Project @model { - id: ID! - name: String @hasOne - team: Team -} - -type Team @model { - id: ID! - name: String! - project: Project @belongsTo -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to.graphql deleted file mode 100644 index 28227305f8..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-belongs-to.graphql +++ /dev/null @@ -1,11 +0,0 @@ -type Project @model { - id: ID! - name: String - team: Team -} - -type Team @model { - id: ID! - name: String! - project: Project @belongsTo -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-correct-type-in-many-to-many-relation.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-correct-type-in-many-to-many-relation.graphql deleted file mode 100644 index 3a86dc560b..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-correct-type-in-many-to-many-relation.graphql +++ /dev/null @@ -1,13 +0,0 @@ -type AmplifyMoodEntry @model @auth(rules: [{ allow: public }]) { - id: ID! - activities: [AmplifyActivity] @manyToMany(relationName: "AmplifyMoodEntryAmplifyActivity") -} - -type AmplifyActivity @model @auth(rules: [{ allow: public }]) { - id: ID! - name: String! - image: String! - position: Int! - hidden: Boolean! - moodEntries: [AmplifyActivity] @manyToMany(relationName: "AmplifyMoodEntryAmplifyActivity") -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-default-directive1.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-default-directive1.graphql deleted file mode 100644 index ca097d0c06..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-default-directive1.graphql +++ /dev/null @@ -1,4 +0,0 @@ -type Post { - id: ID! - title: Boolean! @default(value: false) -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-default-directive2.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-default-directive2.graphql deleted file mode 100644 index 201675cbc1..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-default-directive2.graphql +++ /dev/null @@ -1,8 +0,0 @@ -type Test @model { - id: ID! - student: Student @default(value: "{'name':'FooBar'}") -} - -type Student { - name: String -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-default-directive3.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-default-directive3.graphql deleted file mode 100644 index 8b513d9ef1..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-default-directive3.graphql +++ /dev/null @@ -1,4 +0,0 @@ -type Post @model { - id: ID! - title: Boolean! @default(value: "false", name: "test") -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-default-directive4.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-default-directive4.graphql deleted file mode 100644 index c863cf514c..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-default-directive4.graphql +++ /dev/null @@ -1,4 +0,0 @@ -type Post @model { - id: ID! - title: Boolean! @default(value: false) -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-empty-schema.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-empty-schema.graphql deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-enum-is-defined-once.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-enum-is-defined-once.graphql deleted file mode 100644 index 78a282d1c2..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-enum-is-defined-once.graphql +++ /dev/null @@ -1,15 +0,0 @@ -enum NotificationType { - LIKE - FOLLOW - POST - COMMENT - LIKE -} - -type Notification @model { - id: ID! - type: NotificationType! - recipient: String! - sender: String! - status: Boolean! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-field-is-not-defined-once.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-field-is-not-defined-once.graphql deleted file mode 100644 index 92e9b1eafa..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-field-is-not-defined-once.graphql +++ /dev/null @@ -1,5 +0,0 @@ -type Test @model { - id: ID! - email: String - email: String -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-field-not-in-parent-model-hasMany.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-field-not-in-parent-model-hasMany.graphql deleted file mode 100644 index 6842c473b5..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-field-not-in-parent-model-hasMany.graphql +++ /dev/null @@ -1,11 +0,0 @@ -type Test @model { - id: ID! - testObj: Test1 @hasMany(fields: ["id", "email"]) -} - -type Test1 @model { - id: ID! @primaryKey(sortKeyFields: ["name"]) - email: String - friendID: ID! - name: String! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-field-not-in-parent-model.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-field-not-in-parent-model.graphql deleted file mode 100644 index 972ee96f2f..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-field-not-in-parent-model.graphql +++ /dev/null @@ -1,11 +0,0 @@ -type Test @model { - id: ID! - testObj: Test1 @belongsTo(fields: ["id", "email"]) -} - -type Test1 @model { - id: ID! @primaryKey(sortKeyFields: ["name"]) - email: String - friendID: ID! - name: String! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-hasMany-must-be-used-with-lists.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-hasMany-must-be-used-with-lists.graphql deleted file mode 100644 index 4f6317cd32..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-hasMany-must-be-used-with-lists.graphql +++ /dev/null @@ -1,9 +0,0 @@ -type Foo @model { - id: ID! - bars: Bar @hasMany -} - -type Bar @model { - id: ID! - bar: String! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-hasOne-cannot-be-used-with-lists.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-hasOne-cannot-be-used-with-lists.graphql deleted file mode 100644 index 29e1eba7c6..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-hasOne-cannot-be-used-with-lists.graphql +++ /dev/null @@ -1,9 +0,0 @@ -type Foo @model { - id: ID! - bars: [Bar] @hasOne -} - -type Bar @model { - id: ID! - bar: String! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-index-directive-schema.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-index-directive-schema.graphql deleted file mode 100644 index 9f625c29b7..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-index-directive-schema.graphql +++ /dev/null @@ -1,24 +0,0 @@ -# This "input" configures a global authorization rule to enable public access to -# all models in this schema. Learn more about authorization rules here: https://docs.amplify.aws/cli/graphql/authorization-rules -input AMPLIFY { - globalAuthRule: AuthRule = { allow: public } -} # FOR TESTING ONLY! -enum ScalarIndexEnum { - SPACESHIP - HOUSE - CAMPSITE - APARTMENT - ROOM -} - -type User @model { - id: ID! - firstName: String! - nonScalarIndex: InvalidNonScalar! @index(name: "byNonScalarIndex", sortKeyFields: ["createdAt"]) - scalarIndexEnum: ScalarIndexEnum! @index(name: "byScalarIndexEnum", sortKeyFields: ["createdAt"]) - createdAt: AWSDateTime! -} - -type InvalidNonScalar @model { - id: ID! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-index-exists-in-related-model.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-index-exists-in-related-model.graphql deleted file mode 100644 index c23123b6f3..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-index-exists-in-related-model.graphql +++ /dev/null @@ -1,11 +0,0 @@ -type Test @model { - id: ID! - email: String - testObj: [Test1] @hasMany(indexName: "byUser") -} - -type Test1 @model { - id: ID! @primaryKey(sortKeyFields: ["name"]) - testID: ID! @index(name: "byUser1") - name: String! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-index-is-defined-once-in-model.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-index-is-defined-once-in-model.graphql deleted file mode 100644 index c1c0685c40..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-index-is-defined-once-in-model.graphql +++ /dev/null @@ -1,5 +0,0 @@ -type Project @model { - id: ID! - name: String @index(name: "byTeam") - team: String @index(name: "byTeam") -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-key-exists-in-related-model.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-key-exists-in-related-model.graphql deleted file mode 100644 index c6884e708b..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-key-exists-in-related-model.graphql +++ /dev/null @@ -1,15 +0,0 @@ -type Blog @model { - id: ID! - name: String! - posts: [Post] @connection(keyName: "byBlog", fields: ["id"]) -} - -type Post @model { - id: ID! - title: [Comment]! @connection(keyName: "byPost") -} - -type Comment @model @key(name: "byPost1") { - id: ID! - title: String! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-many-to-many-count.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-many-to-many-count.graphql deleted file mode 100644 index 2039380150..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-many-to-many-count.graphql +++ /dev/null @@ -1,18 +0,0 @@ -# This "input" configures a global authorization rule to enable public access to -# all models in this schema. Learn more about authorization rules here: https://docs.amplify.aws/cli/graphql/authorization-rules -input AMPLIFY { - globalAuthRule: AuthRule = { allow: public } -} # FOR TESTING ONLY! -type Post @model @auth(rules: [{ allow: public }]) { - id: ID! - title: String! - content: String - tags: [Tag] @manyToMany(relationName: "PostTags") -} - -type Tag @model @auth(rules: [{ allow: public }]) { - id: ID! - label: String! - posts: [Post] - abc: String -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-many-to-many-has-a-relationname-test1.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-many-to-many-has-a-relationname-test1.graphql deleted file mode 100644 index 172a530c45..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-many-to-many-has-a-relationname-test1.graphql +++ /dev/null @@ -1,4 +0,0 @@ -type Foo @model { - id: ID! - bars: [Bar] @manyToMany -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-many-to-many-has-a-relationname-test2.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-many-to-many-has-a-relationname-test2.graphql deleted file mode 100644 index 521f73d36b..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-many-to-many-has-a-relationname-test2.graphql +++ /dev/null @@ -1,4 +0,0 @@ -type Foo @model { - id: ID! - bars: [Bar] @manyToMany(test: "test") -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-object-must-be-annotated-with-model.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-object-must-be-annotated-with-model.graphql deleted file mode 100644 index 72bbf625a5..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-object-must-be-annotated-with-model.graphql +++ /dev/null @@ -1,9 +0,0 @@ -type Foo @model { - id: ID! - bars: [Bar] @hasMany -} - -type Bar { - id: ID! - bar: String! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-owner-field-type-string.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-owner-field-type-string.graphql deleted file mode 100644 index 8e1e081e3f..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-owner-field-type-string.graphql +++ /dev/null @@ -1,7 +0,0 @@ -type Inicio - @model - @auth( - rules: [{ allow: owner, operations: [create, delete, update, read], provider: userPools, ownerField: autores, groups: ["MeuCPD"] }] - ) { - Name: String! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-relationname-doesnot-conflict-with-typename.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-relationname-doesnot-conflict-with-typename.graphql deleted file mode 100644 index 9c84c11284..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-relationname-doesnot-conflict-with-typename.graphql +++ /dev/null @@ -1,13 +0,0 @@ -type Foo @model { - id: ID! - bars: [Bar] @manyToMany(relationName: "foo Bar") -} - -type FooBar { - id: ID! -} - -type Bar @model { - id: ID! - foos: [Foo] @manyToMany(relationName: "foo Bar") -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-relationshipname-not-inverseof-relationname.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-relationshipname-not-inverseof-relationname.graphql deleted file mode 100644 index 4a3f3023cd..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-relationshipname-not-inverseof-relationname.graphql +++ /dev/null @@ -1,9 +0,0 @@ -type Bar @model @auth(rules: [{ allow: public }]) { - id: ID! - foos: [Foo] @manyToMany(relationName: "FooBar") -} - -type Foo @model @auth(rules: [{ allow: public }]) { - id: ID! - BarFoo: [Bar] @manyToMany(relationName: "FooBar") -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-reserved-field-name.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-reserved-field-name.graphql deleted file mode 100644 index c3e9d38281..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-reserved-field-name.graphql +++ /dev/null @@ -1,5 +0,0 @@ -type Test @model { - id: ID! - str: String - _version: String -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-reserved-type-name.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-reserved-type-name.graphql deleted file mode 100644 index b8e2c87a3e..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-reserved-type-name.graphql +++ /dev/null @@ -1,4 +0,0 @@ -type Query @model { - id: ID! - str: String -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-sort-key-field-exists.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-sort-key-field-exists.graphql deleted file mode 100644 index e8d34f9243..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-sort-key-field-exists.graphql +++ /dev/null @@ -1,5 +0,0 @@ -type Test @model { - id: ID! - name: String! @index(name: "byName", sortKeyFields: ["createdAt"]) - email: String -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-type-is-not-defined-once.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-type-is-not-defined-once.graphql deleted file mode 100644 index 8205c4d694..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-type-is-not-defined-once.graphql +++ /dev/null @@ -1,11 +0,0 @@ -type Test @model { - id: ID! - email: String - name: String -} - -type Test @model { - id: ID! - email: String - name: String -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-unique-field-names-with-relation.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-unique-field-names-with-relation.graphql deleted file mode 100644 index c4c4eb6065..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-unique-field-names-with-relation.graphql +++ /dev/null @@ -1,17 +0,0 @@ -type Contact @model @auth(rules: [{ allow: public }]) { - id: ID! - users: [User] @manyToMany(relationName: "UserContact") - Users: User @hasOne -} - -type User @model @auth(rules: [{ allow: public }]) { - id: ID! - name: String - image: String - status: String - email: AWSEmail - sub: String - createdOn: AWSTimestamp - Contacts: [Contact] @manyToMany(relationName: "UserContact") - contactID: ID! @index(name: "byContact") -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-use-belongsto-when-datastore-inuse.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-use-belongsto-when-datastore-inuse.graphql deleted file mode 100644 index f782ced710..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-use-belongsto-when-datastore-inuse.graphql +++ /dev/null @@ -1,9 +0,0 @@ -type Blog @model { - id: ID! - posts: [Post] @hasMany -} - -type Post @model { - id: ID! - blog: Blog @hasOne -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-use-directives-from-newer-transformer-version.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-use-directives-from-newer-transformer-version.graphql deleted file mode 100644 index edf0bd5272..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-use-directives-from-newer-transformer-version.graphql +++ /dev/null @@ -1,5 +0,0 @@ -type Post { - id: ID! @primaryKey - title: String! @index - blog: String! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-use-directives-from-older-transformer-version.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/invalid-use-directives-from-older-transformer-version.graphql deleted file mode 100644 index b81f211a25..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/invalid-use-directives-from-older-transformer-version.graphql +++ /dev/null @@ -1,11 +0,0 @@ -type Post @key { - id: ID! - title: String! - blog: Blog! @connection -} - -type Blog @versioned { - id: ID! - name: String! - posts: [Post]! @connection -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/schema-with-nonnulltype.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/schema-with-nonnulltype.graphql deleted file mode 100644 index 80f46824ab..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/schema-with-nonnulltype.graphql +++ /dev/null @@ -1,135 +0,0 @@ -type AllTypes @model @auth(rules: [{ allow: public }, { allow: private }]) { - id: ID! - name: String - age: Int - height: Float - active: Boolean - createdAt: AWSDate - updatedAtDateTime: AWSDateTime - time: AWSTime - timestamp: AWSTimestamp - json: AWSJSON - email: AWSEmail - url: AWSURL - phone: AWSPhone - ip: AWSIPAddress - test: String -} - -type Contract @model @auth(rules: [{ allow: public }]) { - id: ID! - OrderId: String - status: String - users: [User!] @manyToMany(relationName: "UserContract") - Devices: [Device!] @hasMany(indexName: "byContract", fields: ["id"]) - owners: [String] - viewers: [String] -} - -type Iccid @model @auth(rules: [{ allow: public }]) { - serialNumber: ID! - Status: String - ops: String - Devices: [Device] @manyToMany(relationName: "IccidDevice") - owners: [String] - viewers: [String] -} - -type Relative @model @auth(rules: [{ allow: public }]) { - id: ID! - User: User @hasOne - seniors: [Senior] @manyToMany(relationName: "SeniorRelative") - owners: [String] - viewers: [String] -} - -type Senior @model @auth(rules: [{ allow: public }]) { - id: ID! - User: User @hasOne - Relatives: [Relative] @manyToMany(relationName: "SeniorRelative") - owners: [String] - viewers: [String] -} - -type Device @model @auth(rules: [{ allow: public }]) { - id: ID! - serialNumber: ID! - Senior: Senior @hasOne - DeviceType: String - IsActive: String - PcbID: String - Status: String - contractID: ID @index(name: "byContract") - dashboards: [Dashboard] @manyToMany(relationName: "DashboardDevice") - iccids: [Iccid] @manyToMany(relationName: "IccidDevice") - owners: [String] - viewers: [String] -} - -type Dashboard @model @auth(rules: [{ allow: public }]) { - id: ID! - DashboardName: String! - Devices: [Device] @manyToMany(relationName: "DashboardDevice") - users: [User] @manyToMany(relationName: "UserDashboard") - owners: [String] - viewers: [String] -} - -type User @model @auth(rules: [{ allow: public }]) { - id: ID! - Email: String! - Dashboards: [Dashboard] @manyToMany(relationName: "UserDashboard") - UserContracts: [Contract] @manyToMany(relationName: "UserContract") - """ - UserContracts: [UserContract] @hasMany(indexName: "byUser", fields: ["id"]) - """ - AliasName: String - Birthday: String - City: String - Country: String - Department: String - FirstName: String - Gender: String - IdentityId: String - LastName: String - MobileNumber: String - PassportId: String - PhoneNumber: String - Relationship: String - Role: String - RoomNumber: String - State: String - Street: String - ZipCode: String - dashboardID: String - Community: String - Notes: String - HouseNumber: String - owners: [String] - viewers: [String] -} - -type Foo @model @auth(rules: [{ allow: public }]) { - name: String - Bar: Bar! @hasOne -} - -type Bar @model @auth(rules: [{ allow: public }]) { - name: String - description: String - Foo: Foo @belongsTo -} - -type Project @model @auth(rules: [{ allow: public }]) { - id: ID! - name: String! - team: Team @hasOne - projectID: ID -} - -type Team @model @auth(rules: [{ allow: public }]) { - id: ID! - name: String! - projectID: ID - project: Project! @belongsTo(fields: ["projectID"]) -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-auth-must-be-annotated-with-model.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-auth-must-be-annotated-with-model.graphql deleted file mode 100644 index d43c68e350..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-auth-must-be-annotated-with-model.graphql +++ /dev/null @@ -1,7 +0,0 @@ -type Post @model @auth(rules: [{ allow: groups, groupsField: "groups" }]) { - id: ID! - title: String! - group: String - createdAt: String - updatedAt: String -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-belongs-to-fields-match-related-type-primary-key.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-belongs-to-fields-match-related-type-primary-key.graphql deleted file mode 100644 index 1622a161d5..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-belongs-to-fields-match-related-type-primary-key.graphql +++ /dev/null @@ -1,12 +0,0 @@ -type Test @model { - id: ID! - email: ID! - testObj: Test1 @belongsTo(fields: ["email"]) -} - -type Test1 @model { - id: ID! - friendID: ID! - email: String! - test: Test @hasOne -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-belongs-to-has-many.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-belongs-to-has-many.graphql deleted file mode 100644 index 8e49fcd6c7..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-belongs-to-has-many.graphql +++ /dev/null @@ -1,11 +0,0 @@ -type Project @model { - id: ID! - name: String - team: Team @hasOne -} - -type Team @model { - id: ID! - name: String! - project: Project @belongsTo -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-belongs-to-has-one.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-belongs-to-has-one.graphql deleted file mode 100644 index 0b6671a6d6..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-belongs-to-has-one.graphql +++ /dev/null @@ -1,11 +0,0 @@ -type Project @model { - id: ID! - name: String - team: [Team] @hasMany -} - -type Team @model { - id: ID! - name: String! - project: Project @belongsTo -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-blank-schema.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-blank-schema.graphql deleted file mode 100644 index 1d96b14b66..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-blank-schema.graphql +++ /dev/null @@ -1,5 +0,0 @@ -# This "input" configures a global authorization rule to enable public access to -# all models in this schema. Learn more about authorization rules here: https://docs.amplify.aws/cli/graphql/authorization-rules -input AMPLIFY { - globalAuthRule: AuthRule = { allow: public } -} # FOR TESTING ONLY! diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-blog-schema.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-blog-schema.graphql deleted file mode 100644 index f10efa80c3..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-blog-schema.graphql +++ /dev/null @@ -1,18 +0,0 @@ -# This "input" configures a global authorization rule to enable public access to -# all models in this schema. Learn more about authorization rules here: https://docs.amplify.aws/cli/graphql/authorization-rules -input AMPLIFY { - globalAuthRule: AuthRule = { allow: public } -} # FOR TESTING ONLY! -type Post @model @auth(rules: [{ allow: public }]) { - id: ID! - title: String! - content: String - tags: [Tag] @manyToMany(relationName: "PostTags") -} - -type Tag @model @auth(rules: [{ allow: public }]) { - id: ID! - label: String! - posts: [Post] @manyToMany(relationName: "PostTags") - abc: String -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-correct-type-in-many-to-many-relation.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-correct-type-in-many-to-many-relation.graphql deleted file mode 100644 index 4e9b71362e..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-correct-type-in-many-to-many-relation.graphql +++ /dev/null @@ -1,13 +0,0 @@ -type AmplifyMoodEntry @model @auth(rules: [{ allow: public }]) { - id: ID! - activities: [AmplifyActivity] @manyToMany(relationName: "AmplifyMoodEntryAmplifyActivity") -} - -type AmplifyActivity @model @auth(rules: [{ allow: public }]) { - id: ID! - name: String! - image: String! - position: Int! - hidden: Boolean! - moodEntries: [AmplifyMoodEntry] @manyToMany(relationName: "AmplifyMoodEntryAmplifyActivity") -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-default-directive.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-default-directive.graphql deleted file mode 100644 index d2dc4e80bf..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-default-directive.graphql +++ /dev/null @@ -1,4 +0,0 @@ -type Post @model { - id: ID! - title: Boolean! @default(value: "false") -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-enum-is-defined-once.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-enum-is-defined-once.graphql deleted file mode 100644 index 2ed59efa99..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-enum-is-defined-once.graphql +++ /dev/null @@ -1,14 +0,0 @@ -enum NotificationType { - LIKE - FOLLOW - POST - COMMENT -} - -type Notification @model { - id: ID! - type: NotificationType! - recipient: String! - sender: String! - status: Boolean! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-field-in-parent-model.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-field-in-parent-model.graphql deleted file mode 100644 index abd7aa1b70..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-field-in-parent-model.graphql +++ /dev/null @@ -1,10 +0,0 @@ -type Project @model { - id: ID! - team: [Team] @hasMany -} - -type Team @model { - id: ID! - name: String! - project: Project @belongsTo(fields: ["id", "name"]) -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-field-is-defined-once.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-field-is-defined-once.graphql deleted file mode 100644 index 824aeadaee..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-field-is-defined-once.graphql +++ /dev/null @@ -1,5 +0,0 @@ -type Test @model { - id: ID! - email: String - name: String -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-hasMany-must-be-used-with-lists.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-hasMany-must-be-used-with-lists.graphql deleted file mode 100644 index 132bc343c5..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-hasMany-must-be-used-with-lists.graphql +++ /dev/null @@ -1,9 +0,0 @@ -type Foo @model { - id: ID! - bars: [Bar] @hasMany -} - -type Bar @model { - id: ID! - bar: String! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-hasOne-cannot-be-used-with-lists.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-hasOne-cannot-be-used-with-lists.graphql deleted file mode 100644 index 723e86d771..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-hasOne-cannot-be-used-with-lists.graphql +++ /dev/null @@ -1,9 +0,0 @@ -type Foo @model { - id: ID! - bars: Bar @hasOne -} - -type Bar @model { - id: ID! - bar: String! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-index-directive-schema.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-index-directive-schema.graphql deleted file mode 100644 index 80ba5183af..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-index-directive-schema.graphql +++ /dev/null @@ -1,11 +0,0 @@ -# This "input" configures a global authorization rule to enable public access to -# all models in this schema. Learn more about authorization rules here: https://docs.amplify.aws/cli/graphql/authorization-rules -input AMPLIFY { - globalAuthRule: AuthRule = { allow: public } -} # FOR TESTING ONLY! -type User @model { - id: ID! - firstName: String! - lastName: String! @index(name: "byLastName", sortKeyFields: ["createdAt"]) - createdAt: AWSDateTime! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-index-exists-in-related-model.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-index-exists-in-related-model.graphql deleted file mode 100644 index 4eecdca109..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-index-exists-in-related-model.graphql +++ /dev/null @@ -1,11 +0,0 @@ -type Test @model { - id: ID! - email: String - testObj: [Test1] @hasMany(indexName: "byUser") -} - -type Test1 @model { - id: ID! @primaryKey(sortKeyFields: ["name"]) - testID: ID! @index(name: "byUser") - name: String! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-index-is-defined-once-in-model.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-index-is-defined-once-in-model.graphql deleted file mode 100644 index 12766f95a4..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-index-is-defined-once-in-model.graphql +++ /dev/null @@ -1,5 +0,0 @@ -type Project @model { - id: ID! - name: String @index(name: "byTeam") - team: String -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-key-exists-in-related-model.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-key-exists-in-related-model.graphql deleted file mode 100644 index 25c1af978d..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-key-exists-in-related-model.graphql +++ /dev/null @@ -1,12 +0,0 @@ -type Blog @model { - id: ID! - name: String! - posts: [Post] @connection(keyName: "byBlog", fields: ["id"]) -} - -type Post @model @key(name: "byBlog", fields: ["blogID"]) { - id: ID! - title: String! - blogID: ID! - blog: Blog @connection(fields: ["blogID"]) -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-many-to-many-has-a-relationname.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-many-to-many-has-a-relationname.graphql deleted file mode 100644 index e01a5f9077..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-many-to-many-has-a-relationname.graphql +++ /dev/null @@ -1,9 +0,0 @@ -type Foo @model { - id: ID! - bars: [Bar] @manyToMany(relationName: "fooBar") -} - -type Bar @model { - id: ID! - foos: [Foo] @manyToMany(relationName: "fooBar") -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-object-must-be-annotated-with-model.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-object-must-be-annotated-with-model.graphql deleted file mode 100644 index 723e86d771..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-object-must-be-annotated-with-model.graphql +++ /dev/null @@ -1,9 +0,0 @@ -type Foo @model { - id: ID! - bars: Bar @hasOne -} - -type Bar @model { - id: ID! - bar: String! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-owner-field-type-string.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-owner-field-type-string.graphql deleted file mode 100644 index 451b97f76a..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-owner-field-type-string.graphql +++ /dev/null @@ -1,7 +0,0 @@ -type Inicio - @model - @auth( - rules: [{ allow: owner, operations: [create, delete, update, read], provider: userPools, ownerField: "autores", groups: ["MeuCPD"] }] - ) { - Name: String! -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-relationshipname-not-inverseof-relationname.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-relationshipname-not-inverseof-relationname.graphql deleted file mode 100644 index 76012794ce..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-relationshipname-not-inverseof-relationname.graphql +++ /dev/null @@ -1,9 +0,0 @@ -type Bar @model @auth(rules: [{ allow: public }]) { - id: ID! - foos: [Foo] @manyToMany(relationName: "FooBar") -} - -type Foo @model @auth(rules: [{ allow: public }]) { - id: ID! - Bars: [Bar] @manyToMany(relationName: "FooBar") -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-reserved-type-name.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-reserved-type-name.graphql deleted file mode 100644 index cde8071d0f..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-reserved-type-name.graphql +++ /dev/null @@ -1,4 +0,0 @@ -type Query { - id: ID! - str: String -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-sort-key-field-exists.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-sort-key-field-exists.graphql deleted file mode 100644 index a625355265..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-sort-key-field-exists.graphql +++ /dev/null @@ -1,6 +0,0 @@ -type Test @model { - id: ID! - name: String! @index(name: "byName", sortKeyFields: ["createdAt"]) - email: String - createdAt: String -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-todo-schema.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-todo-schema.graphql deleted file mode 100644 index f10efa80c3..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-todo-schema.graphql +++ /dev/null @@ -1,18 +0,0 @@ -# This "input" configures a global authorization rule to enable public access to -# all models in this schema. Learn more about authorization rules here: https://docs.amplify.aws/cli/graphql/authorization-rules -input AMPLIFY { - globalAuthRule: AuthRule = { allow: public } -} # FOR TESTING ONLY! -type Post @model @auth(rules: [{ allow: public }]) { - id: ID! - title: String! - content: String - tags: [Tag] @manyToMany(relationName: "PostTags") -} - -type Tag @model @auth(rules: [{ allow: public }]) { - id: ID! - label: String! - posts: [Post] @manyToMany(relationName: "PostTags") - abc: String -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-type-is-defined-once.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-type-is-defined-once.graphql deleted file mode 100644 index 824aeadaee..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-type-is-defined-once.graphql +++ /dev/null @@ -1,5 +0,0 @@ -type Test @model { - id: ID! - email: String - name: String -} diff --git a/packages/amplify-schema-validator/src/__tests__/schemas/valid-unique-field-names-with-relation.graphql b/packages/amplify-schema-validator/src/__tests__/schemas/valid-unique-field-names-with-relation.graphql deleted file mode 100644 index 48a11fd1d2..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/schemas/valid-unique-field-names-with-relation.graphql +++ /dev/null @@ -1,17 +0,0 @@ -type Contact @model @auth(rules: [{ allow: public }]) { - id: ID! - users: [User] @manyToMany(relationName: "UserContact") - Users: String -} - -type User @model @auth(rules: [{ allow: public }]) { - id: ID! - name: String - image: String - status: String - email: AWSEmail - sub: String - createdOn: AWSTimestamp - Contacts: [Contact] @manyToMany(relationName: "UserContact") - contactID: ID! @index(name: "byContact") -} diff --git a/packages/amplify-schema-validator/src/__tests__/utils/resolve-field-type-name.test.ts b/packages/amplify-schema-validator/src/__tests__/utils/resolve-field-type-name.test.ts deleted file mode 100644 index 7af0c00aac..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/utils/resolve-field-type-name.test.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { TypeNode } from 'graphql'; -import { resolveFieldTypeName } from '../../helpers/resolve-field-type-name'; - -describe('resolve field type name', () => { - it('resolves field type for NamedType case', () => { - const example = { - kind: 'NamedType', - name: { - value: 'hello world', - }, - }; - const value = resolveFieldTypeName(example as TypeNode); - expect(value).toBe('hello world'); - }); - - it('resolves field type for NonNullType / NamedType case', () => { - const example = { - kind: 'NonNullType', - type: { - kind: 'NamedType', - name: { - value: 'hello world', - }, - }, - }; - const value = resolveFieldTypeName(example as TypeNode); - expect(value).toBe('hello world'); - }); - - it('resolves field type for NonNullType / other case', () => { - const example = { - kind: 'NonNullType', - type: { - kind: 'other', - name: { - value: 'hello world', - }, - }, - }; - expect(() => resolveFieldTypeName(example as TypeNode)).toThrow(`Unknown type ${example}`); - }); - - it('resolves field type for NonNullType / ListType case', () => { - const example = { - kind: 'NonNullType', - type: { - kind: 'ListType', - type: { - kind: 'NamedType', - name: { - value: 'hello world', - }, - }, - }, - }; - const value = resolveFieldTypeName(example as TypeNode); - expect(value).toBe('hello world'); - }); - - it('resolves field type for NonNullType / ListType / NonNullType case', () => { - const example = { - kind: 'NonNullType', - type: { - kind: 'ListType', - type: { - kind: 'NonNullType', - type: { - kind: 'NamedType', - name: { - value: 'hello world', - }, - }, - }, - }, - }; - const value = resolveFieldTypeName(example as TypeNode); - expect(value).toBe('hello world'); - }); - - it('resolves field type for NonNullType / ListType / other case', () => { - const example = { - kind: 'NonNullType', - type: { - kind: 'ListType', - type: { - kind: 'other', - type: { - kind: 'NamedType', - name: { - value: 'hello world', - }, - }, - }, - }, - }; - expect(() => resolveFieldTypeName(example as TypeNode)).toThrow(`Unknown type ${example}`); - }); - - it('resolves field type for other case', () => { - const example = { - kind: 'other', - name: { - value: '', - }, - }; - expect(() => resolveFieldTypeName(example as TypeNode)).toThrow(`Unknown type ${example}`); - }); - - it('resolves field type for ListType / NamedType case', () => { - const example = { - kind: 'ListType', - type: { - kind: 'NamedType', - name: { - value: 'hello world', - }, - }, - }; - const value = resolveFieldTypeName(example as TypeNode); - expect(value).toBe('hello world'); - }); - - it('resolves field type for ListType / NonNullType case', () => { - const example = { - kind: 'ListType', - type: { - kind: 'NonNullType', - type: { - kind: 'NamedType', - name: { - value: 'hello world', - }, - }, - }, - }; - const value = resolveFieldTypeName(example as TypeNode); - expect(value).toBe('hello world'); - }); - - it('resolves field type for ListType / other case', () => { - const example = { - kind: 'ListType', - type: { - kind: 'other', - type: { - kind: 'NamedType', - name: { - value: 'hello world', - }, - }, - }, - }; - expect(() => resolveFieldTypeName(example as TypeNode)).toThrow(`Unknown type ${example}`); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-auth-must-be-annotated-with-model.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-auth-must-be-annotated-with-model.test.ts deleted file mode 100644 index 5d00bbe56a..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-auth-must-be-annotated-with-model.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when type annotated with @auth is not annotated with @model', () => { - const schema = readSchema('invalid-auth-must-be-annotated-with-model.graphql'); - const errorRegex = 'Types annotated with @auth must also be annotated with @model.'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation when type annotated with @auth is annotated with @model', () => { - const schema = readSchema('valid-auth-must-be-annotated-with-model.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-belongs-to-fields-match-related-type-primary-key.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-belongs-to-fields-match-related-type-primary-key.test.ts deleted file mode 100644 index 468240b82f..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-belongs-to-fields-match-related-type-primary-key.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when schema has belongs to fields which does not match related type primary key1', () => { - const schema = readSchema('invalid-belongs-to-fields-match-related-type-primary-key1.graphql'); - const errorRegex = 'email field is not of type ID'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('fails validation when schema has belongs to fields which does not match related type primary key2', () => { - const schema = readSchema('invalid-belongs-to-fields-match-related-type-primary-key2.graphql'); - const errorRegex = 'email field is not of type ID'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('fails validation when schema has belongs to fields which does not match related type primary key3', () => { - const schema = readSchema('invalid-belongs-to-fields-match-related-type-primary-key3.graphql'); - const errorRegex = 'email field is not of type ID'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('fails validation when schema has belongs to fields which does not match related type primary key4', () => { - const schema = readSchema('invalid-belongs-to-fields-match-related-type-primary-key4.graphql'); - const errorRegex = 'name field is not of type ID'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation when schema has belongs to fields which match related type primary key', () => { - const schema = readSchema('valid-belongs-to-fields-match-related-type-primary-key.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-belongs-to-relation-exists.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-belongs-to-relation-exists.test.ts deleted file mode 100644 index bc2a9ab6e0..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-belongs-to-relation-exists.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when schema has unmatched @belongsTo', () => { - const schema = readSchema('invalid-belongs-to.graphql'); - const errorRegex = - 'Invalid @belongs directive in schema: @belongsTo directive requires that a @hasOne or @hasMany relationship already exists from parent to the related model.'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation when schema has @belongsTo matched with @hasOne', () => { - const schema = readSchema('valid-belongs-to-has-one.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); - - it('passes validation when schema has @belongsTo matched with @hasMany', () => { - const schema = readSchema('valid-belongs-to-has-many.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-cli-generated-schemas.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-cli-generated-schemas.test.ts deleted file mode 100644 index 88bc25134f..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-cli-generated-schemas.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('successfully validates CLI-generated todo schema', () => { - const schema = readSchema('valid-todo-schema.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); - - it('successfully validates CLI-generated blog schema', () => { - const schema = readSchema('valid-blog-schema.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); - - it('successfully validates CLI-generated blank schema', () => { - const schema = readSchema('valid-blank-schema.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-correct-type-in-many-to-many-relation.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-correct-type-in-many-to-many-relation.test.ts deleted file mode 100644 index a91f6a5077..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-correct-type-in-many-to-many-relation.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when schema has incorrect type in many to many relation', () => { - const schema = readSchema('invalid-correct-type-in-many-to-many-relation.graphql'); - const errorRegex = '@manyToMany relation AmplifyMoodEntryAmplifyActivity expects AmplifyMoodEntry but got AmplifyActivity'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation when schema has correct type in many to many relation', () => { - const schema = readSchema('valid-correct-type-in-many-to-many-relation.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-default-directive.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-default-directive.test.ts deleted file mode 100644 index a524fe816c..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-default-directive.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when @default directive is not added to object definitions annotated with @model', () => { - const schema = readSchema('invalid-default-directive1.graphql'); - const errorRegex = 'InvalidDirectiveError - The @default directive may only be added to object definitions annotated with @model.'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('fails validation when @default directive is not added to scalar or enum field types', () => { - const schema = readSchema('invalid-default-directive2.graphql'); - const errorRegex = 'InvalidDirectiveError - The @default directive may only be added to scalar or enum field types.'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('fails validation when @default directive has more than a value property', () => { - const schema = readSchema('invalid-default-directive3.graphql'); - const errorRegex = 'InvalidDirectiveError - The @default directive only takes a value property'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('fails validation when @default directives value property does not have a string value', () => { - const schema = readSchema('invalid-default-directive4.graphql'); - const errorRegex = 'InvalidDirectiveError - String cannot represent a non string value: the @default directive has a non String value'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes @default directive validations', () => { - const schema = readSchema('valid-default-directive.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-enum-is-defined-once.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-enum-is-defined-once.test.ts deleted file mode 100644 index ada072f48e..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-enum-is-defined-once.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when schema has a field defined more than once', () => { - const schema = readSchema('invalid-enum-is-defined-once.graphql'); - const errorRegex = 'Schema validation failed. Enum value NotificationType.LIKE can only be defined once'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation when schema has a field defined once', () => { - const schema = readSchema('valid-enum-is-defined-once.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-field-is-defined-once.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-field-is-defined-once.test.ts deleted file mode 100644 index 78ef7c494d..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-field-is-defined-once.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when schema has a field defined more than once', () => { - const schema = readSchema('invalid-field-is-not-defined-once.graphql'); - const errorRegex = 'Schema validation failed. Field Test.email can only be defined once.'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation when schema has a field defined once', () => { - const schema = readSchema('valid-field-is-defined-once.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-fields-match-in-parent-model.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-fields-match-in-parent-model.test.ts deleted file mode 100644 index 29a5202abf..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-fields-match-in-parent-model.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when field is not in the parent model', () => { - const schema = readSchema('invalid-field-not-in-parent-model.graphql'); - const errorRegex = 'email is not a field in Test'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('fails validation when hasMany field is not in the parent model', () => { - const schema = readSchema('invalid-field-not-in-parent-model-hasMany.graphql'); - const errorRegex = 'email is not a field in Test'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation when field is in the parent model', () => { - const schema = readSchema('valid-field-in-parent-model.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-graphql-syntax.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-graphql-syntax.test.ts deleted file mode 100644 index e36a57c299..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-graphql-syntax.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when schema is not valid graphql', () => { - const schema = 'asf'; - const errorRegex = 'Syntax Error'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('fails validation when schema is empty', () => { - const schema = readSchema('invalid-empty-schema.graphql'); - const errorRegex = 'Syntax Error'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-hasMany-is-used-with-lists.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-hasMany-is-used-with-lists.test.ts deleted file mode 100644 index 154a757d5e..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-hasMany-is-used-with-lists.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when schema has a hasMany directive not used with lists', () => { - const schema = readSchema('invalid-hasMany-must-be-used-with-lists.graphql'); - const errorRegex = 'bars field in Foo object has a @hasMany directive which must be used with a list. Use @hasOne for non-list types.'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation when schema has a hasMany directive used with lists', () => { - const schema = readSchema('valid-hasMany-must-be-used-with-lists.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-hasOne-is-not-used-with-lists.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-hasOne-is-not-used-with-lists.test.ts deleted file mode 100644 index 35bc491071..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-hasOne-is-not-used-with-lists.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when schema has a hasOne directive used with lists', () => { - const schema = readSchema('invalid-hasOne-cannot-be-used-with-lists.graphql'); - const errorRegex = '@hasOne cannot be used with lists in bars field in Foo object. Use @hasMany instead'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation when schema has a hasOne directive not used with lists', () => { - const schema = readSchema('valid-hasOne-cannot-be-used-with-lists.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-index-exists-in-related-model.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-index-exists-in-related-model.test.ts deleted file mode 100644 index 8ea5ba6938..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-index-exists-in-related-model.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when schema has an index with the same name more than once', () => { - const schema = readSchema('invalid-index-exists-in-related-model.graphql'); - const errorRegex = 'Index byUser does not exist for model Test1'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation when schema has an index with same name defined once', () => { - const schema = readSchema('valid-index-exists-in-related-model.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-index-is-defined-once-in-model.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-index-is-defined-once-in-model.test.ts deleted file mode 100644 index a8e885b6f8..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-index-is-defined-once-in-model.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when schema has an index with the same name more than once', () => { - const schema = readSchema('invalid-index-is-defined-once-in-model.graphql'); - const errorRegex = 'You may only supply one @index with the name byTeam on type Project'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation when schema has an index with same name defined once', () => { - const schema = readSchema('valid-index-is-defined-once-in-model.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-key-exists-in-related-model.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-key-exists-in-related-model.test.ts deleted file mode 100644 index bd5d989434..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-key-exists-in-related-model.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when schema has an index with the same name more than once', () => { - const schema = readSchema('invalid-key-exists-in-related-model.graphql'); - const errorRegex = 'Key byBlog does not exist for model Post'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation when schema has an index with same name defined once', () => { - const schema = readSchema('valid-key-exists-in-related-model.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-many-to-many-has-a-relationname.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-many-to-many-has-a-relationname.test.ts deleted file mode 100644 index 44dd2d98bd..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-many-to-many-has-a-relationname.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when schema has a manyToMany directive without a relationName', () => { - const schema = readSchema('invalid-many-to-many-has-a-relationname-test1.graphql'); - const errorRegex = '@manyToMany relation does not have a relationName'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('fails validation when schema has a manyToMany directive without a relationName', () => { - const schema = readSchema('invalid-many-to-many-has-a-relationname-test2.graphql'); - const errorRegex = '@manyToMany relation does not have a relationName'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation when schema has a manyToMany directive with a relationName', () => { - const schema = readSchema('valid-many-to-many-has-a-relationname.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-many-to-many-relations-match.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-many-to-many-relations-match.test.ts deleted file mode 100644 index 15ea59f358..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-many-to-many-relations-match.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when schema has only one @manyToMany directive', () => { - const schema = readSchema('invalid-many-to-many-count.graphql'); - const errorRegex = "Invalid @manyToMany directive in schema: relation names 'PostTags' must be used in exactly two locations."; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-object-must-be-annotated-with-model.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-object-must-be-annotated-with-model.test.ts deleted file mode 100644 index e275265b2f..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-object-must-be-annotated-with-model.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when @belongsTo/@hasOne/@hasMany/@connection was used with a related type that is not a model', () => { - const schema = readSchema('invalid-object-must-be-annotated-with-model.graphql'); - const errorRegex = 'Object type Bar must be annotated with @model'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation when @belongsTo/@hasOne/@hasMany/@connection was used with a related type that is a model', () => { - const schema = readSchema('valid-object-must-be-annotated-with-model.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-owner-field-type-string.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-owner-field-type-string.test.ts deleted file mode 100644 index 0476f78bc6..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-owner-field-type-string.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when ownerfield does not have a string value', () => { - const schema = readSchema('invalid-owner-field-type-string.graphql'); - const errorRegex = 'String cannot represent a non string value'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation when ownerfield has a string value', () => { - const schema = readSchema('valid-owner-field-type-string.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-relationname-doesnot-conflict-with-typename.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-relationname-doesnot-conflict-with-typename.test.ts deleted file mode 100644 index 758caa418a..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-relationname-doesnot-conflict-with-typename.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when relation name conflicts with type name', () => { - const schema = readSchema('invalid-relationname-doesnot-conflict-with-typename.graphql'); - const errorRegex = '@manyToMany relation name FooBar (derived from foo Bar) already exists as a type in the schema.'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-relationshipname-not-inverseof-relationname.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-relationshipname-not-inverseof-relationname.test.ts deleted file mode 100644 index accb0a0a60..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-relationshipname-not-inverseof-relationname.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when relationshipname is inverse of relation name', () => { - const schema = readSchema('invalid-relationshipname-not-inverseof-relationname.graphql'); - const errorRegex = 'Relationship name BarFoo conflicts with relationName FooBar. Please change your relationship name'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation relationshipname is not inverse of relation name', () => { - const schema = readSchema('valid-relationshipname-not-inverseof-relationname.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-reserved-field-name.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-reserved-field-name.test.ts deleted file mode 100644 index 5cfa70fe2a..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-reserved-field-name.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when reserved words are used in field names', () => { - const schema = readSchema('invalid-reserved-field-name.graphql'); - const errorRegex = '_version is a reserved word and cannnot be used as a field name.'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-reserved-type-name.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-reserved-type-name.test.ts deleted file mode 100644 index 5aada0dc24..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-reserved-type-name.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when reserved words are used in model names', () => { - const schema = readSchema('invalid-reserved-type-name.graphql'); - const errorRegex = 'Query is a reserved type name and currently in use within the default schema element.'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passed validation when reserved words are not used in model names', () => { - const schema = readSchema('valid-reserved-type-name.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-scalar-index.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-scalar-index.test.ts deleted file mode 100644 index 472dc2b766..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-scalar-index.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('is valid when @index directive is a scalar', () => { - const schema = readSchema('valid-index-directive-schema.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); - - it('is invalid when @index directive is a non-scalar', () => { - const schema = readSchema('invalid-index-directive-schema.graphql'); - const errorRegex = "@index directive on 'nonScalarIndex' cannot be a non-scalar"; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-schemas-with-nonnulltype.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-schemas-with-nonnulltype.test.ts deleted file mode 100644 index 44e9e8f4ca..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-schemas-with-nonnulltype.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('is valid when schema includes nonnulltype', () => { - const schema = readSchema('schema-with-nonnulltype.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-sort-key-field-exists.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-sort-key-field-exists.test.ts deleted file mode 100644 index 1d091658ff..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-sort-key-field-exists.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when sort key field does not exist in model', () => { - const schema = readSchema('invalid-sort-key-field-exists.graphql'); - const errorRegex = "Can't find field 'createdAt' in Test, but it was specified in index 'byName'"; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation when sort key field exists in model', () => { - const schema = readSchema('valid-sort-key-field-exists.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-type-is-defined-once.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-type-is-defined-once.test.ts deleted file mode 100644 index 9531cd7766..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-type-is-defined-once.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when schema has a type defined more than once', () => { - const schema = readSchema('invalid-type-is-not-defined-once.graphql'); - const errorRegex = 'Schema validation failed. There can be only one type named Test.'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation when schema has a type defined once', () => { - const schema = readSchema('valid-type-is-defined-once.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-unique-field-names-with-relation.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-unique-field-names-with-relation.test.ts deleted file mode 100644 index e3f420afc8..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-unique-field-names-with-relation.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { validateSchema } from '..'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation if relationship fields are not unique', () => { - const schema = readSchema('invalid-unique-field-names-with-relation.graphql'); - const errorRegex = 'There are two or more relationship fields with the same name'; - expect(() => validateSchema(schema)).toThrow(errorRegex); - }); - - it('passes validation if relationship names are unique', () => { - const schema = readSchema('valid-unique-field-names-with-relation.graphql'); - expect(() => validateSchema(schema)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-use-belongsto-when-datastore-inuse.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-use-belongsto-when-datastore-inuse.test.ts deleted file mode 100644 index 3267221d85..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-use-belongsto-when-datastore-inuse.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { validateSchemaWithContext } from '..'; -import { ValidateSchemaProps } from '../helpers/schema-validator-props'; -import { readSchema } from './helpers/readSchema'; - -describe('Validate Schema', () => { - it('fails validation when hasOne and hasMany relation is used when datastore is enabled', () => { - const schemaProps: ValidateSchemaProps = { - graphqlTransformerVersion: 2, - isDataStoreEnabled: true, - }; - const schema = readSchema('invalid-use-belongsto-when-datastore-inuse.graphql'); - const errorRegex = - 'InvalidDirectiveError - Post and Blog cannot refer to each other via @hasOne or @hasMany when DataStore is in use. Use @belongsTo instead. See https://docs.amplify.aws/cli/graphql/data-modeling/#belongs-to-relationship'; - expect(() => validateSchemaWithContext(schema, schemaProps)).toThrow(errorRegex); - }); - - it('passes validation when hasOne and hasMany relation is used when datastore is disabled', () => { - const schemaProps: ValidateSchemaProps = { - graphqlTransformerVersion: 2, - isDataStoreEnabled: false, - }; - const schema = readSchema('invalid-use-belongsto-when-datastore-inuse.graphql'); - expect(() => validateSchemaWithContext(schema, schemaProps)).not.toThrow(); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-use-directives-from-newer-transformer-version.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-use-directives-from-newer-transformer-version.test.ts deleted file mode 100644 index 6fcdcb7d5a..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-use-directives-from-newer-transformer-version.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { validateSchemaWithContext } from '..'; -import { ValidateSchemaProps } from '../helpers/schema-validator-props'; -import { readSchema } from './helpers/readSchema'; - -const schemaProps: ValidateSchemaProps = { - graphqlTransformerVersion: 1, - isDataStoreEnabled: true, -}; - -describe('Validate Schema', () => { - it('fails validation when schema uses new directives in old transformer version', () => { - const schema = readSchema('invalid-use-directives-from-newer-transformer-version.graphql'); - const errorRegex = - 'InvalidDirectiveError - Your GraphQL Schema is using @primaryKey, @index directives from a newer version of the GraphQL Transformer. Visit https://docs.amplify.aws/cli/migration/transformer-migration/ to learn how to migrate your GraphQL schema.'; - expect(() => validateSchemaWithContext(schema, schemaProps)).toThrow(errorRegex); - }); -}); diff --git a/packages/amplify-schema-validator/src/__tests__/validates-use-directives-from-older-transformer-version.test.ts b/packages/amplify-schema-validator/src/__tests__/validates-use-directives-from-older-transformer-version.test.ts deleted file mode 100644 index f9592ae917..0000000000 --- a/packages/amplify-schema-validator/src/__tests__/validates-use-directives-from-older-transformer-version.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { validateSchemaWithContext } from '..'; -import { ValidateSchemaProps } from '../helpers/schema-validator-props'; -import { readSchema } from './helpers/readSchema'; - -const schemaProps: ValidateSchemaProps = { - graphqlTransformerVersion: 2, - isDataStoreEnabled: true, -}; - -describe('Validate Schema', () => { - it('fails validation when schema uses old directives in new transformer version', () => { - const schema = readSchema('invalid-use-directives-from-older-transformer-version.graphql'); - const errorRegex = - 'InvalidDirectiveError - Your GraphQL Schema is using @key, @connection, @versioned directives from an older version of the GraphQL Transformer. Visit https://docs.amplify.aws/cli/migration/transformer-migration/ to learn how to migrate your GraphQL schema.'; - expect(() => validateSchemaWithContext(schema, schemaProps)).toThrow(errorRegex); - }); -}); diff --git a/packages/amplify-schema-validator/src/exceptions/invalid-directive-error.ts b/packages/amplify-schema-validator/src/exceptions/invalid-directive-error.ts deleted file mode 100644 index 01dc41abdb..0000000000 --- a/packages/amplify-schema-validator/src/exceptions/invalid-directive-error.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Exception class for Invalid Directive errors - */ -export class InvalidDirectiveError extends Error { - constructor(message: string) { - super(message); - Object.setPrototypeOf(this, InvalidDirectiveError.prototype); - this.name = 'InvalidDirectiveError'; - } -} diff --git a/packages/amplify-schema-validator/src/exceptions/validation-error.ts b/packages/amplify-schema-validator/src/exceptions/validation-error.ts deleted file mode 100644 index f41d5bbc80..0000000000 --- a/packages/amplify-schema-validator/src/exceptions/validation-error.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Exception class for general Validation Errors - */ -export class ValidationError extends Error { - constructor(message: string) { - super(message); - Object.setPrototypeOf(this, ValidationError.prototype); - this.name = 'ValidationError'; - } -} diff --git a/packages/amplify-schema-validator/src/helpers/get-object-with-name.ts b/packages/amplify-schema-validator/src/helpers/get-object-with-name.ts deleted file mode 100644 index 1869f83f0d..0000000000 --- a/packages/amplify-schema-validator/src/helpers/get-object-with-name.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode } from 'graphql'; - -/** - * Finds a graphql object definition by name - * - * @param schema graphql schema - * @param name name of object being searched for - * @returns ObjectTypeDefinitionNode - */ -export const getObjectWithName = (schema: DocumentNode, name: string): ObjectTypeDefinitionNode | undefined => { - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - return objectTypeDefinitions.find((objectTypeDefinition) => objectTypeDefinition.name.value === name); -}; diff --git a/packages/amplify-schema-validator/src/helpers/get-type-definitions-of-kind.ts b/packages/amplify-schema-validator/src/helpers/get-type-definitions-of-kind.ts deleted file mode 100644 index b615688707..0000000000 --- a/packages/amplify-schema-validator/src/helpers/get-type-definitions-of-kind.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { DocumentNode, TypeDefinitionNode } from 'graphql'; - -/** - * Fetches all type definitions by kind - * - * @param schema graphql schema - * @param kind graphql type defition kind - * @returns TypeDefinitionNode[] - */ -export const getTypeDefinitionsOfKind = (schema: DocumentNode, kind: string): TypeDefinitionNode[] => { - const typeDefs = schema.definitions.filter((definition) => definition.kind === kind) as TypeDefinitionNode[]; - return typeDefs; -}; diff --git a/packages/amplify-schema-validator/src/helpers/is-scalar-or-enum.ts b/packages/amplify-schema-validator/src/helpers/is-scalar-or-enum.ts deleted file mode 100644 index 8432633375..0000000000 --- a/packages/amplify-schema-validator/src/helpers/is-scalar-or-enum.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { EnumTypeDefinitionNode, Kind, TypeNode } from 'graphql'; - -type ScalarMap = { - [k: string]: 'String' | 'Int' | 'Float' | 'Boolean' | 'ID'; -}; -export const STANDARD_SCALARS: ScalarMap = { - String: 'String', - Int: 'Int', - Float: 'Float', - Boolean: 'Boolean', - ID: 'ID', -}; - -const OTHER_SCALARS: ScalarMap = { - BigInt: 'Int', - Double: 'Float', -}; - -export const APPSYNC_DEFINED_SCALARS: ScalarMap = { - AWSDate: 'String', - AWSTime: 'String', - AWSDateTime: 'String', - AWSTimestamp: 'Int', - AWSEmail: 'String', - AWSJSON: 'String', - AWSURL: 'String', - AWSPhone: 'String', - AWSIPAddress: 'String', -}; - -export const DEFAULT_SCALARS: ScalarMap = { - ...STANDARD_SCALARS, - ...OTHER_SCALARS, - ...APPSYNC_DEFINED_SCALARS, -}; - -/** - * Returns whether a given type is a scalar or enum - * - * @param type the type to check whether it's a scalar - * @param enums enums to consider as scalars - * @returns boolean - */ -export const isScalarOrEnum = (type: TypeNode, enums: EnumTypeDefinitionNode[]): boolean => { - if (type.kind === Kind.NON_NULL_TYPE) { - return isScalarOrEnum(type.type, enums); - } - if (type.kind === Kind.LIST_TYPE) { - /* istanbul ignore next */ - return false; - } - for (const e of enums) { - if (e.name.value === type.name.value) { - return true; - } - } - return Boolean(DEFAULT_SCALARS[type.name.value]); -}; diff --git a/packages/amplify-schema-validator/src/helpers/resolve-field-type-name.ts b/packages/amplify-schema-validator/src/helpers/resolve-field-type-name.ts deleted file mode 100644 index 9e50bc651d..0000000000 --- a/packages/amplify-schema-validator/src/helpers/resolve-field-type-name.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { NamedTypeNode, TypeNode } from 'graphql'; - -/** - * Gets the name of of a graphql TypeNode - * - * @param type graphql TypeNode - * @returns string|undefined - */ -export const resolveFieldTypeName = (type: TypeNode): string => { - switch (type?.kind) { - case 'NamedType': { - return type.name.value; - } - case 'NonNullType': { - if (type.type.kind === 'NamedType') { - return type.type.name.value; - } else if (type.type.kind === 'ListType') { - if (type.type.type.kind === 'NamedType') { - return type.type.type.name.value; - } - if (type.type.type.kind === 'NonNullType') { - return (type.type.type.type as NamedTypeNode).name.value; - } - throw new Error(`Unknown type ${type}`); - } - throw new Error(`Unknown type ${type}`); - } - case 'ListType': { - if (type.type.kind === 'NamedType') { - return type.type.name.value; - } else if (type.type.kind === 'NonNullType') { - return (type.type.type as NamedTypeNode).name.value; - } - throw new Error(`Unknown type ${type}`); - } - default: { - throw new Error(`Unknown type ${type}`); - } - } -}; diff --git a/packages/amplify-schema-validator/src/helpers/resolve-field-type.ts b/packages/amplify-schema-validator/src/helpers/resolve-field-type.ts deleted file mode 100644 index 34fc0bd5aa..0000000000 --- a/packages/amplify-schema-validator/src/helpers/resolve-field-type.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { TypeNode } from 'graphql'; - -/** - * Gets the type of a field - * - * @param type graphql TypeNode - * @returns true|false - */ -export const isListType = (type: TypeNode): boolean => { - if (type.kind === 'NonNullType') { - return isListType(type.type); - } else if (type.kind === 'ListType') { - return true; - } else { - return false; - } -}; diff --git a/packages/amplify-schema-validator/src/helpers/schema-validator-props.ts b/packages/amplify-schema-validator/src/helpers/schema-validator-props.ts deleted file mode 100644 index f3d881d7f8..0000000000 --- a/packages/amplify-schema-validator/src/helpers/schema-validator-props.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type ValidateSchemaProps = { - graphqlTransformerVersion: number; - isDataStoreEnabled: boolean; -}; diff --git a/packages/amplify-schema-validator/src/helpers/transformer-validation.ts b/packages/amplify-schema-validator/src/helpers/transformer-validation.ts deleted file mode 100644 index 6751cadb67..0000000000 --- a/packages/amplify-schema-validator/src/helpers/transformer-validation.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; - -export const transformerValidationErrors = (directivesInUse: Set, graphqlTransformerVersion: number): Error[] => { - const errors: Error[] = []; - if (directivesInUse.size > 0) { - const errorMessage = `Your GraphQL Schema is using ${Array.from(directivesInUse.values()) - .map((directive) => `${directive}`) - .join(', ')} ${directivesInUse.size > 1 ? 'directives' : 'directive'} from ${ - graphqlTransformerVersion === 1 ? 'a newer' : 'an older' - } version of the GraphQL Transformer. Visit https://docs.amplify.aws/cli/migration/transformer-migration/ to learn how to migrate your GraphQL schema.`; - errors.push(new InvalidDirectiveError(errorMessage)); - } - - return errors; -}; diff --git a/packages/amplify-schema-validator/src/helpers/util.ts b/packages/amplify-schema-validator/src/helpers/util.ts deleted file mode 100644 index 1180ae7ba2..0000000000 --- a/packages/amplify-schema-validator/src/helpers/util.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Gets the graphql name from a string by removing any special characters and spaces - * - * @param val string - * @returns string - */ -export const getGraphqlName = (val: string): string => { - if (!val.trim()) { - /* istanbul ignore next */ - return ''; - } - const cleaned = val.replace(/^[^_A-Za-z]+|[^_0-9A-Za-z]/g, ''); - return cleaned; -}; - -export const toUpper = (word: string): string => word.charAt(0).toUpperCase() + word.slice(1); diff --git a/packages/amplify-schema-validator/src/index.ts b/packages/amplify-schema-validator/src/index.ts deleted file mode 100644 index 80aeededc4..0000000000 --- a/packages/amplify-schema-validator/src/index.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ -/* eslint-disable global-require */ - -import { parse } from 'graphql'; -import { validateIndexScalarTypes } from './validators/index-scalar-types'; -import { validateRequireBelongsToRelation } from './validators/relation-required-with-belongs-to'; -import { validateManyToManyTwoLocations } from './validators/two-many-to-many-locations'; -import { validateFieldsMatchInParentModel } from './validators/fields-match-in-parent-model'; -import { ValidationError } from './exceptions/validation-error'; -import { validateFieldIsDefinedOnce } from './validators/field-is-defined-once'; -import { validateAuthIsAnnotatedWithModel } from './validators/auth-must-be-annotated-with-model'; -import { verifyIndexSortKeyFieldsExistInModel } from './validators/sort-key-field-exists'; -import { validateReservedTypeNames } from './validators/reserved-type-name'; -import { validateCorrectTypeInManyToManyRelation } from './validators/correct-type-in-many-to-many-relation'; -import { validateReservedFieldNames } from './validators/reserved-field-name'; -import { validateRelationNameDoesNotConflictWithTypeName } from './validators/relationname-doesnot-conflict-with-typename'; -import { validateBelongsToFieldsMatchRelatedTypePrimaryKey } from './validators/belongs-to-fields-match-related-type-primary-key'; -import { validateTypeIsDefinedOnce } from './validators/type-is-defined-once'; -import { validateIndexIsDefinedOnce } from './validators/index-is-defined-once-in-model'; -import { validateIndexExistsInRelatedModel } from './validators/index-exists-in-related-model'; -import { validateEnumIsDefinedOnce } from './validators/enum-is-defined-once'; -import { validateKeyExistsInRelatedModel } from './validators/key-exists-in-related-model'; -import { validateBelongsToIsUsedWhenDatastoreInUse } from './validators/use-belongsto-when-datastore-inuse'; -import { validateDirectivesFromOlderTransformerVersionAreNotUsed } from './validators/use-directives-from-older-transformer-version'; -import { validateDirectivesFromNewerTransformerVersionAreNotUsed } from './validators/use-directives-from-newer-transformer-version'; -import { ValidateSchemaProps } from './helpers/schema-validator-props'; -import { validateFieldNamesAreUniqueWithRelationsPresent } from './validators/unique-field-names-with-relation'; -import { validateManyToManyHasRelationName } from './validators/many-to-many-has-a-relationname'; -import { validateHasOneNotUsedWithLists } from './validators/hasOne-cannot-be-used-with-lists'; -import { validateHasManyIsUsedWithLists } from './validators/hasMany-must-be-used-with-lists'; -import { validateObjectIsAnnotatedWithModel } from './validators/object-must-be-annotated-with-model'; -import { validateRelationshipNamesAreNotInverseOfRelationName } from './validators/relationshipname-not-inverseof-relationname'; -import { validateOwnerFieldTypeString } from './validators/owner-field-type-string'; -import { validateDefaultDirective } from './validators/default-directive-validation'; - -const allValidators = [ - validateIndexScalarTypes, - validateRequireBelongsToRelation, - validateManyToManyTwoLocations, - validateFieldIsDefinedOnce, - validateAuthIsAnnotatedWithModel, - verifyIndexSortKeyFieldsExistInModel, - validateReservedTypeNames, - validateCorrectTypeInManyToManyRelation, - validateReservedFieldNames, - validateRelationNameDoesNotConflictWithTypeName, - validateBelongsToFieldsMatchRelatedTypePrimaryKey, - validateTypeIsDefinedOnce, - validateIndexIsDefinedOnce, - validateFieldsMatchInParentModel, - validateIndexExistsInRelatedModel, - validateEnumIsDefinedOnce, - validateKeyExistsInRelatedModel, - validateFieldNamesAreUniqueWithRelationsPresent, - validateManyToManyHasRelationName, - validateHasOneNotUsedWithLists, - validateHasManyIsUsedWithLists, - validateObjectIsAnnotatedWithModel, - validateRelationshipNamesAreNotInverseOfRelationName, - validateOwnerFieldTypeString, - validateDefaultDirective, -]; - -const allValidatorsWithContext = [ - validateBelongsToIsUsedWhenDatastoreInUse, - validateDirectivesFromOlderTransformerVersionAreNotUsed, - validateDirectivesFromNewerTransformerVersionAreNotUsed, -]; - -/** - * The primary export of this library - * runs all validators and throws a ValidationException with all failure reasons - * - * @param schemaString the graphql schema - * @returns void - */ -export const validateSchema = (schemaString: string): void => { - const schema = parse(schemaString); - const validationErrors = allValidators.flatMap((validate) => validate(schema)); - if (validationErrors.length > 0) { - const allErrorMessages = validationErrors.map((error: Error) => `${error.name} - ${error.message}`); - throw new ValidationError(allErrorMessages.join('\n')); - } -}; - -/** - * The primary export of this library - * runs all validators which require context and throws a ValidationException with all failure reasons - * - * @param schemaString the graphql schema - * @param props feature flags that are required for validation - * @returns void - */ -export const validateSchemaWithContext = (schemaString: string, props: ValidateSchemaProps): void => { - const schema = parse(schemaString); - const validationErrors = allValidatorsWithContext.flatMap((validate) => validate(schema, props)); - if (validationErrors.length > 0) { - const allErrorMessages = validationErrors.map((error: Error) => `${error.name} - ${error.message}`); - throw new ValidationError(allErrorMessages.join('\n')); - } -}; diff --git a/packages/amplify-schema-validator/src/validators/auth-must-be-annotated-with-model.ts b/packages/amplify-schema-validator/src/validators/auth-must-be-annotated-with-model.ts deleted file mode 100644 index da5ea66ec5..0000000000 --- a/packages/amplify-schema-validator/src/validators/auth-must-be-annotated-with-model.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode } from 'graphql'; -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; - -/** - * Types annotated with @auth must also be annotated with @model. - * - * @param schema graphql schema - * @returns true if types annotated with @auth are also be annotated with @model. - */ - -export const validateAuthIsAnnotatedWithModel = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const directives = objectTypeDefinition.directives?.map((directive) => directive.name.value); - if (directives && directives.includes('auth') && !directives.includes('model')) { - errors.push(new InvalidDirectiveError('Types annotated with @auth must also be annotated with @model.')); - } - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/belongs-to-fields-match-related-type-primary-key.ts b/packages/amplify-schema-validator/src/validators/belongs-to-fields-match-related-type-primary-key.ts deleted file mode 100644 index 489dfa7915..0000000000 --- a/packages/amplify-schema-validator/src/validators/belongs-to-fields-match-related-type-primary-key.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { DocumentNode, Kind, ListValueNode, ObjectTypeDefinitionNode, StringValueNode } from 'graphql'; -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; -import { resolveFieldTypeName } from '../helpers/resolve-field-type-name'; -import { getObjectWithName } from '../helpers/get-object-with-name'; - -/** - * Validates that every @belongsTo fields match related type primary key - * - * @param schema graphql schema - * @returns true if @belongsTo fields match related type primary key - */ - -export const validateBelongsToFieldsMatchRelatedTypePrimaryKey = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const belongsToDirectiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'belongsTo'), - ); - - const fieldTypes = {} as { [fieldName: string]: string }; - objectTypeDefinition.fields?.forEach((field) => { - const fieldName = field.name.value; - const fieldType = resolveFieldTypeName(field.type); - fieldTypes[fieldName] = fieldType; - }); - - belongsToDirectiveFields?.forEach((belongsToDirectiveField) => { - const belongsTodirectiveArgs = belongsToDirectiveField.directives?.filter( - (belongsToDirective) => belongsToDirective.arguments && belongsToDirective.arguments.length > 0, - ); - belongsTodirectiveArgs?.forEach((belongsTodirectiveArg) => { - const fieldsArg = belongsTodirectiveArg?.arguments?.find((arg) => arg.name.value === 'fields'); - if (!fieldsArg) { - /* istanbul ignore next */ - return; - } - const fieldsVals = (fieldsArg?.value as ListValueNode)?.values; - const typeName = resolveFieldTypeName(belongsToDirectiveField.type); - const objectOfType = getObjectWithName(schema, typeName); - - const primaryKeyDirectiveFields = objectOfType?.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'primaryKey'), - ); - - if (primaryKeyDirectiveFields?.length === 0 && fieldsVals.length === 1) { - const fieldVal = (fieldsVals[0] as StringValueNode).value; - if (fieldTypes[fieldVal] !== 'ID') { - errors.push(new InvalidDirectiveError(`${fieldVal} field is not of type ID`)); - } - } - - const relatedModelFieldTypes = {} as { [fieldName: string]: string }; - objectOfType?.fields?.forEach((field) => { - const fieldName = field.name.value; - const fieldType = resolveFieldTypeName(field.type); - relatedModelFieldTypes[fieldName] = fieldType; - }); - - primaryKeyDirectiveFields?.forEach((primaryKeyDirectiveField) => { - const primaryKeydirectiveArgs = primaryKeyDirectiveField.directives?.filter( - (primaryKeyDirective) => primaryKeyDirective.arguments && primaryKeyDirective.arguments.length > 0, - ); - if (primaryKeydirectiveArgs?.length === 0 && fieldsVals.length === 1) { - const fieldVal = (fieldsVals[0] as StringValueNode).value; - const primaryKeyType = relatedModelFieldTypes[primaryKeyDirectiveField.name.value]; - if (fieldTypes[fieldVal] !== primaryKeyType) { - errors.push(new InvalidDirectiveError(`${fieldVal} field is not of type ${primaryKeyType}`)); - } - } - primaryKeydirectiveArgs?.forEach((primaryKeydirectiveArg) => { - const sortKeyFieldsArg = primaryKeydirectiveArg?.arguments?.find((arg) => arg.name.value === 'sortKeyFields'); - if (!sortKeyFieldsArg) { - if (fieldsVals.length === 1) { - const fieldVal = (fieldsVals[0] as StringValueNode).value; - const primaryKeyType = relatedModelFieldTypes[primaryKeyDirectiveField.name.value]; - if (fieldTypes[fieldVal] !== primaryKeyType) { - errors.push(new InvalidDirectiveError(`${fieldVal} field is not of type ${primaryKeyType}`)); - return errors; - } - } - } - - const sortKeyFieldsVals = (sortKeyFieldsArg?.value as ListValueNode).values; - - if (sortKeyFieldsVals.length === fieldsVals.length - 1) { - for (let i = 1; i < fieldsVals.length; i++) { - const fieldVal = (fieldsVals[i] as StringValueNode).value; - const sortKeyFieldVal = (sortKeyFieldsVals[i - 1] as StringValueNode).value; - if (fieldTypes[fieldVal] !== relatedModelFieldTypes[sortKeyFieldVal]) { - errors.push(new InvalidDirectiveError(`${fieldVal} field is not of type ${relatedModelFieldTypes[sortKeyFieldVal]}`)); - } - } - } - return errors; - }); - return errors; - }); - }); - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/correct-type-in-many-to-many-relation.ts b/packages/amplify-schema-validator/src/validators/correct-type-in-many-to-many-relation.ts deleted file mode 100644 index de3970fd5f..0000000000 --- a/packages/amplify-schema-validator/src/validators/correct-type-in-many-to-many-relation.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode, StringValueNode } from 'graphql'; -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; -import { resolveFieldTypeName } from '../helpers/resolve-field-type-name'; - -/** - * Validates that every @manyToMany relation has correct types - * - * @param schema graphql schema - * @returns true if @manyToMany relation has correct type - */ - -export const validateCorrectTypeInManyToManyRelation = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - - const relationObjectNames = {} as { [relationName: string]: string[] }; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const directiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'manyToMany'), - ); - - const objectName = objectTypeDefinition.name.value; - - directiveFields?.forEach((directiveField) => { - const directiveArgs = directiveField.directives?.filter((directive) => directive.arguments && directive.arguments.length > 0); - directiveArgs?.forEach((directiveArg) => { - const fieldArg = directiveArg?.arguments?.find((arg) => arg.name.value === 'relationName'); - if (!fieldArg) { - /* istanbul ignore next */ - return; - } - - const relationName = (fieldArg?.value as StringValueNode)?.value; - - if (relationObjectNames[relationName]) { - relationObjectNames[relationName].push(objectName); - } else { - const objectNames = []; - objectNames.push(objectName); - relationObjectNames[relationName] = objectNames; - } - }); - }); - }); - - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const directiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'manyToMany'), - ); - const objectName = objectTypeDefinition.name.value; - directiveFields?.forEach((directiveField) => { - const typeName = resolveFieldTypeName(directiveField.type); - const directiveArgs = directiveField.directives?.filter((directive) => directive.arguments && directive.arguments.length > 0); - directiveArgs?.forEach((directiveArg) => { - const fieldArg = directiveArg?.arguments?.find((arg) => arg.name.value === 'relationName'); - if (!fieldArg) { - /* istanbul ignore next */ - return; - } - - const relationName = (fieldArg?.value as StringValueNode)?.value; - - const objectNames = relationObjectNames[relationName]; - - if (typeName === objectName || !objectNames.includes(typeName)) { - let expectedName; - objectNames.forEach((name) => { - if (name !== objectName) { - expectedName = name; - } - }); - errors.push(new InvalidDirectiveError(`@manyToMany relation ${relationName} expects ${expectedName} but got ${typeName}`)); - } - }); - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/default-directive-validation.ts b/packages/amplify-schema-validator/src/validators/default-directive-validation.ts deleted file mode 100644 index 9f534ea21a..0000000000 --- a/packages/amplify-schema-validator/src/validators/default-directive-validation.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode, EnumTypeDefinitionNode } from 'graphql'; -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; -import { isScalarOrEnum } from '../helpers/is-scalar-or-enum'; -import { getTypeDefinitionsOfKind } from '../helpers/get-type-definitions-of-kind'; - -/** - * Validates all the @default directive validations - * - * @param schema graphql schema - * @returns true if @default directive validations are satsified - */ - -export const validateDefaultDirective = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const directives = objectTypeDefinition.directives?.map((directive) => directive.name.value); - - const defaultDirectiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'default'), - ); - - if (defaultDirectiveFields && defaultDirectiveFields?.length > 0 && !directives?.includes('model')) { - errors.push(new InvalidDirectiveError('The @default directive may only be added to object definitions annotated with @model.')); - return errors; - } - - defaultDirectiveFields?.forEach((defaultDirectiveField) => { - const defaultDirectiveArgs = defaultDirectiveField.directives?.filter( - (defaultDirective) => defaultDirective.arguments && defaultDirective.arguments.length > 0, - ); - - const enums = getTypeDefinitionsOfKind(schema, Kind.ENUM_TYPE_DEFINITION) as EnumTypeDefinitionNode[]; - if (!isScalarOrEnum(defaultDirectiveField.type, enums)) { - errors.push(new InvalidDirectiveError('The @default directive may only be added to scalar or enum field types.')); - return errors; - } - - defaultDirectiveArgs?.forEach((defaultDirectiveArg) => { - if (defaultDirectiveArg.name.value === 'default') { - if (defaultDirectiveArg.arguments && defaultDirectiveArg?.arguments?.length > 1) { - errors.push(new InvalidDirectiveError('The @default directive only takes a value property')); - return errors; - } - - const fieldsArg = defaultDirectiveArg?.arguments?.find((arg) => arg.name.value === 'value'); - if (!fieldsArg) { - /* istanbul ignore next */ - return; - } - - if (fieldsArg.value.kind !== 'StringValue') { - errors.push( - new InvalidDirectiveError('String cannot represent a non string value: the @default directive has a non String value'), - ); - return errors; - } - } - }); - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/enum-is-defined-once.ts b/packages/amplify-schema-validator/src/validators/enum-is-defined-once.ts deleted file mode 100644 index ff5bda9560..0000000000 --- a/packages/amplify-schema-validator/src/validators/enum-is-defined-once.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { DocumentNode, Kind, EnumTypeDefinitionNode } from 'graphql'; -import { ValidationError } from '../exceptions/validation-error'; - -/** - * Enum is defined once - * - * @param schema graphql schema - * @returns true if an enum is defined once - */ - -export const validateEnumIsDefinedOnce = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const enumTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.ENUM_TYPE_DEFINITION, - ) as EnumTypeDefinitionNode[]; - - enumTypeDefinitions.forEach((enumTypeDefinition) => { - const enumName = enumTypeDefinition.name.value; - const enumValues = enumTypeDefinition.values; - if (!enumValues) { - /* istanbul ignore next */ - return; - } - - const uniqueEnums: string[] = []; - enumValues?.forEach((enumVal) => { - const val = enumVal.name.value; - if (!uniqueEnums.includes(val)) { - uniqueEnums.push(val); - } else { - errors.push(new ValidationError(`Schema validation failed. Enum value ${enumName}.${val} can only be defined once.`)); - } - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/field-is-defined-once.ts b/packages/amplify-schema-validator/src/validators/field-is-defined-once.ts deleted file mode 100644 index 0ce76b5646..0000000000 --- a/packages/amplify-schema-validator/src/validators/field-is-defined-once.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode } from 'graphql'; -import { ValidationError } from '../exceptions/validation-error'; - -/** - * Field is defined once in a model - * - * @param schema graphql schema - * @returns true if a field is defined once in a model - */ - -export const validateFieldIsDefinedOnce = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const objectName = objectTypeDefinition.name.value; - const { fields } = objectTypeDefinition; - if (!fields) { - /* istanbul ignore next */ - return; - } - - const uniquefields: string[] = []; - fields?.forEach((field) => { - const val = field.name.value; - if (!uniquefields.includes(val)) { - uniquefields.push(val); - } else { - errors.push(new ValidationError(`Schema validation failed. Field ${objectName}.${val} can only be defined once.`)); - } - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/fields-match-in-parent-model.ts b/packages/amplify-schema-validator/src/validators/fields-match-in-parent-model.ts deleted file mode 100644 index e0b522aa70..0000000000 --- a/packages/amplify-schema-validator/src/validators/fields-match-in-parent-model.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { DocumentNode, Kind, ListValueNode, ObjectTypeDefinitionNode, StringValueNode } from 'graphql'; -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; - -/** - * Validates that fields match in the parent model - * - * @param schema graphql schema - * @returns true if fields match in parent model - */ - -export const validateFieldsMatchInParentModel = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const directiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find( - (directive) => - directive.name.value === 'connection' || - directive.name.value === 'hasOne' || - directive.name.value === 'belongsTo' || - directive.name.value === 'hasMany', - ), - ); - - directiveFields?.forEach((directiveField) => { - const fields = objectTypeDefinition?.fields; - if (!fields) { - /* istanbul ignore next */ - return; - } - - const fieldVals = fields.map((field) => field.name.value); - - const directiveArgs = directiveField.directives?.filter((directive) => directive.arguments && directive.arguments.length > 0); - directiveArgs?.forEach((directiveArg) => { - const fieldArg = directiveArg?.arguments?.find((arg) => arg.name.value === 'fields'); - if (!fieldArg) { - /* istanbul ignore next */ - return; - } - - const fieldArgVals = (fieldArg.value as ListValueNode).values; - fieldArgVals.forEach((fieldArgVal) => { - const val = (fieldArgVal as StringValueNode).value; - if (!fieldVals.includes(val)) { - errors.push(new InvalidDirectiveError(`${val} is not a field in ${objectTypeDefinition.name.value}`)); - } - }); - }); - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/hasMany-must-be-used-with-lists.ts b/packages/amplify-schema-validator/src/validators/hasMany-must-be-used-with-lists.ts deleted file mode 100644 index c288bf5aba..0000000000 --- a/packages/amplify-schema-validator/src/validators/hasMany-must-be-used-with-lists.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode } from 'graphql'; -import { isListType } from '../helpers/resolve-field-type'; -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; - -/** - * Validates that directive hasMany is used with lists - * - * @param schema graphql schema - * @returns true if hasMany is used with lists - */ - -export const validateHasManyIsUsedWithLists = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const objectName = objectTypeDefinition.name.value; - const directiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'hasMany'), - ); - - directiveFields?.forEach((directiveField) => { - const listType = isListType(directiveField.type); - if (!listType) { - errors.push( - new InvalidDirectiveError( - `${directiveField.name.value} field in ${objectName} object has a @hasMany directive which must be used with a list. Use @hasOne for non-list types.`, - ), - ); - } - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/hasOne-cannot-be-used-with-lists.ts b/packages/amplify-schema-validator/src/validators/hasOne-cannot-be-used-with-lists.ts deleted file mode 100644 index 23d9d0f322..0000000000 --- a/packages/amplify-schema-validator/src/validators/hasOne-cannot-be-used-with-lists.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode } from 'graphql'; -import { isListType } from '../helpers/resolve-field-type'; -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; - -/** - * Validates that directive hasOne is not used with a list - * - * @param schema graphql schema - * @returns true if hasOne is not used with lists - */ - -export const validateHasOneNotUsedWithLists = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const objectName = objectTypeDefinition.name.value; - const directiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'hasOne'), - ); - - directiveFields?.forEach((directiveField) => { - const listType = isListType(directiveField.type); - if (listType) { - errors.push( - new InvalidDirectiveError( - `@hasOne cannot be used with lists in ${directiveField.name.value} field in ${objectName} object. Use @hasMany instead`, - ), - ); - } - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/index-exists-in-related-model.ts b/packages/amplify-schema-validator/src/validators/index-exists-in-related-model.ts deleted file mode 100644 index 8fd313b337..0000000000 --- a/packages/amplify-schema-validator/src/validators/index-exists-in-related-model.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode, StringValueNode } from 'graphql'; -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; -import { getObjectWithName } from '../helpers/get-object-with-name'; -import { resolveFieldTypeName } from '../helpers/resolve-field-type-name'; - -/** - * Validates that index exists in the related model - * - * @param schema graphql schema - * @returns true if index exists in the related model - */ - -export const validateIndexExistsInRelatedModel = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const hasManyDirectiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'hasMany'), - ); - - hasManyDirectiveFields?.forEach((hasManyDirectiveField) => { - const hasManyDirectiveArgs = hasManyDirectiveField.directives?.filter( - (hasManyDirective) => hasManyDirective.arguments && hasManyDirective.arguments.length > 0, - ); - hasManyDirectiveArgs?.forEach((hasManyDirectiveArg) => { - const indexNameFieldArg = hasManyDirectiveArg?.arguments?.find((arg) => arg.name.value === 'indexName'); - if (!indexNameFieldArg) { - /* istanbul ignore next */ - return; - } - - const indexName = (indexNameFieldArg.value as StringValueNode).value; - - const typeName = resolveFieldTypeName(hasManyDirectiveField.type); - const objectOfType = getObjectWithName(schema, typeName); - const indexDirectiveFields = objectOfType?.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'index'), - ); - - const indexNameInRelatedModel: string[] = []; - indexDirectiveFields?.forEach((indexDirectiveField) => { - const indexDirectiveArgs = indexDirectiveField.directives?.filter( - (indexDirective) => indexDirective.arguments && indexDirective.arguments.length > 0, - ); - indexDirectiveArgs?.forEach((indexDirectiveArg) => { - const nameFieldArg = indexDirectiveArg?.arguments?.find((arg) => arg.name.value === 'name'); - if (!nameFieldArg) { - /* istanbul ignore next */ - return; - } - - indexNameInRelatedModel.push((nameFieldArg.value as StringValueNode).value); - }); - }); - - if (!indexNameInRelatedModel.includes(indexName)) { - errors.push(new InvalidDirectiveError(`Index ${indexName} does not exist for model ${objectOfType?.name.value}`)); - } - }); - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/index-is-defined-once-in-model.ts b/packages/amplify-schema-validator/src/validators/index-is-defined-once-in-model.ts deleted file mode 100644 index 451591ebc2..0000000000 --- a/packages/amplify-schema-validator/src/validators/index-is-defined-once-in-model.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode, StringValueNode } from 'graphql'; -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; - -/** - * Validates that an index with same name exists only once in a model - * - * @param schema graphql schema - * @returns true if an index with same name exists only once in a model - */ - -export const validateIndexIsDefinedOnce = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const objectName = objectTypeDefinition.name.value; - const directiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'index'), - ); - - if (!directiveFields) { - /* istanbul ignore next */ - return; - } - - const uniqueIndexNames: string[] = []; - directiveFields.forEach((directiveField) => { - const directiveArgs = directiveField.directives?.filter((directive) => directive.arguments && directive.arguments.length > 0); - directiveArgs?.forEach((directiveArg) => { - const fieldArg = directiveArg?.arguments?.find((arg) => arg.name.value === 'name'); - if (!fieldArg) { - /* istanbul ignore next */ - return; - } - const indexName = (fieldArg.value as StringValueNode).value; - if (uniqueIndexNames.includes(indexName)) { - errors.push(new InvalidDirectiveError(`You may only supply one @index with the name ${indexName} on type ${objectName}`)); - } else { - uniqueIndexNames.push(indexName); - } - }); - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/index-scalar-types.ts b/packages/amplify-schema-validator/src/validators/index-scalar-types.ts deleted file mode 100644 index 585eb1a6c8..0000000000 --- a/packages/amplify-schema-validator/src/validators/index-scalar-types.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode, FieldDefinitionNode, EnumTypeDefinitionNode } from 'graphql'; -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; -import { isScalarOrEnum } from '../helpers/is-scalar-or-enum'; -import { getTypeDefinitionsOfKind } from '../helpers/get-type-definitions-of-kind'; - -/** - * Validates that every @index directive is of a scalar type - * - * @param schema graphql schema - * @returns true - */ - -export const validateIndexScalarTypes = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - const allObjectFields = objectTypeDefinitions.reduce( - (acc, objectTypeDefinition) => acc.concat(objectTypeDefinition.fields as FieldDefinitionNode[]), - [] as FieldDefinitionNode[], - ); - - const fieldsWithIndexDirectives = allObjectFields.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'index'), - ); - - const enums = getTypeDefinitionsOfKind(schema, Kind.ENUM_TYPE_DEFINITION) as EnumTypeDefinitionNode[]; - const fieldsWithNonScalarIndex = fieldsWithIndexDirectives.filter((field) => !isScalarOrEnum(field.type, enums)); - const fieldNamesWithNonScalarIndex = fieldsWithNonScalarIndex.map((field) => field.name.value); - if (fieldsWithNonScalarIndex.length) { - errors.push(new InvalidDirectiveError(`@index directive on '${fieldNamesWithNonScalarIndex.join(', ')}' cannot be a non-scalar`)); - } - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/key-exists-in-related-model.ts b/packages/amplify-schema-validator/src/validators/key-exists-in-related-model.ts deleted file mode 100644 index 7bdf74f1cf..0000000000 --- a/packages/amplify-schema-validator/src/validators/key-exists-in-related-model.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode, StringValueNode } from 'graphql'; -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; -import { getObjectWithName } from '../helpers/get-object-with-name'; -import { resolveFieldTypeName } from '../helpers/resolve-field-type-name'; - -/** - * Validates that key exists in the related model - * - * @param schema graphql schema - * @returns true if key exists in the related model - */ - -export const validateKeyExistsInRelatedModel = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const connectionDirectiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'connection'), - ); - - connectionDirectiveFields?.forEach((connectionDirectiveField) => { - const connectionDirectiveArgs = connectionDirectiveField.directives?.filter( - (connectionDirective) => connectionDirective.arguments && connectionDirective.arguments.length > 0, - ); - connectionDirectiveArgs?.forEach((connectionDirectiveArg) => { - const keyNameFieldArg = connectionDirectiveArg?.arguments?.find((arg) => arg.name.value === 'keyName'); - if (!keyNameFieldArg) { - /* istanbul ignore next */ - return; - } - - const keyName = (keyNameFieldArg.value as StringValueNode).value; - const typeName = resolveFieldTypeName(connectionDirectiveField.type); - const objectOfType = getObjectWithName(schema, typeName); - const keyDirective = objectOfType?.directives?.find((directive) => directive.name.value === 'key'); - if (!keyDirective) { - errors.push(new InvalidDirectiveError(`Key ${keyName} does not exist for model ${objectOfType?.name.value}`)); - } - - keyDirective?.arguments?.forEach((keyDirectiveArg) => { - if (keyDirectiveArg.name.value === 'name' && (keyDirectiveArg.value as StringValueNode).value !== keyName) { - errors.push(new InvalidDirectiveError(`Key ${keyName} does not exist for model ${objectOfType?.name.value}`)); - } - }); - }); - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/many-to-many-has-a-relationname.ts b/packages/amplify-schema-validator/src/validators/many-to-many-has-a-relationname.ts deleted file mode 100644 index 39fc847fb1..0000000000 --- a/packages/amplify-schema-validator/src/validators/many-to-many-has-a-relationname.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode, StringValueNode } from 'graphql'; -import { ValidationError } from '../exceptions/validation-error'; - -/** - * Validates that directive manyTomany has a relationName - * - * @param schema graphql schema - * @returns true if manytomany has a relationName - */ - -export const validateManyToManyHasRelationName = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const directiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'manyToMany'), - ); - - directiveFields?.forEach((directiveField) => { - const directiveArgs = directiveField.directives?.filter((directive) => directive.arguments && directive.arguments.length > 0); - if (!directiveArgs || directiveArgs.length == 0) { - errors.push(new ValidationError('@manyToMany relation does not have a relationName')); - } - directiveArgs?.forEach((directiveArg) => { - const fieldArg = directiveArg?.arguments?.find((arg) => arg.name.value === 'relationName'); - if (!fieldArg) { - errors.push(new ValidationError('@manyToMany relation does not have a relationName')); - } - }); - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/object-must-be-annotated-with-model.ts b/packages/amplify-schema-validator/src/validators/object-must-be-annotated-with-model.ts deleted file mode 100644 index d6ff2105e9..0000000000 --- a/packages/amplify-schema-validator/src/validators/object-must-be-annotated-with-model.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode } from 'graphql'; -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; -import { getObjectWithName } from '../helpers/get-object-with-name'; -import { resolveFieldTypeName } from '../helpers/resolve-field-type-name'; - -/** - * Validates @belongsTo/@hasOne/@hasMany/@connection was used with a related type that is a model - * - * @param schema graphql schema - * @returns true if @belongsTo/@hasOne/@hasMany/@connection was used with a related type that is a model - */ - -export const validateObjectIsAnnotatedWithModel = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const directiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find( - (directive) => - directive.name.value === 'connection' || - directive.name.value === 'hasOne' || - directive.name.value === 'belongsTo' || - directive.name.value === 'hasMany', - ), - ); - directiveFields?.forEach((directiveField) => { - const typeName = resolveFieldTypeName(directiveField.type); - const objectOfType = getObjectWithName(schema, typeName); - const directives = objectOfType?.directives?.map((directive) => directive.name.value); - if (!directives || !directives.includes('model')) { - errors.push(new InvalidDirectiveError(`Object type ${objectOfType?.name.value} must be annotated with @model`)); - } - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/owner-field-type-string.ts b/packages/amplify-schema-validator/src/validators/owner-field-type-string.ts deleted file mode 100644 index 21f7248fa1..0000000000 --- a/packages/amplify-schema-validator/src/validators/owner-field-type-string.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { DocumentNode, Kind, ListValueNode, ObjectTypeDefinitionNode, ObjectValueNode } from 'graphql'; -import { ValidationError } from '../exceptions/validation-error'; - -/** - * Types annotated with @auth must also be annotated with @model. - * - * @param schema graphql schema - * @returns true if types annotated with @auth are also be annotated with @model. - */ - -export const validateOwnerFieldTypeString = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const directives = objectTypeDefinition.directives; - directives?.forEach((directive) => { - if (directive.name.value === 'auth') { - const directiveArgs = directive.arguments; - directiveArgs?.forEach((directiveArg) => { - if (directiveArg.name.value === 'rules') { - const authArgs = (directiveArg.value as ListValueNode).values.find((elem) => elem.kind); - const authFields = (authArgs as ObjectValueNode).fields; - authFields.forEach((authField) => { - if (authField.name.value === 'ownerField' && authField.value.kind !== 'StringValue') { - errors.push(new ValidationError('String cannot represent a non string value')); - return errors; - } - }); - } - }); - } - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/relation-required-with-belongs-to.ts b/packages/amplify-schema-validator/src/validators/relation-required-with-belongs-to.ts deleted file mode 100644 index b6f2c96ef8..0000000000 --- a/packages/amplify-schema-validator/src/validators/relation-required-with-belongs-to.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode } from 'graphql'; -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; -import { getObjectWithName } from '../helpers/get-object-with-name'; -import { resolveFieldTypeName } from '../helpers/resolve-field-type-name'; - -/** - * The @belongsTo directive requires that a @hasOne or @hasMany relationship already exists from parent to the related model. - * - * @param schema graphql schema - * @returns true - */ - -export const validateRequireBelongsToRelation = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const objectName = objectTypeDefinition.name.value; - const belongsToFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'belongsTo'), - ); - belongsToFields?.forEach((belongsToField) => { - const typeName = resolveFieldTypeName(belongsToField.type); - const objectOfType = getObjectWithName(schema, typeName); - const relationField = objectOfType?.fields?.find((field) => resolveFieldTypeName(field.type) === objectName); - const relationDirective = relationField?.directives?.find((directive) => ['hasOne', 'hasMany'].includes(directive.name.value)); - if (!relationDirective) { - errors.push( - new InvalidDirectiveError( - 'Invalid @belongs directive in schema: @belongsTo directive requires that a @hasOne or @hasMany relationship already exists from parent to the related model.', - ), - ); - } - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/relationname-doesnot-conflict-with-typename.ts b/packages/amplify-schema-validator/src/validators/relationname-doesnot-conflict-with-typename.ts deleted file mode 100644 index 39ef038247..0000000000 --- a/packages/amplify-schema-validator/src/validators/relationname-doesnot-conflict-with-typename.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode, StringValueNode } from 'graphql'; -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; -import { getGraphqlName, toUpper } from '../helpers/util'; - -/** - * Validates that relation name does not conflict with an existing type name - * - * @param schema graphql schema - * @returns true if relation name does not conflict with an existing type name - */ - -export const validateRelationNameDoesNotConflictWithTypeName = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - const typeNames = objectTypeDefinitions.map((objectTypeDefinition) => objectTypeDefinition.name.value); - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const directiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'manyToMany'), - ); - - directiveFields?.forEach((directiveField) => { - const directiveArgs = directiveField.directives?.filter((directive) => directive.arguments && directive.arguments.length > 0); - directiveArgs?.forEach((directiveArg) => { - const fieldArg = directiveArg?.arguments?.find((arg) => arg.name.value === 'relationName'); - if (!fieldArg) { - /* istanbul ignore next */ - return; - } - - const val = (fieldArg.value as StringValueNode).value; - const graphqlName = getGraphqlName(toUpper(val)); - if (typeNames.includes(graphqlName)) { - errors.push( - new InvalidDirectiveError( - `@manyToMany relation name ${graphqlName} (derived from ${val}) already exists as a type in the schema.`, - ), - ); - } - }); - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/relationshipname-not-inverseof-relationname.ts b/packages/amplify-schema-validator/src/validators/relationshipname-not-inverseof-relationname.ts deleted file mode 100644 index ea148cc622..0000000000 --- a/packages/amplify-schema-validator/src/validators/relationshipname-not-inverseof-relationname.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode, StringValueNode } from 'graphql'; -import { ValidationError } from '../exceptions/validation-error'; - -/** - * Validates that relationship names are not inverse of relation names - * - * @param schema graphql schema - * @returns true if relationship names are not inverse of relation names - */ - -export const validateRelationshipNamesAreNotInverseOfRelationName = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const objectName = objectTypeDefinition.name.value; - const directiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'manyToMany'), - ); - directiveFields?.forEach((directiveField) => { - const directiveArgs = directiveField.directives?.filter((directive) => directive.arguments && directive.arguments.length > 0); - directiveArgs?.forEach((directiveArg) => { - const fieldArg = directiveArg?.arguments?.find((arg) => arg.name.value === 'relationName'); - if (!fieldArg) { - /* istanbul ignore next */ - return; - } - - const relationName = (fieldArg?.value as StringValueNode)?.value; - const resolver1 = relationName.concat(objectName); - const resolver2 = objectName.concat(directiveField.name.value); - - if (resolver1 === resolver2) { - errors.push( - new ValidationError( - `Relationship name ${directiveField.name.value} conflicts with relationName ${relationName}. Please change your relationship name`, - ), - ); - } - }); - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/reserved-field-name.ts b/packages/amplify-schema-validator/src/validators/reserved-field-name.ts deleted file mode 100644 index c970b4276d..0000000000 --- a/packages/amplify-schema-validator/src/validators/reserved-field-name.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode } from 'graphql'; -import { ValidationError } from '../exceptions/validation-error'; - -/** - * Reserved words are not used in field names - * - * @param schema graphql schema - * @returns true if reserved words are not used in field names - */ - -export const validateReservedFieldNames = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const reservedWords = ['_version', '_changedAt', '_deleted']; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const { fields } = objectTypeDefinition; - - fields?.forEach((field) => { - const fieldName = field.name.value; - if (reservedWords.includes(fieldName)) { - errors.push(new ValidationError(`${fieldName} is a reserved word and cannnot be used as a field name.`)); - } - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/reserved-type-name.ts b/packages/amplify-schema-validator/src/validators/reserved-type-name.ts deleted file mode 100644 index 4d5a4f0078..0000000000 --- a/packages/amplify-schema-validator/src/validators/reserved-type-name.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode } from 'graphql'; -import { ValidationError } from '../exceptions/validation-error'; - -/** - * Reserved words are not used in type names - * - * @param schema graphql schema - * @returns true if reserved words are not used in type names - */ - -export const validateReservedTypeNames = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const reservedWords = ['Query', 'Mutation', 'Subscription']; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const objectName = objectTypeDefinition.name.value; - const directives = objectTypeDefinition.directives?.map((directive) => directive.name.value); - if (directives && directives.includes('model') && reservedWords.includes(objectName)) { - errors.push(new ValidationError(`${objectName} is a reserved type name and currently in use within the default schema element.`)); - } - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/sort-key-field-exists.ts b/packages/amplify-schema-validator/src/validators/sort-key-field-exists.ts deleted file mode 100644 index 100d4e6deb..0000000000 --- a/packages/amplify-schema-validator/src/validators/sort-key-field-exists.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode, ListValueNode, StringValueNode } from 'graphql'; -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; - -/** - * Validates that sort key fields exists in model - * - * @param schema graphql schema - * @returns true if sort key fields exists in model - */ - -export const verifyIndexSortKeyFieldsExistInModel = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const directiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'index'), - ); - - directiveFields?.forEach((directiveField) => { - const fieldVals = objectTypeDefinition.fields?.map((field) => field.name.value); - - const directiveArgs = directiveField.directives?.filter((directive) => directive.arguments && directive.arguments.length > 0); - directiveArgs?.forEach((directiveArg) => { - const sortKeyFieldArg = directiveArg?.arguments?.find((arg) => arg.name.value === 'sortKeyFields'); - if (!sortKeyFieldArg) { - /* istanbul ignore next */ - return; - } - const sortKeyFieldArgVals = (sortKeyFieldArg.value as ListValueNode).values; - sortKeyFieldArgVals.forEach((fieldArgVal) => { - const val = (fieldArgVal as StringValueNode).value; - if (!fieldVals?.includes(val)) { - const nameFieldArg = directiveArg?.arguments?.find((arg) => arg.name.value === 'name'); - const nameVal = (nameFieldArg?.value as StringValueNode).value; - errors.push( - new InvalidDirectiveError( - `Can't find field '${val}' in ${objectTypeDefinition.name.value}, but it was specified in index '${nameVal}'`, - ), - ); - } - }); - }); - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/two-many-to-many-locations.ts b/packages/amplify-schema-validator/src/validators/two-many-to-many-locations.ts deleted file mode 100644 index 8c98fd2a6b..0000000000 --- a/packages/amplify-schema-validator/src/validators/two-many-to-many-locations.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode, FieldDefinitionNode, StringValueNode } from 'graphql'; -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; - -/** - * Validates that every @manyToMany relation has exactly two matching fields - * - * @param schema graphql schema - * @returns true - */ - -export const validateManyToManyTwoLocations = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - const allObjectFields = objectTypeDefinitions.reduce((acc, objectTypeDefinition) => { - if (objectTypeDefinition.fields) { - return acc.concat(objectTypeDefinition.fields); - } - /* istanbul ignore next */ - return acc; - }, [] as FieldDefinitionNode[]); - const allManyToManyDirectives = allObjectFields - .map((objectField) => objectField.directives?.find((directive) => directive.name.value === 'manyToMany')) - .filter((directive) => directive); - - const relationCounts = {} as { [relationName: string]: number }; - allManyToManyDirectives.forEach((directive) => { - const relationNameArgument = directive?.arguments?.find((argument) => argument.name.value === 'relationName'); - const relationName = (relationNameArgument?.value as StringValueNode)?.value; - relationCounts[relationName] = relationCounts[relationName] ? relationCounts[relationName] + 1 : 1; - }); - - const unmatchedRelations = Object.keys(relationCounts).filter((relationName) => relationCounts[relationName] !== 2); - if (unmatchedRelations.length) { - errors.push( - new InvalidDirectiveError( - `Invalid @manyToMany directive in schema: relation names '${unmatchedRelations.join(', ')}' must be used in exactly two locations.`, - ), - ); - } - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/type-is-defined-once.ts b/packages/amplify-schema-validator/src/validators/type-is-defined-once.ts deleted file mode 100644 index 3dc43fee5b..0000000000 --- a/packages/amplify-schema-validator/src/validators/type-is-defined-once.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode } from 'graphql'; -import { ValidationError } from '../exceptions/validation-error'; - -/** - * Type is defined once in the schema - * - * @param schema graphql schema - * @returns true if a type is defined once in the schema - */ - -export const validateTypeIsDefinedOnce = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - - const uniqueTypes: string[] = []; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const objectName = objectTypeDefinition.name.value; - if (!uniqueTypes.includes(objectName)) { - uniqueTypes.push(objectName); - } else { - errors.push(new ValidationError(`Schema validation failed. There can be only one type named ${objectName}.`)); - } - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/unique-field-names-with-relation.ts b/packages/amplify-schema-validator/src/validators/unique-field-names-with-relation.ts deleted file mode 100644 index bd43ccdbf0..0000000000 --- a/packages/amplify-schema-validator/src/validators/unique-field-names-with-relation.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode } from 'graphql'; -import { ValidationError } from '../exceptions/validation-error'; - -/** - * Validates that two or more relationship fields with the same name does not exist - * - * @param schema graphql schema - * @returns true if relationship fields are unique - */ - -export const validateFieldNamesAreUniqueWithRelationsPresent = (schema: DocumentNode): Error[] => { - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const directiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.some( - (directive) => directive.name.value === 'manyToMany' || directive.name.value === 'hasMany' || directive.name.value === 'hasOne', - ), - ); - - const uniquefields = new Set(); - directiveFields?.forEach((field) => { - const val = field.name.value; - if (!uniquefields.has(val.toLowerCase())) { - uniquefields.add(val.toLowerCase()); - } else { - errors.push(new ValidationError(`There are two or more relationship fields with the same name`)); - } - }); - }); - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/use-belongsto-when-datastore-inuse.ts b/packages/amplify-schema-validator/src/validators/use-belongsto-when-datastore-inuse.ts deleted file mode 100644 index b540b98bf5..0000000000 --- a/packages/amplify-schema-validator/src/validators/use-belongsto-when-datastore-inuse.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode } from 'graphql'; -import { InvalidDirectiveError } from '../exceptions/invalid-directive-error'; -import { getObjectWithName } from '../helpers/get-object-with-name'; -import { resolveFieldTypeName } from '../helpers/resolve-field-type-name'; -import { ValidateSchemaProps } from '../helpers/schema-validator-props'; - -/** - * Validates that models do not refer each other with @hasMany/@hasOne relation when dataStore is enabled - * - * @param schema graphql schema - * @returns true if models do not refer each other with @hasMany/@hasOne relation when dataStore is enabled - */ - -export const validateBelongsToIsUsedWhenDatastoreInUse = (schema: DocumentNode, props: ValidateSchemaProps): Error[] => { - if (!props.isDataStoreEnabled) { - return []; - } - - const errors: Error[] = []; - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - for (let i = 0; i < objectTypeDefinitions.length; i++) { - const objectTypeDefinition = objectTypeDefinitions[i]; - const directiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'hasOne' || directive.name.value === 'hasMany'), - ); - - const objectName = objectTypeDefinition.name.value; - directiveFields?.forEach((directiveField) => { - const typeName = resolveFieldTypeName(directiveField.type); - const relatedObject = getObjectWithName(schema, typeName); - - if (relatedObject?.name.value === objectName) { - /* istanbul ignore next */ - return; - } - - const relatedObjectdirectiveFields = relatedObject?.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'hasOne' || directive.name.value === 'hasMany'), - ); - - if (!relatedObjectdirectiveFields) { - /* istanbul ignore next */ - return; - } - - for (let j = 0; j < relatedObjectdirectiveFields.length; j++) { - const relatedObjectdirectiveField = relatedObjectdirectiveFields[j]; - const typeName1 = resolveFieldTypeName(relatedObjectdirectiveField.type); - const relatedObject1 = getObjectWithName(schema, typeName1); - if (relatedObject1?.name.value === objectName) { - errors.push( - new InvalidDirectiveError( - `${relatedObject?.name.value} and ${objectName} cannot refer to each other via @hasOne or @hasMany when DataStore is in use. Use @belongsTo instead. See https://docs.amplify.aws/cli/graphql/data-modeling/#belongs-to-relationship`, - ), - ); - break; - } - } - }); - if (errors.length > 0) { - break; - } - } - return errors; -}; diff --git a/packages/amplify-schema-validator/src/validators/use-directives-from-newer-transformer-version.ts b/packages/amplify-schema-validator/src/validators/use-directives-from-newer-transformer-version.ts deleted file mode 100644 index cd0f17cac6..0000000000 --- a/packages/amplify-schema-validator/src/validators/use-directives-from-newer-transformer-version.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode } from 'graphql'; -import { ValidateSchemaProps } from '../helpers/schema-validator-props'; -import { transformerValidationErrors } from '../helpers/transformer-validation'; - -/** - * Validates that @belongsTo, @connection directives from older graphql transformer version is not used in version 1.0 - * - * @param schema graphql schema - * @returns true if correct directives are used - */ - -const GRAPHQL_TRANSFORMER_V2_DIRECTIVES = ['hasOne', 'index', 'primaryKey', 'belongsTo', 'manyToMany', 'hasMany', 'default']; -export const validateDirectivesFromNewerTransformerVersionAreNotUsed = (schema: DocumentNode, props: ValidateSchemaProps): Error[] => { - if (props.graphqlTransformerVersion !== 1) { - return []; - } - - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - const v2DirectivesInUse = new Set(); - - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const directiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find((directive) => GRAPHQL_TRANSFORMER_V2_DIRECTIVES.includes(directive.name.value)), - ); - - directiveFields?.forEach((directiveField) => { - const { directives } = directiveField; - - directives?.forEach((directive) => { - const directiveName = directive.name.value; - if (GRAPHQL_TRANSFORMER_V2_DIRECTIVES.includes(directiveName)) { - v2DirectivesInUse.add(`@${directiveName}`); - } - }); - }); - }); - - return transformerValidationErrors(v2DirectivesInUse, props.graphqlTransformerVersion); -}; diff --git a/packages/amplify-schema-validator/src/validators/use-directives-from-older-transformer-version.ts b/packages/amplify-schema-validator/src/validators/use-directives-from-older-transformer-version.ts deleted file mode 100644 index faf16ac9db..0000000000 --- a/packages/amplify-schema-validator/src/validators/use-directives-from-older-transformer-version.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { DocumentNode, Kind, ObjectTypeDefinitionNode } from 'graphql'; -import { ValidateSchemaProps } from '../helpers/schema-validator-props'; -import { transformerValidationErrors } from '../helpers/transformer-validation'; - -/** - * Validates that @key, @connection directives from older graphql transformer version is not used in version 2.0 - * - * @param schema graphql schema - * @returns true if correct directives are used - */ - -export const validateDirectivesFromOlderTransformerVersionAreNotUsed = (schema: DocumentNode, props: ValidateSchemaProps): Error[] => { - if (props.graphqlTransformerVersion !== 2) { - return []; - } - - const objectTypeDefinitions = schema.definitions.filter( - (defintion) => defintion.kind === Kind.OBJECT_TYPE_DEFINITION, - ) as ObjectTypeDefinitionNode[]; - const v1DirectivesInUse = new Set(); - - objectTypeDefinitions.forEach((objectTypeDefinition) => { - const objectDirectives = objectTypeDefinition.directives?.map((directive) => directive.name.value); - const directiveFields = objectTypeDefinition.fields?.filter((objectField) => - objectField.directives?.find((directive) => directive.name.value === 'connection'), - ); - if (objectDirectives?.includes('key')) { - v1DirectivesInUse.add('@key'); - } - if (objectDirectives?.includes('versioned')) { - v1DirectivesInUse.add('@versioned'); - } - if (directiveFields && directiveFields.length > 0) { - v1DirectivesInUse.add('@connection'); - } - }); - return transformerValidationErrors(v1DirectivesInUse, props.graphqlTransformerVersion); -}; diff --git a/packages/amplify-schema-validator/tsconfig.json b/packages/amplify-schema-validator/tsconfig.json deleted file mode 100644 index 93af52659d..0000000000 --- a/packages/amplify-schema-validator/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "strict": true, - "sourceMap": true, - "esModuleInterop": true, - "declaration": true, - "outDir": "./dist", - "rootDir": "src" - }, - "include": ["src"], - "exclude": ["src/__tests__"] -} diff --git a/packages/amplify-util-mock/CHANGELOG.md b/packages/amplify-util-mock/CHANGELOG.md deleted file mode 100644 index 22ecf3a329..0000000000 --- a/packages/amplify-util-mock/CHANGELOG.md +++ /dev/null @@ -1,1661 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [6.5.5](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.5.4...amplify-category-api-util-mock@6.5.5) (2024-08-12) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.5.4](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.5.3...amplify-category-api-util-mock@6.5.4) (2024-07-25) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.5.3](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.5.2...amplify-category-api-util-mock@6.5.3) (2024-07-15) - -### Bug Fixes - -- add translation behavior to disable gen 1 patterns ([#2670](https://github.com/aws-amplify/amplify-category-api/issues/2670)) ([38d1a71](https://github.com/aws-amplify/amplify-category-api/commit/38d1a718ec2b0290f514780c6d1d5f0790ba7764)) - -## [6.5.2](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.5.1...amplify-category-api-util-mock@6.5.2) (2024-07-02) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.5.1](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.5.0...amplify-category-api-util-mock@6.5.1) (2024-07-01) - -**Note:** Version bump only for package amplify-category-api-util-mock - -# [6.5.0](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.21...amplify-category-api-util-mock@6.5.0) (2024-06-25) - -### Features - -- allow subscriptions to inherit primary model auth rules for relational fields behind a feature flag ([#2649](https://github.com/aws-amplify/amplify-category-api/issues/2649)) ([56a853a](https://github.com/aws-amplify/amplify-category-api/commit/56a853ace0026de97395cfa17ca156cf360ac5c2)) - -## [6.4.21](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.20...amplify-category-api-util-mock@6.4.21) (2024-06-06) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.20](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.19...amplify-category-api-util-mock@6.4.20) (2024-06-04) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.19](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.18...amplify-category-api-util-mock@6.4.19) (2024-05-15) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.18](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.17...amplify-category-api-util-mock@6.4.18) (2024-05-10) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.17](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.16...amplify-category-api-util-mock@6.4.17) (2024-05-01) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.16](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.15...amplify-category-api-util-mock@6.4.16) (2024-04-26) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.15](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.14...amplify-category-api-util-mock@6.4.15) (2024-04-16) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.14](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.13...amplify-category-api-util-mock@6.4.14) (2024-04-11) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.13](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.12...amplify-category-api-util-mock@6.4.13) (2024-03-28) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.12](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.11...amplify-category-api-util-mock@6.4.12) (2024-03-13) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.11](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.10...amplify-category-api-util-mock@6.4.11) (2024-02-28) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.10](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.9...amplify-category-api-util-mock@6.4.10) (2024-02-05) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.9](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.8...amplify-category-api-util-mock@6.4.9) (2024-01-30) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.8](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.7...amplify-category-api-util-mock@6.4.8) (2024-01-22) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.7](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.6...amplify-category-api-util-mock@6.4.7) (2023-12-21) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.6](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.5...amplify-category-api-util-mock@6.4.6) (2023-12-18) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.5](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.4...amplify-category-api-util-mock@6.4.5) (2023-12-14) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.4](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.3...amplify-category-api-util-mock@6.4.4) (2023-12-06) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.3](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.2...amplify-category-api-util-mock@6.4.3) (2023-11-22) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.4.2](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.1...amplify-category-api-util-mock@6.4.2) (2023-11-18) - -### Bug Fixes - -- regionalize lambda layer patching SNS topics ([#2079](https://github.com/aws-amplify/amplify-category-api/issues/2079)) ([6006c86](https://github.com/aws-amplify/amplify-category-api/commit/6006c86cd4ee624b24c184fab523fcdcdb38be63)) - -## [6.4.1](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.4.0...amplify-category-api-util-mock@6.4.1) (2023-11-16) - -**Note:** Version bump only for package amplify-category-api-util-mock - -# [6.4.0](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.3.6...amplify-category-api-util-mock@6.4.0) (2023-11-15) - -### Features - -- add refersTo directive transformer for model renaming ([#1830](https://github.com/aws-amplify/amplify-category-api/issues/1830)) ([afbd6f2](https://github.com/aws-amplify/amplify-category-api/commit/afbd6f282bc411313ce098a53a87bb8c6481aa48)) -- transformer behavior of replacing table upon gsi updates ([#2067](https://github.com/aws-amplify/amplify-category-api/issues/2067)) ([c4b7530](https://github.com/aws-amplify/amplify-category-api/commit/c4b7530e0880b34d411fc2732fa199e4a28bcea1)) - -## [6.3.6](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.3.5...amplify-category-api-util-mock@6.3.6) (2023-11-02) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.3.5](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.3.4...amplify-category-api-util-mock@6.3.5) (2023-10-21) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.3.4](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.3.3...amplify-category-api-util-mock@6.3.4) (2023-10-12) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.3.3](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.3.2...amplify-category-api-util-mock@6.3.3) (2023-10-05) - -### Bug Fixes - -- iam auth values can be passed as cdk tokens ([#1919](https://github.com/aws-amplify/amplify-category-api/issues/1919)) ([9297fa5](https://github.com/aws-amplify/amplify-category-api/commit/9297fa5cda87697645ad0c78b84c3004b32ac319)) - -## [6.3.2](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.3.1...amplify-category-api-util-mock@6.3.2) (2023-10-03) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.3.1](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.3.0...amplify-category-api-util-mock@6.3.1) (2023-10-02) - -**Note:** Version bump only for package amplify-category-api-util-mock - -# [6.3.0](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.2.4...amplify-category-api-util-mock@6.3.0) (2023-09-20) - -### Features - -- disable amplify cfn outputs for cdk apps ([0c72d18](https://github.com/aws-amplify/amplify-category-api/commit/0c72d1822f8e5ccb3e04a0a49049a459b5fb49e6)) - -## [6.2.4](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.2.3...amplify-category-api-util-mock@6.2.4) (2023-09-13) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.2.3](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.2.2...amplify-category-api-util-mock@6.2.3) (2023-09-07) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.2.2](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.2.1...amplify-category-api-util-mock@6.2.2) (2023-08-30) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.2.1](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.2.0...amplify-category-api-util-mock@6.2.1) (2023-08-28) - -**Note:** Version bump only for package amplify-category-api-util-mock - -# [6.2.0](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.13...amplify-category-api-util-mock@6.2.0) (2023-08-09) - -### Features - -- bump major version of transformer packages ([2458c84](https://github.com/aws-amplify/amplify-category-api/commit/2458c8426da5772aa669d37e11f99ee9c6c5ac2e)) - -## [6.1.13](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.12...amplify-category-api-util-mock@6.1.13) (2023-07-21) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.1.12](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.11...amplify-category-api-util-mock@6.1.12) (2023-07-17) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.1.11](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.10...amplify-category-api-util-mock@6.1.11) (2023-07-07) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.1.10](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.9...amplify-category-api-util-mock@6.1.10) (2023-07-07) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.1.9](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.8...amplify-category-api-util-mock@6.1.9) (2023-07-07) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.1.8](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.7...amplify-category-api-util-mock@6.1.8) (2023-06-29) - -### Bug Fixes - -- handling of all floating promises ([#1577](https://github.com/aws-amplify/amplify-category-api/issues/1577)) ([d5981b2](https://github.com/aws-amplify/amplify-category-api/commit/d5981b2f912d03b44e1269ca704816dd250ff501)) - -## [6.1.7](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.6...amplify-category-api-util-mock@6.1.7) (2023-06-20) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.1.6](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.5...amplify-category-api-util-mock@6.1.6) (2023-06-05) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.1.5](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.4...amplify-category-api-util-mock@6.1.5) (2023-05-23) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.1.4](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.3...amplify-category-api-util-mock@6.1.4) (2023-05-17) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.1.3](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.2...amplify-category-api-util-mock@6.1.3) (2023-04-25) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.1.2](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.1...amplify-category-api-util-mock@6.1.2) (2023-03-30) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [6.1.1](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.0...amplify-category-api-util-mock@6.1.1) (2023-03-15) - -**Note:** Version bump only for package amplify-category-api-util-mock - -# [6.1.0](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.27...amplify-category-api-util-mock@6.1.0) (2023-03-01) - -### Features - -- migrate amplify-category-api to CDK v2 ([#883](https://github.com/aws-amplify/amplify-category-api/issues/883)) ([2183f0f](https://github.com/aws-amplify/amplify-category-api/commit/2183f0f7144369cbcf6e7de3c8a2af7f5dc5b6b4)) - -# [6.1.0-beta.6](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.26...amplify-category-api-util-mock@6.1.0-beta.6) (2023-02-21) - -### Features - -- migrate amplify-category-api to CDK v2 ([#883](https://github.com/aws-amplify/amplify-category-api/issues/883)) ([2183f0f](https://github.com/aws-amplify/amplify-category-api/commit/2183f0f7144369cbcf6e7de3c8a2af7f5dc5b6b4)) - -# [6.1.0-beta.5](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.26...amplify-category-api-util-mock@6.1.0-beta.5) (2023-02-15) - -### Features - -- migrate amplify-category-api to CDK v2 ([#883](https://github.com/aws-amplify/amplify-category-api/issues/883)) ([2183f0f](https://github.com/aws-amplify/amplify-category-api/commit/2183f0f7144369cbcf6e7de3c8a2af7f5dc5b6b4)) - -# [6.1.0-beta.4](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.24...amplify-category-api-util-mock@6.1.0-beta.4) (2023-02-03) - -### Features - -- migrate amplify-category-api to CDK v2 ([#883](https://github.com/aws-amplify/amplify-category-api/issues/883)) ([2183f0f](https://github.com/aws-amplify/amplify-category-api/commit/2183f0f7144369cbcf6e7de3c8a2af7f5dc5b6b4)) - -# [6.1.0-beta.3](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.21...amplify-category-api-util-mock@6.1.0-beta.3) (2022-12-27) - -### Features - -- migrate amplify-category-api to CDK v2 ([#883](https://github.com/aws-amplify/amplify-category-api/issues/883)) ([2183f0f](https://github.com/aws-amplify/amplify-category-api/commit/2183f0f7144369cbcf6e7de3c8a2af7f5dc5b6b4)) - -# [6.1.0-beta.2](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.0-beta.0...amplify-category-api-util-mock@6.1.0-beta.2) (2022-12-12) - -**Note:** Version bump only for package amplify-category-api-util-mock - -# [6.1.0-beta.1](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.0-beta.0...amplify-category-api-util-mock@6.1.0-beta.1) (2022-11-30) - -**Note:** Version bump only for package amplify-category-api-util-mock - -# [6.1.0-beta.0](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.0-cdkv2.3...amplify-category-api-util-mock@6.1.0-beta.0) (2022-11-18) - -**Note:** Version bump only for package amplify-category-api-util-mock - -# [6.1.0-cdkv2.3](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.18...amplify-category-api-util-mock@6.1.0-cdkv2.3) (2022-11-15) - -### Features - -- migrate amplify-category-api to CDK v2 ([#883](https://github.com/aws-amplify/amplify-category-api/issues/883)) ([2183f0f](https://github.com/aws-amplify/amplify-category-api/commit/2183f0f7144369cbcf6e7de3c8a2af7f5dc5b6b4)) - -# [6.1.0-cdkv2.2](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.0-cdkv2.1...amplify-category-api-util-mock@6.1.0-cdkv2.2) (2022-11-03) - -**Note:** Version bump only for package amplify-category-api-util-mock - -# [6.1.0-cdkv2.1](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@6.1.0-cdkv2.0...amplify-category-api-util-mock@6.1.0-cdkv2.1) (2022-10-24) - -**Note:** Version bump only for package amplify-category-api-util-mock - -# [6.1.0-cdkv2.0](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.14...amplify-category-api-util-mock@6.1.0-cdkv2.0) (2022-10-24) - -### Features - -- migrate amplify-category-api to CDK v2 ([#883](https://github.com/aws-amplify/amplify-category-api/issues/883)) ([2183f0f](https://github.com/aws-amplify/amplify-category-api/commit/2183f0f7144369cbcf6e7de3c8a2af7f5dc5b6b4)) - -## [5.1.27](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.26...amplify-category-api-util-mock@5.1.27) (2023-02-27) - -### Bug Fixes - -- **test:** remove references to graphql 14 module ([ad79a84](https://github.com/aws-amplify/amplify-category-api/commit/ad79a84f0a7edeb84aa40f056c734961f445070b)) -- **test:** update cli dependencies to use the cli rc packages ([#1294](https://github.com/aws-amplify/amplify-category-api/issues/1294)) ([7b13884](https://github.com/aws-amplify/amplify-category-api/commit/7b138841bf2c26fa16465ef263af0de7ce5a4122)) - -## [5.1.26](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.25...amplify-category-api-util-mock@5.1.26) (2023-02-15) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.25](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.24...amplify-category-api-util-mock@5.1.25) (2023-02-10) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.24](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.23...amplify-category-api-util-mock@5.1.24) (2023-01-26) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.23](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.22...amplify-category-api-util-mock@5.1.23) (2023-01-12) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.22](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.21...amplify-category-api-util-mock@5.1.22) (2023-01-12) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.21](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.20...amplify-category-api-util-mock@5.1.21) (2022-12-13) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.20](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.19...amplify-category-api-util-mock@5.1.20) (2022-12-09) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.19](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.18...amplify-category-api-util-mock@5.1.19) (2022-12-03) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.18](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.17...amplify-category-api-util-mock@5.1.18) (2022-11-08) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.17](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.16...amplify-category-api-util-mock@5.1.17) (2022-11-04) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.16](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.15...amplify-category-api-util-mock@5.1.16) (2022-10-26) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.15](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.14...amplify-category-api-util-mock@5.1.15) (2022-10-24) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.14](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.13...amplify-category-api-util-mock@5.1.14) (2022-10-04) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.13](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.12...amplify-category-api-util-mock@5.1.13) (2022-09-20) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.12](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.11...amplify-category-api-util-mock@5.1.12) (2022-09-14) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.11](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.10...amplify-category-api-util-mock@5.1.11) (2022-08-23) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.10](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.9...amplify-category-api-util-mock@5.1.10) (2022-08-18) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.9](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.8...amplify-category-api-util-mock@5.1.9) (2022-08-18) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.8](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.7...amplify-category-api-util-mock@5.1.8) (2022-08-18) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.7](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.6...amplify-category-api-util-mock@5.1.7) (2022-08-16) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.6](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.5...amplify-category-api-util-mock@5.1.6) (2022-08-04) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.5](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.4...amplify-category-api-util-mock@5.1.5) (2022-07-26) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.4](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.2...amplify-category-api-util-mock@5.1.4) (2022-07-20) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.3](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.2...amplify-category-api-util-mock@5.1.3) (2022-07-14) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.2](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.1...amplify-category-api-util-mock@5.1.2) (2022-07-01) - -**Note:** Version bump only for package amplify-category-api-util-mock - -## [5.1.1](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.1.0...amplify-category-api-util-mock@5.1.1) (2022-06-23) - -**Note:** Version bump only for package amplify-category-api-util-mock - -# [5.1.0](https://github.com/aws-amplify/amplify-category-api/compare/amplify-category-api-util-mock@5.0.0...amplify-category-api-util-mock@5.1.0) (2022-06-13) - -### Features - -- add error when using an owner field as a sort key field ([#517](https://github.com/aws-amplify/amplify-category-api/issues/517)) ([201032d](https://github.com/aws-amplify/amplify-category-api/commit/201032d674a8272931fad0c75e9e146a22ed030b)) -- **graphql-auth-transformer:** [@auth](https://github.com/auth) allow more granular access rights for read ([#23](https://github.com/aws-amplify/amplify-category-api/issues/23)) ([041fb80](https://github.com/aws-amplify/amplify-category-api/commit/041fb808e380d04f2c4913cef1037c3d87e98d22)) - -# 5.0.0 (2022-06-10) - -### Bug Fixes - -- [#1056](https://github.com/aws-amplify/amplify-category-api/issues/1056), dedup environment file reading ([#2088](https://github.com/aws-amplify/amplify-category-api/issues/2088)) ([940deaa](https://github.com/aws-amplify/amplify-category-api/commit/940deaa6bbe7370e40e61946d0f1073623ba6e90)) -- [#2296](https://github.com/aws-amplify/amplify-category-api/issues/2296) [#2304](https://github.com/aws-amplify/amplify-category-api/issues/2304) [#2100](https://github.com/aws-amplify/amplify-category-api/issues/2100) ([#2439](https://github.com/aws-amplify/amplify-category-api/issues/2439)) ([82762d6](https://github.com/aws-amplify/amplify-category-api/commit/82762d6187eb2102ebd134b181622188c5632d1d)) -- [#7441](https://github.com/aws-amplify/amplify-category-api/issues/7441) - init from git prompts for credentials twice ([#7682](https://github.com/aws-amplify/amplify-category-api/issues/7682)) ([7471c5f](https://github.com/aws-amplify/amplify-category-api/commit/7471c5fcc86af0e17a967066a388f67891f93355)) -- allow mock to run if [@searchable](https://github.com/searchable) is used ([#8864](https://github.com/aws-amplify/amplify-category-api/issues/8864)) ([995d895](https://github.com/aws-amplify/amplify-category-api/commit/995d8952bb9d8f9423a5fbd4bb3fa911d3dd5ac8)) -- **amplify-appsync-simulator:** add support for AppSync template version ([#2329](https://github.com/aws-amplify/amplify-category-api/issues/2329)) ([88cd220](https://github.com/aws-amplify/amplify-category-api/commit/88cd220cbb254a018b888ee587c9c35994010377)), closes [#2134](https://github.com/aws-amplify/amplify-category-api/issues/2134) [#2211](https://github.com/aws-amplify/amplify-category-api/issues/2211) [#2299](https://github.com/aws-amplify/amplify-category-api/issues/2299) -- **amplify-appsync-simulator:** expose errors from util.validate ([#6514](https://github.com/aws-amplify/amplify-category-api/issues/6514)) ([8273037](https://github.com/aws-amplify/amplify-category-api/commit/82730371ed0292e762d45313a7fa8de062c860dd)), closes [#6068](https://github.com/aws-amplify/amplify-category-api/issues/6068) -- **amplify-appsync-simulator:** fix returning null on nonexistent fields ([#5093](https://github.com/aws-amplify/amplify-category-api/issues/5093)) ([a0439db](https://github.com/aws-amplify/amplify-category-api/commit/a0439db462e8189d7b158472f269326e2c6bdb8d)), closes [#5003](https://github.com/aws-amplify/amplify-category-api/issues/5003) -- **amplify-appsync-simulator:** support inline resolver templates ([56fdd00](https://github.com/aws-amplify/amplify-category-api/commit/56fdd0057a6ecfbd320f2a3f8b0858959bbe750e)), closes [#3834](https://github.com/aws-amplify/amplify-category-api/issues/3834) -- **amplify-category-api:** use standard json read ([#2581](https://github.com/aws-amplify/amplify-category-api/issues/2581)) ([3adc395](https://github.com/aws-amplify/amplify-category-api/commit/3adc395a5e4ccf3673735f8091db63923a46c501)) -- **amplify-category-auth:** expand [@auth](https://github.com/auth) directive to explicit set of allowed operations ([#9859](https://github.com/aws-amplify/amplify-category-api/issues/9859)) ([e44ed18](https://github.com/aws-amplify/amplify-category-api/commit/e44ed189b2c94230cbd5674606ffa488cb6c7bfe)) -- **amplify-codegen:** update dependency on amplify-codegen to latest ([#6796](https://github.com/aws-amplify/amplify-category-api/issues/6796)) ([33f4c15](https://github.com/aws-amplify/amplify-category-api/commit/33f4c156153ef6398659dd5c24a7de8b0d9b13f2)) -- amplify-mock with build folder ([#8851](https://github.com/aws-amplify/amplify-category-api/issues/8851)) ([186f21a](https://github.com/aws-amplify/amplify-category-api/commit/186f21a9d52d838d2ff9fd8bb78d19b8c57c1293)) -- **amplify-util-mock:** add support for custom resolver template name ([#2355](https://github.com/aws-amplify/amplify-category-api/issues/2355)) ([c9829e2](https://github.com/aws-amplify/amplify-category-api/commit/c9829e22aed7082798605f23aeff978ac1fa85f6)), closes [#2306](https://github.com/aws-amplify/amplify-category-api/issues/2306) -- **amplify-util-mock:** Change exposed attr to reference correct attr ([#10080](https://github.com/aws-amplify/amplify-category-api/issues/10080)) ([8314372](https://github.com/aws-amplify/amplify-category-api/commit/831437205f18b4343ac6c34f27a8b9848ce77fdd)) -- **amplify-util-mock:** correct mock env variable name to match name used at runtime ([#9272](https://github.com/aws-amplify/amplify-category-api/issues/9272)) ([0be3ace](https://github.com/aws-amplify/amplify-category-api/commit/0be3acea6026bbf7d52109b5a327966344dc9d47)) -- **amplify-util-mock:** fix inifinte reload on windows ([#4270](https://github.com/aws-amplify/amplify-category-api/issues/4270)) ([20f207e](https://github.com/aws-amplify/amplify-category-api/commit/20f207ef835e7866cae78e6a521bf11e1d62b41d)), closes [#2736](https://github.com/aws-amplify/amplify-category-api/issues/2736) -- **amplify-util-mock:** fixes [#3319](https://github.com/aws-amplify/amplify-category-api/issues/3319) java version check ([#3511](https://github.com/aws-amplify/amplify-category-api/issues/3511)) ([e237610](https://github.com/aws-amplify/amplify-category-api/commit/e237610ac7e799f2f0f752596489528812c5d9dc)), closes [aws-amplify#3317](https://github.com/aws-amplify/issues/3317) -- **amplify-util-mock:** fixes [#3510](https://github.com/aws-amplify/amplify-category-api/issues/3510) bucketname error ([#3526](https://github.com/aws-amplify/amplify-category-api/issues/3526)) ([0552f72](https://github.com/aws-amplify/amplify-category-api/commit/0552f72cf3ec301c6ff0dc7d2617cf9beb787725)) -- **amplify-util-mock:** handle unsupported data source gracefully ([#1999](https://github.com/aws-amplify/amplify-category-api/issues/1999)) ([f7cfe3e](https://github.com/aws-amplify/amplify-category-api/commit/f7cfe3e01be7a3abe45a1129419f2306924b4ebe)), closes [#1997](https://github.com/aws-amplify/amplify-category-api/issues/1997) -- **amplify-util-mock:** include custom resolver templates ([#2119](https://github.com/aws-amplify/amplify-category-api/issues/2119)) ([f7174a7](https://github.com/aws-amplify/amplify-category-api/commit/f7174a7b0bf09023e620cb4e2f4b0c7ccc154eea)), closes [#2049](https://github.com/aws-amplify/amplify-category-api/issues/2049) [#2004](https://github.com/aws-amplify/amplify-category-api/issues/2004) -- **amplify-util-mock:** loading resources from amplify-meta ([#4194](https://github.com/aws-amplify/amplify-category-api/issues/4194)) ([2c73f44](https://github.com/aws-amplify/amplify-category-api/commit/2c73f440e01ec9b471fbbf9d77658d42a5b61d3d)), closes [#4085](https://github.com/aws-amplify/amplify-category-api/issues/4085) [#4012](https://github.com/aws-amplify/amplify-category-api/issues/4012) -- **amplify-util-mock:** mock appsync key when server is running ([#6923](https://github.com/aws-amplify/amplify-category-api/issues/6923)) ([1ee817c](https://github.com/aws-amplify/amplify-category-api/commit/1ee817cf40efb73930ca17360ef3c35e04dd8c1b)) -- **amplify-util-mock:** mock to add/update DDB index ([#3960](https://github.com/aws-amplify/amplify-category-api/issues/3960)) ([132ca06](https://github.com/aws-amplify/amplify-category-api/commit/132ca06829e54677dde62798dade117aecdd9315)), closes [#2210](https://github.com/aws-amplify/amplify-category-api/issues/2210) -- **amplify-util-mock:** non-promise lambda failing ([#4203](https://github.com/aws-amplify/amplify-category-api/issues/4203)) ([e34b97f](https://github.com/aws-amplify/amplify-category-api/commit/e34b97f3750374a8bc8b693d9998fba1ec6f3ea0)) -- **amplify-util-mock:** off-by-one array reference and general refactor ([#6462](https://github.com/aws-amplify/amplify-category-api/issues/6462)) ([9acdc7e](https://github.com/aws-amplify/amplify-category-api/commit/9acdc7e5b8aebc1fcbcd43e25c0fcdd5842f2427)) -- **amplify-util-mock:** pass env vars to lambda when invoked with mock ([#3790](https://github.com/aws-amplify/amplify-category-api/issues/3790)) ([cc9c8a9](https://github.com/aws-amplify/amplify-category-api/commit/cc9c8a92a37d8e47c1acaadb5d6caab79e5f0e9e)), closes [#2453](https://github.com/aws-amplify/amplify-category-api/issues/2453) [#2690](https://github.com/aws-amplify/amplify-category-api/issues/2690) -- **amplify-util-mock:** pass transform config into generateCode ([#5259](https://github.com/aws-amplify/amplify-category-api/issues/5259)) ([7a5ec2d](https://github.com/aws-amplify/amplify-category-api/commit/7a5ec2ddc36ef2402f305eeca12964a5caac0b84)), closes [#5055](https://github.com/aws-amplify/amplify-category-api/issues/5055) -- **amplify-util-mock:** prevent resolver file overwrite in windows ([#2007](https://github.com/aws-amplify/amplify-category-api/issues/2007)) ([5b78d25](https://github.com/aws-amplify/amplify-category-api/commit/5b78d25519228085c5a0010ef90ac01cf161ccff)), closes [#2006](https://github.com/aws-amplify/amplify-category-api/issues/2006) -- **amplify-util-mock:** safe access to LambdaConfiguration ([#2294](https://github.com/aws-amplify/amplify-category-api/issues/2294)) ([0624739](https://github.com/aws-amplify/amplify-category-api/commit/0624739fd3e44a14ae20122a2c29c77169b6bc0a)) -- **amplify-util-mock:** support large response from lambda ([#2060](https://github.com/aws-amplify/amplify-category-api/issues/2060)) ([60efd28](https://github.com/aws-amplify/amplify-category-api/commit/60efd2889bf59f533efe9aed9a39886eca296d1e)) -- **amplify-util-mock:** update Java version check logic ([dc28a0e](https://github.com/aws-amplify/amplify-category-api/commit/dc28a0e770ae78a4d37138b76d3c22bae4679c6a)), closes [#5044](https://github.com/aws-amplify/amplify-category-api/issues/5044) -- **amplify-util-mock:** use lambda fn name instead of resource name ([#2357](https://github.com/aws-amplify/amplify-category-api/issues/2357)) ([4858921](https://github.com/aws-amplify/amplify-category-api/commit/48589212b329e81122aab5adfb7589dd479934b7)), closes [#2280](https://github.com/aws-amplify/amplify-category-api/issues/2280) -- **amplify-velocity-template:** support 'get' and 'set' of array vars ([#5747](https://github.com/aws-amplify/amplify-category-api/issues/5747)) ([b5f917a](https://github.com/aws-amplify/amplify-category-api/commit/b5f917a81524feb64ec7e674c6213cb47fd7794c)), closes [#5741](https://github.com/aws-amplify/amplify-category-api/issues/5741) -- Bubbling error up to Graphiql from Lambda ([#3231](https://github.com/aws-amplify/amplify-category-api/issues/3231)) ([12345da](https://github.com/aws-amplify/amplify-category-api/commit/12345da3e99990d6f9994917667c30da0b0b2f2e)) -- build break, chore: typescript, lerna update ([#2640](https://github.com/aws-amplify/amplify-category-api/issues/2640)) ([29fae36](https://github.com/aws-amplify/amplify-category-api/commit/29fae366f4cab054feefa58c7dc733002d19570c)) -- bump codegen versions ([#6871](https://github.com/aws-amplify/amplify-category-api/issues/6871)) ([e53175d](https://github.com/aws-amplify/amplify-category-api/commit/e53175d96136fba57662b1a035d3cea4a65a7601)) -- change to new docs url in some messages ([#6281](https://github.com/aws-amplify/amplify-category-api/issues/6281)) ([9d1a682](https://github.com/aws-amplify/amplify-category-api/commit/9d1a682cf5c49cc6ba87a00fbefec7fbc10af47b)) -- **cli:** fix new plugin platform codegen related issue ([#2266](https://github.com/aws-amplify/amplify-category-api/issues/2266)) ([c557182](https://github.com/aws-amplify/amplify-category-api/commit/c557182b2d423bb1c2f8832ecd49076c806b05bb)) -- e2e test failures with node env ([#2831](https://github.com/aws-amplify/amplify-category-api/issues/2831)) ([377dfa7](https://github.com/aws-amplify/amplify-category-api/commit/377dfa7c78d97408d53ba3611045d19d477c163d)) -- e2e tests, tsconfigs, [@deprecated](https://github.com/deprecated) directive for codegen: ([#3338](https://github.com/aws-amplify/amplify-category-api/issues/3338)) ([2ed7715](https://github.com/aws-amplify/amplify-category-api/commit/2ed77151dd6367ac9547f78fe600e7913a3d37b2)) -- export Typescript definitions and fix resulting type errors ([#2452](https://github.com/aws-amplify/amplify-category-api/issues/2452)) ([7de3845](https://github.com/aws-amplify/amplify-category-api/commit/7de384594d3b9cbf22cdaa85107fc8df26c141ec)), closes [#2451](https://github.com/aws-amplify/amplify-category-api/issues/2451) -- falsy values can be returned in mock now ([#3254](https://github.com/aws-amplify/amplify-category-api/issues/3254)) ([6795e78](https://github.com/aws-amplify/amplify-category-api/commit/6795e783c104004a2b2576f6903b35c1c6d2ed03)), closes [#2566](https://github.com/aws-amplify/amplify-category-api/issues/2566) -- fix messed up merge ([#6612](https://github.com/aws-amplify/amplify-category-api/issues/6612)) ([0e5d85b](https://github.com/aws-amplify/amplify-category-api/commit/0e5d85be780c800aad2322ebb2b5598187c97ae8)) -- fixed exit codes on message ([#5385](https://github.com/aws-amplify/amplify-category-api/issues/5385)) ([b5641db](https://github.com/aws-amplify/amplify-category-api/commit/b5641db760134bcf3185b798b384fbb7cc5ac382)) -- GraphQL V2 fix for codegen ([#9489](https://github.com/aws-amplify/amplify-category-api/issues/9489)) ([d8b82b9](https://github.com/aws-amplify/amplify-category-api/commit/d8b82b9bf3182efef3c57f02f76b6963bd4d2839)) -- **graphql-auth-transformer:** add list support for ownerField in subs ([#3166](https://github.com/aws-amplify/amplify-category-api/issues/3166)) ([8d68277](https://github.com/aws-amplify/amplify-category-api/commit/8d6827752ebd076424d3c76122b136eca65b02a8)) -- **graphql-auth-transformer:** early return if no obj ([#5050](https://github.com/aws-amplify/amplify-category-api/issues/5050)) ([ed1f2b3](https://github.com/aws-amplify/amplify-category-api/commit/ed1f2b364b50ab3f2b16ddac849c937b239bb499)) -- **graphql-auth-transformer:** fix key condition expression ([#9264](https://github.com/aws-amplify/amplify-category-api/issues/9264)) ([5794692](https://github.com/aws-amplify/amplify-category-api/commit/5794692a05c16f23d903321644fe37a4913861e0)) -- **graphql-auth-transformer:** remove enforce model check for field ([#2607](https://github.com/aws-amplify/amplify-category-api/issues/2607)) ([b1d6d4b](https://github.com/aws-amplify/amplify-category-api/commit/b1d6d4b1c933e552874b3bb016f611567df186d0)), closes [#2591](https://github.com/aws-amplify/amplify-category-api/issues/2591) [#2591](https://github.com/aws-amplify/amplify-category-api/issues/2591) -- **graphql-auth-transformer:** update resolver should allow if update operation is set ([#9808](https://github.com/aws-amplify/amplify-category-api/issues/9808)) ([44a9bea](https://github.com/aws-amplify/amplify-category-api/commit/44a9bea139a9a1483cfbc7db29b84938510ffdca)) -- **graphql-auth-transformer:** use read to allow subscriptions ([#4340](https://github.com/aws-amplify/amplify-category-api/issues/4340)) ([b8fc10d](https://github.com/aws-amplify/amplify-category-api/commit/b8fc10d4e55c871826f1309fe340e32d0259ac0e)), closes [#3777](https://github.com/aws-amplify/amplify-category-api/issues/3777) [#4182](https://github.com/aws-amplify/amplify-category-api/issues/4182) [#4137](https://github.com/aws-amplify/amplify-category-api/issues/4137) -- **graphql-key-transformer:** add key validation in create ([#4146](https://github.com/aws-amplify/amplify-category-api/issues/4146)) ([0e20424](https://github.com/aws-amplify/amplify-category-api/commit/0e20424f78876a1e4d8d5e0c80e6f76bcef98f84)), closes [#1756](https://github.com/aws-amplify/amplify-category-api/issues/1756) -- **graphql-model-transformer:** use modelobject key for mutation resolver creation ([#7419](https://github.com/aws-amplify/amplify-category-api/issues/7419)) ([37bc551](https://github.com/aws-amplify/amplify-category-api/commit/37bc551030d47de993f8227ee3af0ba6cd738ab2)), closes [#i7417](https://github.com/aws-amplify/amplify-category-api/issues/i7417) -- **graphql-transformer-common:** improve generated graphql pluralization ([#7258](https://github.com/aws-amplify/amplify-category-api/issues/7258)) ([fc3ad0d](https://github.com/aws-amplify/amplify-category-api/commit/fc3ad0dd5a12a7912c59ae12024f593b4cdf7f2d)), closes [#4224](https://github.com/aws-amplify/amplify-category-api/issues/4224) -- **graphql:** reset api config on mock exit ([#9385](https://github.com/aws-amplify/amplify-category-api/issues/9385)) ([d0a76f4](https://github.com/aws-amplify/amplify-category-api/commit/d0a76f4a94e847c87ab330394e70d9755244ac9d)) -- handle no mock args ([#6659](https://github.com/aws-amplify/amplify-category-api/issues/6659)) ([6b97ffa](https://github.com/aws-amplify/amplify-category-api/commit/6b97ffa34d387c6a6e1e494d8f25db33710de5fa)) -- let mock startup with gql transformer v2 ([#7433](https://github.com/aws-amplify/amplify-category-api/issues/7433)) ([f994ec2](https://github.com/aws-amplify/amplify-category-api/commit/f994ec2ab4e9d190fcbabb5d599f15f798401f76)) -- listX operations with no args where authField is used in primaryKey ([#9570](https://github.com/aws-amplify/amplify-category-api/issues/9570)) ([1496724](https://github.com/aws-amplify/amplify-category-api/commit/1496724495010f2daec8b160e35e613ca34eaa5e)) -- local mock fix ([#1982](https://github.com/aws-amplify/amplify-category-api/issues/1982)) ([8ee9029](https://github.com/aws-amplify/amplify-category-api/commit/8ee90298189f4d3140ab84fe2d40d16bcb95485f)) -- match Fn::GetAtt and Fn::Sub when initializing lambda resolvers ([#5095](https://github.com/aws-amplify/amplify-category-api/issues/5095)) ([11771f6](https://github.com/aws-amplify/amplify-category-api/commit/11771f6b5dee939abbc4baf54da5fdacf49fbf85)) -- mock bug fixes and e2e test updates ([#6626](https://github.com/aws-amplify/amplify-category-api/issues/6626)) ([af76446](https://github.com/aws-amplify/amplify-category-api/commit/af76446d18bf626ca5f91c3ad41081175c959807)) -- mock handles and prints child proc errors ([#6601](https://github.com/aws-amplify/amplify-category-api/issues/6601)) ([ce075d9](https://github.com/aws-amplify/amplify-category-api/commit/ce075d91c0b93885229ab3c6000a450c6b8cc56a)) -- mock storage trigger invocation ([#7151](https://github.com/aws-amplify/amplify-category-api/issues/7151)) (ref [#7052](https://github.com/aws-amplify/amplify-category-api/issues/7052)) ([ad2499b](https://github.com/aws-amplify/amplify-category-api/commit/ad2499b983c87de9a71165bffb85d2ee561df70d)) -- **mock:** [#2606](https://github.com/aws-amplify/amplify-category-api/issues/2606) - mocking does not start when there are LSIs in DynamoDB table ([#2667](https://github.com/aws-amplify/amplify-category-api/issues/2667)) ([914470e](https://github.com/aws-amplify/amplify-category-api/commit/914470e304391fbff756138d381754021aec6528)) -- move py test event to src/event.json ([#3851](https://github.com/aws-amplify/amplify-category-api/issues/3851)) ([1c4a0cb](https://github.com/aws-amplify/amplify-category-api/commit/1c4a0cb5022869fc6aa3c358e9a4c8935fec2b54)) -- optimize mock package imports ([#6455](https://github.com/aws-amplify/amplify-category-api/issues/6455)) ([1b64a14](https://github.com/aws-amplify/amplify-category-api/commit/1b64a147cbb3b56ce6f8465318d611de5d724685)) -- regression in graphiql-explorer build ([#3453](https://github.com/aws-amplify/amplify-category-api/issues/3453)) ([98c905e](https://github.com/aws-amplify/amplify-category-api/commit/98c905edfdf52495224d2af3a934faeaab8b310a)) -- remove functionName from transform-host lambdas ([#9491](https://github.com/aws-amplify/amplify-category-api/issues/9491)) ([959d6d8](https://github.com/aws-amplify/amplify-category-api/commit/959d6d85056c672b3281794163a7bc534340a513)) -- replaced v1 docs references with v2 docs references ([#4169](https://github.com/aws-amplify/amplify-category-api/issues/4169)) ([b578c2d](https://github.com/aws-amplify/amplify-category-api/commit/b578c2dcd10038367c653ede2f6da42e7644b41b)) -- return field value for admin roles on field resolver fixes issue [#9242](https://github.com/aws-amplify/amplify-category-api/issues/9242) ([#9275](https://github.com/aws-amplify/amplify-category-api/issues/9275)) ([dbef299](https://github.com/aws-amplify/amplify-category-api/commit/dbef2992e53b65789d1ab51a0d342a0671f9661f)) -- support AWS::URLSuffix CFN pseudo-param in mock ([#7416](https://github.com/aws-amplify/amplify-category-api/issues/7416)) ([ef5a507](https://github.com/aws-amplify/amplify-category-api/commit/ef5a507f2b9ebcc96fad2a0bfaeb2ffb35284e6a)) -- support Java numbers in appsync simulator ([#9810](https://github.com/aws-amplify/amplify-category-api/issues/9810)) ([84b61f8](https://github.com/aws-amplify/amplify-category-api/commit/84b61f8c598b473d2de5922417612ed3b3da4620)) -- test config update for e2e ([#3345](https://github.com/aws-amplify/amplify-category-api/issues/3345)) ([0d8cadc](https://github.com/aws-amplify/amplify-category-api/commit/0d8cadcafeeaaaf1f4251017769021d00b8600be)) -- timeout mock function invocation ([#5198](https://github.com/aws-amplify/amplify-category-api/issues/5198)) ([9d7af87](https://github.com/aws-amplify/amplify-category-api/commit/9d7af8731431154091f29a7f194fae2d4ee2ac71)) -- transformer version ([#9092](https://github.com/aws-amplify/amplify-category-api/issues/9092)) ([acfa82c](https://github.com/aws-amplify/amplify-category-api/commit/acfa82c9b275df0a7347ae0700a919dd8c03a4de)) -- update mock cfn parsing to support stack outputs in intrinsic fns ([#9056](https://github.com/aws-amplify/amplify-category-api/issues/9056)) ([5d60832](https://github.com/aws-amplify/amplify-category-api/commit/5d6083265cd48038d2a9d7a3c66f2df5dec12ad6)) -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-category-api/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-category-api/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) -- vtl list utils & update model test scenarios ([#8701](https://github.com/aws-amplify/amplify-category-api/issues/8701)) ([402cd9b](https://github.com/aws-amplify/amplify-category-api/commit/402cd9b12e1603403511b5933404b525bb0de176)) - -* Adding Auth on Subscriptions (#2068) ([81c630d](https://github.com/aws-amplify/amplify-category-api/commit/81c630d782a6be720e513677a34b7a7dacbdc629)), closes [#2068](https://github.com/aws-amplify/amplify-category-api/issues/2068) [#1766](https://github.com/aws-amplify/amplify-category-api/issues/1766) [#1043](https://github.com/aws-amplify/amplify-category-api/issues/1043) [#1766](https://github.com/aws-amplify/amplify-category-api/issues/1766) [#1043](https://github.com/aws-amplify/amplify-category-api/issues/1043) [#1766](https://github.com/aws-amplify/amplify-category-api/issues/1766) [#1043](https://github.com/aws-amplify/amplify-category-api/issues/1043) [#1766](https://github.com/aws-amplify/amplify-category-api/issues/1766) [#1043](https://github.com/aws-amplify/amplify-category-api/issues/1043) [#1766](https://github.com/aws-amplify/amplify-category-api/issues/1766) [#1043](https://github.com/aws-amplify/amplify-category-api/issues/1043) [#2068](https://github.com/aws-amplify/amplify-category-api/issues/2068) [#2068](https://github.com/aws-amplify/amplify-category-api/issues/2068) [#2068](https://github.com/aws-amplify/amplify-category-api/issues/2068) [#2068](https://github.com/aws-amplify/amplify-category-api/issues/2068) [#2068](https://github.com/aws-amplify/amplify-category-api/issues/2068) [#2068](https://github.com/aws-amplify/amplify-category-api/issues/2068) [#2068](https://github.com/aws-amplify/amplify-category-api/issues/2068) [#2068](https://github.com/aws-amplify/amplify-category-api/issues/2068) - -### Features - -- `[@maps](https://github.com/maps)To` directive to enable renaming models while retaining data ([#9340](https://github.com/aws-amplify/amplify-category-api/issues/9340)) ([aedf45d](https://github.com/aws-amplify/amplify-category-api/commit/aedf45d9237812d71bb8b56164efe0222ad3d534)) -- add handling of colon-delimited identity claims to query (revert) ([#10222](https://github.com/aws-amplify/amplify-category-api/issues/10222)) ([f5d7620](https://github.com/aws-amplify/amplify-category-api/commit/f5d76206929da18b44f8639afb095179de1e589f)), closes [#10189](https://github.com/aws-amplify/amplify-category-api/issues/10189) [#10213](https://github.com/aws-amplify/amplify-category-api/issues/10213) -- add support for defining IAM Permissions Boundary for Project ([#7144](https://github.com/aws-amplify/amplify-category-api/issues/7144)) ([acf031b](https://github.com/aws-amplify/amplify-category-api/commit/acf031b29d4e554d647da39ffb8293010cf1d8ad)) -- add support for multiauth in mock server ([#2109](https://github.com/aws-amplify/amplify-category-api/issues/2109)) ([fe8ee8c](https://github.com/aws-amplify/amplify-category-api/commit/fe8ee8cff355a826fa9ccddcf0fad8a200a081af)) -- add support for SMS Sandbox ([#7436](https://github.com/aws-amplify/amplify-category-api/issues/7436)) ([cdcb626](https://github.com/aws-amplify/amplify-category-api/commit/cdcb6260c11bbedef5b056fdcd730612d8bb3230)) -- **amplify-appsync-simulator:** add support for websocket subscriptions ([#3912](https://github.com/aws-amplify/amplify-category-api/issues/3912)) ([f6dac5b](https://github.com/aws-amplify/amplify-category-api/commit/f6dac5b6d55867e35b28b1c3eec9a6eeb4e4fbe3)), closes [#3008](https://github.com/aws-amplify/amplify-category-api/issues/3008) -- **amplify-category-api:** rename private packages to scope them down ([e131d06](https://github.com/aws-amplify/amplify-category-api/commit/e131d06463745d448a699e0e75eedd040c167d9d)) -- **amplify-category-api:** update descriptions to properly publish ([f685bbe](https://github.com/aws-amplify/amplify-category-api/commit/f685bbe52fd2d364e34c0ecb45c8a903555de3fe)) -- **amplify-category-api:** update yarn lock with dynamodb simulator version ([4dce641](https://github.com/aws-amplify/amplify-category-api/commit/4dce6411fbcd45c7f25db3383a0f1f21450738c0)) -- **amplify-category-function:** Refactor invoke to call runtime plugins ([#3768](https://github.com/aws-amplify/amplify-category-api/issues/3768)) ([92293fa](https://github.com/aws-amplify/amplify-category-api/commit/92293fa83190bd18aacdc2f46a22938f94b89609)) -- **amplify-codegen:** Migrate codegen ([#6730](https://github.com/aws-amplify/amplify-category-api/issues/6730)) ([9c7a69a](https://github.com/aws-amplify/amplify-category-api/commit/9c7a69a7d72e31c42572f3ebf2131c6053f96abd)) -- **amplify-util-mock:** add mock config for JAVA_OPTS ([#3503](https://github.com/aws-amplify/amplify-category-api/issues/3503)) ([24d8085](https://github.com/aws-amplify/amplify-category-api/commit/24d8085325d435284b9c49a43592e61891fd72bc)) -- **amplify-util-mock:** add support for S3 triggers in local mocking ([#2101](https://github.com/aws-amplify/amplify-category-api/issues/2101)) ([ac9a134](https://github.com/aws-amplify/amplify-category-api/commit/ac9a13469704f9c3cfa584760087e389380add3d)) -- **amplify-util-mock:** support pseudo parameters in environment variables when running `amplify mock function` ([#7804](https://github.com/aws-amplify/amplify-category-api/issues/7804)) ([3d714b7](https://github.com/aws-amplify/amplify-category-api/commit/3d714b7f522dd151f57d98d9bf48f161f7e75add)) -- **amplify-util-mock:** update cfn processing ([#3285](https://github.com/aws-amplify/amplify-category-api/issues/3285)) ([ab369b3](https://github.com/aws-amplify/amplify-category-api/commit/ab369b33a1459c9296c648748624e2219f1d1fcf)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-category-api/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-category-api/commit/0fd0dd5102177766c454c8715fa5acac32385048)) -- **cli:** new plugin platform ([#2254](https://github.com/aws-amplify/amplify-category-api/issues/2254)) ([7ec29dd](https://github.com/aws-amplify/amplify-category-api/commit/7ec29dd4f2da8c90727b36469eca646d289877b6)) -- Define IAM Permissions Boundary for Project ([#7502](https://github.com/aws-amplify/amplify-category-api/issues/7502)) (ref [#4618](https://github.com/aws-amplify/amplify-category-api/issues/4618)) ([08f7a3c](https://github.com/aws-amplify/amplify-category-api/commit/08f7a3c45b2e98535ef325eb0a97c5bc4d3008c6)), closes [#7053](https://github.com/aws-amplify/amplify-category-api/issues/7053) -- feature flag implementation ([#4891](https://github.com/aws-amplify/amplify-category-api/issues/4891)) ([6d1c632](https://github.com/aws-amplify/amplify-category-api/commit/6d1c632952a49cb56670c11c9cb0c3620d0eb332)) -- fully populate mock function environment variables ([#6551](https://github.com/aws-amplify/amplify-category-api/issues/6551)) ([dceb13a](https://github.com/aws-amplify/amplify-category-api/commit/dceb13a76a85a05940078868a3e2e1ca85656938)) -- **graphql-key-transformer:** add query automatically for named keys ([#4458](https://github.com/aws-amplify/amplify-category-api/issues/4458)) ([375282d](https://github.com/aws-amplify/amplify-category-api/commit/375282d648cf9d096d13c7b958a0dfb7bd6d60b0)) -- implement multi-auth functionality ([#1916](https://github.com/aws-amplify/amplify-category-api/issues/1916)) ([b99f58e](https://github.com/aws-amplify/amplify-category-api/commit/b99f58e4a2b85cbe9f430838554ae3c277440132)) -- Lambda layers ([#4697](https://github.com/aws-amplify/amplify-category-api/issues/4697)) ([4e97400](https://github.com/aws-amplify/amplify-category-api/commit/4e974007d95c894ab4108a2dff8d5996e7e3ce25)) -- minor tweaks to multi-runtime platform ([#3804](https://github.com/aws-amplify/amplify-category-api/issues/3804)) ([60d68d7](https://github.com/aws-amplify/amplify-category-api/commit/60d68d7e1a6e8c00cd629a38e9aefb2396a59737)) -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-category-api/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-category-api/commit/372e5346ee1f27a2e9bee25fbbdcb19417f5230f)) -- pre-deploy pull, new login mechanism and pkg cli updates ([#5941](https://github.com/aws-amplify/amplify-category-api/issues/5941)) ([7274251](https://github.com/aws-amplify/amplify-category-api/commit/7274251faadc1035acce5f44699b172e10e2e67d)) -- prep work for SMS Sandbox support ([#7302](https://github.com/aws-amplify/amplify-category-api/issues/7302)) ([d1f85d2](https://github.com/aws-amplify/amplify-category-api/commit/d1f85d2e0a9c367b71defefe6d9e00737f681ca4)) -- Separate prod and dev lambda function builds ([#6494](https://github.com/aws-amplify/amplify-category-api/issues/6494)) ([2977c6a](https://github.com/aws-amplify/amplify-category-api/commit/2977c6a886b33a38ef46f898a2adc1ffdb6d228b)) -- support for overriding pipeline function templates in transformer ([#4196](https://github.com/aws-amplify/amplify-category-api/issues/4196)) ([e1830ae](https://github.com/aws-amplify/amplify-category-api/commit/e1830aeb31fef8f035cb0a992a150d37f78e07bb)), closes [#4192](https://github.com/aws-amplify/amplify-category-api/issues/4192) -- update post-install to copy executable assets to .amplify ([#5595](https://github.com/aws-amplify/amplify-category-api/issues/5595)) ([53a23a0](https://github.com/aws-amplify/amplify-category-api/commit/53a23a07cbb9e09566c1f0f577ba2b7488bc2eae)) -- use sub:username identity claim by default when persisting behind a feature flag ([#10196](https://github.com/aws-amplify/amplify-category-api/issues/10196)) ([947aae6](https://github.com/aws-amplify/amplify-category-api/commit/947aae6e692653d06d83f3f33298da3a33d87564)) - -### Reverts - -- Revert "fix(graphql-auth-transformer): fix key condition expression (#9264)" (#9566) ([1d15762](https://github.com/aws-amplify/amplify-category-api/commit/1d1576228fd1ed131b8447f21a146b3ffeee1d2b)), closes [#9264](https://github.com/aws-amplify/amplify-category-api/issues/9264) [#9566](https://github.com/aws-amplify/amplify-category-api/issues/9566) -- Revert "chore: codegen version bump (#9512)" (#9524) ([b653441](https://github.com/aws-amplify/amplify-category-api/commit/b65344134a20785afc96abf1798af89eec93fd84)), closes [#9512](https://github.com/aws-amplify/amplify-category-api/issues/9512) [#9524](https://github.com/aws-amplify/amplify-category-api/issues/9524) -- Revert "Revert "ci: add support for e2e token rotation (#7665)" (#7759)" (#7762) ([9ea4c8e](https://github.com/aws-amplify/amplify-category-api/commit/9ea4c8e115ae62d7c348c3f0d82c89d795eebf46)), closes [#7665](https://github.com/aws-amplify/amplify-category-api/issues/7665) [#7759](https://github.com/aws-amplify/amplify-category-api/issues/7759) [#7762](https://github.com/aws-amplify/amplify-category-api/issues/7762) -- Revert "ci: add support for e2e token rotation (#7665)" (#7759) ([aadc915](https://github.com/aws-amplify/amplify-category-api/commit/aadc9155f5c25478c7f317aec77f51290c6b9cfe)), closes [#7665](https://github.com/aws-amplify/amplify-category-api/issues/7665) [#7759](https://github.com/aws-amplify/amplify-category-api/issues/7759) -- Revert "feat: add support for defining IAM Permissions Boundary for Project (#7144)" (#7453) ([08704f0](https://github.com/aws-amplify/amplify-category-api/commit/08704f0271f6f5d0e0e98ad7002f4b35c3890924)), closes [#7144](https://github.com/aws-amplify/amplify-category-api/issues/7144) [#7453](https://github.com/aws-amplify/amplify-category-api/issues/7453) -- Revert "fix(graphql-auth-transformer): add list support for ownerField in subs (#3166)" (#3572) ([d693e6b](https://github.com/aws-amplify/amplify-category-api/commit/d693e6b2819a5d20188fa9f68d94ef955e474bd3)), closes [#3166](https://github.com/aws-amplify/amplify-category-api/issues/3166) [#3572](https://github.com/aws-amplify/amplify-category-api/issues/3572) -- add query automatically for named keys ([#4513](https://github.com/aws-amplify/amplify-category-api/issues/4513)) ([50c1120](https://github.com/aws-amplify/amplify-category-api/commit/50c112050645b8fd5011a1e6863d30f58e0c55cb)) - -### BREAKING CHANGES - -- If an owner is used in the auth directive it will either be a requirement if it's - the only rule or an optional input if used with other rules -- If an owner is included in the auth directive it will either be a requirement if - it's the only rule or an optional input if used with other rules -- the subscription operations will require an argument if owner is the only auth rule -- Subscriptions will require an argument if an owner is only rule set - If owner & - group rules are owner will be an optional arg - -## [4.4.4](https://github.com/aws-amplify/amplify-category-api/compare/amplify-util-mock@4.4.3...amplify-util-mock@4.4.4) (2022-06-10) - -**Note:** Version bump only for package amplify-util-mock - -## [4.4.3](https://github.com/aws-amplify/amplify-category-api/compare/amplify-util-mock@4.4.0...amplify-util-mock@4.4.3) (2022-06-07) - -**Note:** Version bump only for package amplify-util-mock - -## [4.4.2](https://github.com/aws-amplify/amplify-category-api/compare/amplify-util-mock@4.4.0...amplify-util-mock@4.4.2) (2022-05-31) - -**Note:** Version bump only for package amplify-util-mock - -## [4.4.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.4.0...amplify-util-mock@4.4.1) (2022-05-02) - -**Note:** Version bump only for package amplify-util-mock - -# [4.4.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.3.16...amplify-util-mock@4.4.0) (2022-04-29) - -### Features - -- add handling of colon-delimited identity claims to query (revert) ([#10222](https://github.com/aws-amplify/amplify-cli/issues/10222)) ([f5d7620](https://github.com/aws-amplify/amplify-cli/commit/f5d76206929da18b44f8639afb095179de1e589f)), closes [#10189](https://github.com/aws-amplify/amplify-cli/issues/10189) [#10213](https://github.com/aws-amplify/amplify-cli/issues/10213) -- use sub:username identity claim by default when persisting behind a feature flag ([#10196](https://github.com/aws-amplify/amplify-cli/issues/10196)) ([947aae6](https://github.com/aws-amplify/amplify-cli/commit/947aae6e692653d06d83f3f33298da3a33d87564)) - -## [4.3.16](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.3.15...amplify-util-mock@4.3.16) (2022-04-27) - -## 8.0.3 (2022-04-25) - -### Bug Fixes - -- **amplify-util-mock:** Change exposed attr to reference correct attr ([#10080](https://github.com/aws-amplify/amplify-cli/issues/10080)) ([8314372](https://github.com/aws-amplify/amplify-cli/commit/831437205f18b4343ac6c34f27a8b9848ce77fdd)) - -## [4.3.15](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.3.14...amplify-util-mock@4.3.15) (2022-04-18) - -**Note:** Version bump only for package amplify-util-mock - -## [4.3.14](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.3.13...amplify-util-mock@4.3.14) (2022-04-11) - -**Note:** Version bump only for package amplify-util-mock - -## [4.3.13](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.3.12...amplify-util-mock@4.3.13) (2022-04-07) - -**Note:** Version bump only for package amplify-util-mock - -## [4.3.12](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.3.11...amplify-util-mock@4.3.12) (2022-03-23) - -**Note:** Version bump only for package amplify-util-mock - -## [4.3.11](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.3.10...amplify-util-mock@4.3.11) (2022-03-17) - -## 7.6.25 (2022-03-16) - -### Bug Fixes - -- **amplify-category-auth:** expand [@auth](https://github.com/auth) directive to explicit set of allowed operations ([#9859](https://github.com/aws-amplify/amplify-cli/issues/9859)) ([e44ed18](https://github.com/aws-amplify/amplify-cli/commit/e44ed189b2c94230cbd5674606ffa488cb6c7bfe)) - -## [4.3.10](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.3.9...amplify-util-mock@4.3.10) (2022-03-14) - -**Note:** Version bump only for package amplify-util-mock - -## [4.3.9](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.3.8...amplify-util-mock@4.3.9) (2022-03-07) - -### Bug Fixes - -- support Java numbers in appsync simulator ([#9810](https://github.com/aws-amplify/amplify-cli/issues/9810)) ([84b61f8](https://github.com/aws-amplify/amplify-cli/commit/84b61f8c598b473d2de5922417612ed3b3da4620)) - -## [4.3.8](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.3.7...amplify-util-mock@4.3.8) (2022-02-25) - -## 7.6.22 (2022-02-24) - -### Bug Fixes - -- **graphql-auth-transformer:** update resolver should allow if update operation is set ([#9808](https://github.com/aws-amplify/amplify-cli/issues/9808)) ([44a9bea](https://github.com/aws-amplify/amplify-cli/commit/44a9bea139a9a1483cfbc7db29b84938510ffdca)) - -## [4.3.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.3.6...amplify-util-mock@4.3.7) (2022-02-18) - -**Note:** Version bump only for package amplify-util-mock - -## [4.3.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.3.5...amplify-util-mock@4.3.6) (2022-02-15) - -**Note:** Version bump only for package amplify-util-mock - -## [4.3.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.3.1...amplify-util-mock@4.3.5) (2022-02-10) - -## 7.6.19 (2022-02-08) - -**Note:** Version bump only for package amplify-util-mock - -## [4.3.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.3.0...amplify-util-mock@4.3.1) (2022-02-03) - -**Note:** Version bump only for package amplify-util-mock - -# [4.3.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.30...amplify-util-mock@4.3.0) (2022-01-31) - -## 7.6.14 (2022-01-28) - -### Features - -- `[@maps](https://github.com/maps)To` directive to enable renaming models while retaining data ([#9340](https://github.com/aws-amplify/amplify-cli/issues/9340)) ([aedf45d](https://github.com/aws-amplify/amplify-cli/commit/aedf45d9237812d71bb8b56164efe0222ad3d534)) - -## [4.2.30](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.29...amplify-util-mock@4.2.30) (2022-01-27) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.29](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.28...amplify-util-mock@4.2.29) (2022-01-23) - -### Bug Fixes - -- listX operations with no args where authField is used in primaryKey ([#9570](https://github.com/aws-amplify/amplify-cli/issues/9570)) ([1496724](https://github.com/aws-amplify/amplify-cli/commit/1496724495010f2daec8b160e35e613ca34eaa5e)) - -## [4.2.28](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.27...amplify-util-mock@4.2.28) (2022-01-20) - -## 7.6.11 (2022-01-20) - -### Reverts - -- Revert "fix(graphql-auth-transformer): fix key condition expression (#9264)" (#9566) ([1d15762](https://github.com/aws-amplify/amplify-cli/commit/1d1576228fd1ed131b8447f21a146b3ffeee1d2b)), closes [#9264](https://github.com/aws-amplify/amplify-cli/issues/9264) [#9566](https://github.com/aws-amplify/amplify-cli/issues/9566) - -## [4.2.27](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.26...amplify-util-mock@4.2.27) (2022-01-20) - -### Bug Fixes - -- remove functionName from transform-host lambdas ([#9491](https://github.com/aws-amplify/amplify-cli/issues/9491)) ([959d6d8](https://github.com/aws-amplify/amplify-cli/commit/959d6d85056c672b3281794163a7bc534340a513)) - -### Reverts - -- Revert "chore: codegen version bump (#9512)" (#9524) ([b653441](https://github.com/aws-amplify/amplify-cli/commit/b65344134a20785afc96abf1798af89eec93fd84)), closes [#9512](https://github.com/aws-amplify/amplify-cli/issues/9512) [#9524](https://github.com/aws-amplify/amplify-cli/issues/9524) - -## [4.2.26](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.25...amplify-util-mock@4.2.26) (2022-01-13) - -### Bug Fixes - -- **amplify-util-mock:** correct mock env variable name to match name used at runtime ([#9272](https://github.com/aws-amplify/amplify-cli/issues/9272)) ([0be3ace](https://github.com/aws-amplify/amplify-cli/commit/0be3acea6026bbf7d52109b5a327966344dc9d47)) -- GraphQL V2 fix for codegen ([#9489](https://github.com/aws-amplify/amplify-cli/issues/9489)) ([d8b82b9](https://github.com/aws-amplify/amplify-cli/commit/d8b82b9bf3182efef3c57f02f76b6963bd4d2839)) - -## [4.2.25](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.23...amplify-util-mock@4.2.25) (2022-01-10) - -## 7.6.7 (2022-01-10) - -### Bug Fixes - -- **graphql:** reset api config on mock exit ([#9385](https://github.com/aws-amplify/amplify-cli/issues/9385)) ([d0a76f4](https://github.com/aws-amplify/amplify-cli/commit/d0a76f4a94e847c87ab330394e70d9755244ac9d)) -- return field value for admin roles on field resolver fixes issue [#9242](https://github.com/aws-amplify/amplify-cli/issues/9242) ([#9275](https://github.com/aws-amplify/amplify-cli/issues/9275)) ([dbef299](https://github.com/aws-amplify/amplify-cli/commit/dbef2992e53b65789d1ab51a0d342a0671f9661f)) - -## [4.2.23](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.22...amplify-util-mock@4.2.23) (2021-12-21) - -### Bug Fixes - -- **graphql-auth-transformer:** fix key condition expression ([#9264](https://github.com/aws-amplify/amplify-cli/issues/9264)) ([5794692](https://github.com/aws-amplify/amplify-cli/commit/5794692a05c16f23d903321644fe37a4913861e0)) - -## [4.2.22](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.21...amplify-util-mock@4.2.22) (2021-12-17) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.21](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.20...amplify-util-mock@4.2.21) (2021-12-09) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.20](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.19...amplify-util-mock@4.2.20) (2021-12-03) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.19](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.18...amplify-util-mock@4.2.19) (2021-12-02) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.18](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.17...amplify-util-mock@4.2.18) (2021-12-02) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.17](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.16...amplify-util-mock@4.2.17) (2021-12-02) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.16](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.15...amplify-util-mock@4.2.16) (2021-12-01) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.15](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.14...amplify-util-mock@4.2.15) (2021-11-29) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.14](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.13...amplify-util-mock@4.2.14) (2021-11-26) - -## 7.5.3 (2021-11-26) - -### Bug Fixes - -- transformer version ([#9092](https://github.com/aws-amplify/amplify-cli/issues/9092)) ([acfa82c](https://github.com/aws-amplify/amplify-cli/commit/acfa82c9b275df0a7347ae0700a919dd8c03a4de)) - -## [4.2.13](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.12...amplify-util-mock@4.2.13) (2021-11-25) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.12](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.11...amplify-util-mock@4.2.12) (2021-11-24) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.11](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.10...amplify-util-mock@4.2.11) (2021-11-23) - -# 7.5.0 (2021-11-23) - -### Bug Fixes - -- update mock cfn parsing to support stack outputs in intrinsic fns ([#9056](https://github.com/aws-amplify/amplify-cli/issues/9056)) ([5d60832](https://github.com/aws-amplify/amplify-cli/commit/5d6083265cd48038d2a9d7a3c66f2df5dec12ad6)) - -## [4.2.10](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.9...amplify-util-mock@4.2.10) (2021-11-21) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.9](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.8...amplify-util-mock@4.2.9) (2021-11-20) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.8](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.6...amplify-util-mock@4.2.8) (2021-11-19) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.6...amplify-util-mock@4.2.7) (2021-11-19) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.5...amplify-util-mock@4.2.6) (2021-11-18) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.4...amplify-util-mock@4.2.5) (2021-11-17) - -### Bug Fixes - -- allow mock to run if [@searchable](https://github.com/searchable) is used ([#8864](https://github.com/aws-amplify/amplify-cli/issues/8864)) ([995d895](https://github.com/aws-amplify/amplify-cli/commit/995d8952bb9d8f9423a5fbd4bb3fa911d3dd5ac8)) - -## [4.2.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.3...amplify-util-mock@4.2.4) (2021-11-16) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.2...amplify-util-mock@4.2.3) (2021-11-16) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@4.2.1...amplify-util-mock@4.2.2) (2021-11-15) - -**Note:** Version bump only for package amplify-util-mock - -## [4.2.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.34.12...amplify-util-mock@4.2.1) (2021-11-15) - -### Bug Fixes - -- amplify-mock with build folder ([#8851](https://github.com/aws-amplify/amplify-cli/issues/8851)) ([186f21a](https://github.com/aws-amplify/amplify-cli/commit/186f21a9d52d838d2ff9fd8bb78d19b8c57c1293)) - -# [4.0.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.34.12...amplify-util-mock@4.0.0) (2021-11-13) - -**Note:** Version bump only for package amplify-util-mock - -## [3.34.12](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.34.11...amplify-util-mock@3.34.12) (2021-11-11) - -### Bug Fixes - -- vtl list utils & update model test scenarios ([#8701](https://github.com/aws-amplify/amplify-cli/issues/8701)) ([402cd9b](https://github.com/aws-amplify/amplify-cli/commit/402cd9b12e1603403511b5933404b525bb0de176)) - -## [3.34.11](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.34.10...amplify-util-mock@3.34.11) (2021-10-13) - -**Note:** Version bump only for package amplify-util-mock - -## [3.34.10](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.34.9...amplify-util-mock@3.34.10) (2021-10-10) - -**Note:** Version bump only for package amplify-util-mock - -## [3.34.9](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.34.8...amplify-util-mock@3.34.9) (2021-10-08) - -**Note:** Version bump only for package amplify-util-mock - -## [3.34.8](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.34.7...amplify-util-mock@3.34.8) (2021-10-06) - -**Note:** Version bump only for package amplify-util-mock - -## [3.34.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.34.6...amplify-util-mock@3.34.7) (2021-10-01) - -**Note:** Version bump only for package amplify-util-mock - -## [3.34.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.34.5...amplify-util-mock@3.34.6) (2021-09-27) - -**Note:** Version bump only for package amplify-util-mock - -## [3.34.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.34.4...amplify-util-mock@3.34.5) (2021-09-18) - -**Note:** Version bump only for package amplify-util-mock - -## [3.34.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.34.3...amplify-util-mock@3.34.4) (2021-09-14) - -**Note:** Version bump only for package amplify-util-mock - -## [3.34.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.34.2...amplify-util-mock@3.34.3) (2021-09-09) - -**Note:** Version bump only for package amplify-util-mock - -## [3.34.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.34.1...amplify-util-mock@3.34.2) (2021-09-02) - -**Note:** Version bump only for package amplify-util-mock - -## [3.34.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.34.0...amplify-util-mock@3.34.1) (2021-08-24) - -**Note:** Version bump only for package amplify-util-mock - -# [3.34.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.33.7...amplify-util-mock@3.34.0) (2021-08-06) - -### Features - -- **amplify-util-mock:** support pseudo parameters in environment variables when running `amplify mock function` ([#7804](https://github.com/aws-amplify/amplify-cli/issues/7804)) ([3d714b7](https://github.com/aws-amplify/amplify-cli/commit/3d714b7f522dd151f57d98d9bf48f161f7e75add)) - -## [3.33.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.33.6...amplify-util-mock@3.33.7) (2021-07-30) - -**Note:** Version bump only for package amplify-util-mock - -## [3.33.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.33.5...amplify-util-mock@3.33.6) (2021-07-27) - -### Reverts - -- Revert "Revert "ci: add support for e2e token rotation (#7665)" (#7759)" (#7762) ([9ea4c8e](https://github.com/aws-amplify/amplify-cli/commit/9ea4c8e115ae62d7c348c3f0d82c89d795eebf46)), closes [#7665](https://github.com/aws-amplify/amplify-cli/issues/7665) [#7759](https://github.com/aws-amplify/amplify-cli/issues/7759) [#7762](https://github.com/aws-amplify/amplify-cli/issues/7762) -- Revert "ci: add support for e2e token rotation (#7665)" (#7759) ([aadc915](https://github.com/aws-amplify/amplify-cli/commit/aadc9155f5c25478c7f317aec77f51290c6b9cfe)), closes [#7665](https://github.com/aws-amplify/amplify-cli/issues/7665) [#7759](https://github.com/aws-amplify/amplify-cli/issues/7759) - -## [3.33.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.33.4...amplify-util-mock@3.33.5) (2021-07-16) - -### Bug Fixes - -- [#7441](https://github.com/aws-amplify/amplify-cli/issues/7441) - init from git prompts for credentials twice ([#7682](https://github.com/aws-amplify/amplify-cli/issues/7682)) ([7471c5f](https://github.com/aws-amplify/amplify-cli/commit/7471c5fcc86af0e17a967066a388f67891f93355)) - -## [3.33.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.33.3...amplify-util-mock@3.33.4) (2021-07-12) - -**Note:** Version bump only for package amplify-util-mock - -## [3.33.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.33.2...amplify-util-mock@3.33.3) (2021-06-30) - -**Note:** Version bump only for package amplify-util-mock - -## [3.33.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.33.1...amplify-util-mock@3.33.2) (2021-06-24) - -### Bug Fixes - -- let mock startup with gql transformer v2 ([#7433](https://github.com/aws-amplify/amplify-cli/issues/7433)) ([f994ec2](https://github.com/aws-amplify/amplify-cli/commit/f994ec2ab4e9d190fcbabb5d599f15f798401f76)) -- support AWS::URLSuffix CFN pseudo-param in mock ([#7416](https://github.com/aws-amplify/amplify-cli/issues/7416)) ([ef5a507](https://github.com/aws-amplify/amplify-cli/commit/ef5a507f2b9ebcc96fad2a0bfaeb2ffb35284e6a)) -- **graphql-transformer-common:** improve generated graphql pluralization ([#7258](https://github.com/aws-amplify/amplify-cli/issues/7258)) ([fc3ad0d](https://github.com/aws-amplify/amplify-cli/commit/fc3ad0dd5a12a7912c59ae12024f593b4cdf7f2d)), closes [#4224](https://github.com/aws-amplify/amplify-cli/issues/4224) - -## [3.33.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.33.0...amplify-util-mock@3.33.1) (2021-06-19) - -**Note:** Version bump only for package amplify-util-mock - -# [3.33.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.32.0...amplify-util-mock@3.33.0) (2021-06-15) - -### Features - -- add support for defining IAM Permissions Boundary for Project ([#7144](https://github.com/aws-amplify/amplify-cli/issues/7144)) ([acf031b](https://github.com/aws-amplify/amplify-cli/commit/acf031b29d4e554d647da39ffb8293010cf1d8ad)) -- Define IAM Permissions Boundary for Project ([#7502](https://github.com/aws-amplify/amplify-cli/issues/7502)) (ref [#4618](https://github.com/aws-amplify/amplify-cli/issues/4618)) ([08f7a3c](https://github.com/aws-amplify/amplify-cli/commit/08f7a3c45b2e98535ef325eb0a97c5bc4d3008c6)), closes [#7053](https://github.com/aws-amplify/amplify-cli/issues/7053) - -### Reverts - -- Revert "feat: add support for defining IAM Permissions Boundary for Project (#7144)" (#7453) ([08704f0](https://github.com/aws-amplify/amplify-cli/commit/08704f0271f6f5d0e0e98ad7002f4b35c3890924)), closes [#7144](https://github.com/aws-amplify/amplify-cli/issues/7144) [#7453](https://github.com/aws-amplify/amplify-cli/issues/7453) - -# [3.32.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.31.4...amplify-util-mock@3.32.0) (2021-06-02) - -# 4.52.0 (2021-06-01) - -### Features - -- add support for SMS Sandbox ([#7436](https://github.com/aws-amplify/amplify-cli/issues/7436)) ([cdcb626](https://github.com/aws-amplify/amplify-cli/commit/cdcb6260c11bbedef5b056fdcd730612d8bb3230)) - -## [3.31.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.31.3...amplify-util-mock@3.31.4) (2021-05-29) - -## 4.51.4 (2021-05-28) - -### Bug Fixes - -- **graphql-model-transformer:** use modelobject key for mutation resolver creation ([#7419](https://github.com/aws-amplify/amplify-cli/issues/7419)) ([37bc551](https://github.com/aws-amplify/amplify-cli/commit/37bc551030d47de993f8227ee3af0ba6cd738ab2)), closes [#i7417](https://github.com/aws-amplify/amplify-cli/issues/i7417) - -## [3.31.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.31.2...amplify-util-mock@3.31.3) (2021-05-26) - -**Note:** Version bump only for package amplify-util-mock - -## [3.31.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.31.1...amplify-util-mock@3.31.2) (2021-05-22) - -**Note:** Version bump only for package amplify-util-mock - -## [3.31.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.31.0...amplify-util-mock@3.31.1) (2021-05-18) - -**Note:** Version bump only for package amplify-util-mock - -# [3.31.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.30.6...amplify-util-mock@3.31.0) (2021-05-14) - -# 4.51.0 (2021-05-13) - -### Features - -- prep work for SMS Sandbox support ([#7302](https://github.com/aws-amplify/amplify-cli/issues/7302)) ([d1f85d2](https://github.com/aws-amplify/amplify-cli/commit/d1f85d2e0a9c367b71defefe6d9e00737f681ca4)) - -## [3.30.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.30.4...amplify-util-mock@3.30.6) (2021-05-03) - -## 4.50.1 (2021-05-03) - -**Note:** Version bump only for package amplify-util-mock - -## [3.30.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.30.4...amplify-util-mock@3.30.5) (2021-05-03) - -**Note:** Version bump only for package amplify-util-mock - -## [3.30.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.30.3...amplify-util-mock@3.30.4) (2021-04-27) - -### Bug Fixes - -- mock storage trigger invocation ([#7151](https://github.com/aws-amplify/amplify-cli/issues/7151)) (ref [#7052](https://github.com/aws-amplify/amplify-cli/issues/7052)) ([ad2499b](https://github.com/aws-amplify/amplify-cli/commit/ad2499b983c87de9a71165bffb85d2ee561df70d)) - -## [3.30.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.30.2...amplify-util-mock@3.30.3) (2021-04-19) - -**Note:** Version bump only for package amplify-util-mock - -## [3.30.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.30.1...amplify-util-mock@3.30.2) (2021-04-14) - -**Note:** Version bump only for package amplify-util-mock - -## [3.30.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.29.4...amplify-util-mock@3.30.1) (2021-04-09) - -### Bug Fixes - -- **amplify-util-mock:** mock appsync key when server is running ([#6923](https://github.com/aws-amplify/amplify-cli/issues/6923)) ([1ee817c](https://github.com/aws-amplify/amplify-cli/commit/1ee817cf40efb73930ca17360ef3c35e04dd8c1b)) - -## [3.29.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.29.3...amplify-util-mock@3.29.4) (2021-03-24) - -**Note:** Version bump only for package amplify-util-mock - -## [3.29.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.29.2...amplify-util-mock@3.29.3) (2021-03-23) - -**Note:** Version bump only for package amplify-util-mock - -## [3.29.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.29.1...amplify-util-mock@3.29.2) (2021-03-12) - -## 4.45.2 (2021-03-12) - -### Bug Fixes - -- bump codegen versions ([#6871](https://github.com/aws-amplify/amplify-cli/issues/6871)) ([e53175d](https://github.com/aws-amplify/amplify-cli/commit/e53175d96136fba57662b1a035d3cea4a65a7601)) - -## [3.29.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.29.0...amplify-util-mock@3.29.1) (2021-03-11) - -**Note:** Version bump only for package amplify-util-mock - -# [3.29.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.28.2...amplify-util-mock@3.29.0) (2021-03-05) - -### Bug Fixes - -- **amplify-codegen:** update dependency on amplify-codegen to latest ([#6796](https://github.com/aws-amplify/amplify-cli/issues/6796)) ([33f4c15](https://github.com/aws-amplify/amplify-cli/commit/33f4c156153ef6398659dd5c24a7de8b0d9b13f2)) - -### Features - -- **amplify-codegen:** Migrate codegen ([#6730](https://github.com/aws-amplify/amplify-cli/issues/6730)) ([9c7a69a](https://github.com/aws-amplify/amplify-cli/commit/9c7a69a7d72e31c42572f3ebf2131c6053f96abd)) - -## [3.28.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.28.1...amplify-util-mock@3.28.2) (2021-02-26) - -## 4.44.2 (2021-02-26) - -**Note:** Version bump only for package amplify-util-mock - -## [3.28.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.28.0...amplify-util-mock@3.28.1) (2021-02-24) - -### Bug Fixes - -- handle no mock args ([#6659](https://github.com/aws-amplify/amplify-cli/issues/6659)) ([6b97ffa](https://github.com/aws-amplify/amplify-cli/commit/6b97ffa34d387c6a6e1e494d8f25db33710de5fa)) - -# [3.28.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.27.9...amplify-util-mock@3.28.0) (2021-02-17) - -### Bug Fixes - -- fix messed up merge ([#6612](https://github.com/aws-amplify/amplify-cli/issues/6612)) ([0e5d85b](https://github.com/aws-amplify/amplify-cli/commit/0e5d85be780c800aad2322ebb2b5598187c97ae8)) -- mock bug fixes and e2e test updates ([#6626](https://github.com/aws-amplify/amplify-cli/issues/6626)) ([af76446](https://github.com/aws-amplify/amplify-cli/commit/af76446d18bf626ca5f91c3ad41081175c959807)) -- mock handles and prints child proc errors ([#6601](https://github.com/aws-amplify/amplify-cli/issues/6601)) ([ce075d9](https://github.com/aws-amplify/amplify-cli/commit/ce075d91c0b93885229ab3c6000a450c6b8cc56a)) - -### Features - -- fully populate mock function environment variables ([#6551](https://github.com/aws-amplify/amplify-cli/issues/6551)) ([dceb13a](https://github.com/aws-amplify/amplify-cli/commit/dceb13a76a85a05940078868a3e2e1ca85656938)) -- Separate prod and dev lambda function builds ([#6494](https://github.com/aws-amplify/amplify-cli/issues/6494)) ([2977c6a](https://github.com/aws-amplify/amplify-cli/commit/2977c6a886b33a38ef46f898a2adc1ffdb6d228b)) - -## [3.27.9](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.27.8...amplify-util-mock@3.27.9) (2021-02-11) - -### Bug Fixes - -- **amplify-appsync-simulator:** expose errors from util.validate ([#6514](https://github.com/aws-amplify/amplify-cli/issues/6514)) ([8273037](https://github.com/aws-amplify/amplify-cli/commit/82730371ed0292e762d45313a7fa8de062c860dd)), closes [#6068](https://github.com/aws-amplify/amplify-cli/issues/6068) - -## [3.27.8](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.27.7...amplify-util-mock@3.27.8) (2021-02-10) - -### Bug Fixes - -- **amplify-util-mock:** off-by-one array reference and general refactor ([#6462](https://github.com/aws-amplify/amplify-cli/issues/6462)) ([9acdc7e](https://github.com/aws-amplify/amplify-cli/commit/9acdc7e5b8aebc1fcbcd43e25c0fcdd5842f2427)) -- **amplify-velocity-template:** support 'get' and 'set' of array vars ([#5747](https://github.com/aws-amplify/amplify-cli/issues/5747)) ([b5f917a](https://github.com/aws-amplify/amplify-cli/commit/b5f917a81524feb64ec7e674c6213cb47fd7794c)), closes [#5741](https://github.com/aws-amplify/amplify-cli/issues/5741) -- optimize mock package imports ([#6455](https://github.com/aws-amplify/amplify-cli/issues/6455)) ([1b64a14](https://github.com/aws-amplify/amplify-cli/commit/1b64a147cbb3b56ce6f8465318d611de5d724685)) - -## [3.27.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.27.6...amplify-util-mock@3.27.7) (2021-01-08) - -### Bug Fixes - -- change to new docs url in some messages ([#6281](https://github.com/aws-amplify/amplify-cli/issues/6281)) ([9d1a682](https://github.com/aws-amplify/amplify-cli/commit/9d1a682cf5c49cc6ba87a00fbefec7fbc10af47b)) - -## [3.27.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.27.5...amplify-util-mock@3.27.6) (2020-12-31) - -**Note:** Version bump only for package amplify-util-mock - -## [3.27.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.27.4...amplify-util-mock@3.27.5) (2020-12-21) - -**Note:** Version bump only for package amplify-util-mock - -## [3.27.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.27.3...amplify-util-mock@3.27.4) (2020-12-16) - -**Note:** Version bump only for package amplify-util-mock - -## [3.27.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.27.2...amplify-util-mock@3.27.3) (2020-12-11) - -**Note:** Version bump only for package amplify-util-mock - -## [3.27.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.27.1...amplify-util-mock@3.27.2) (2020-12-07) - -**Note:** Version bump only for package amplify-util-mock - -## [3.27.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.27.0...amplify-util-mock@3.27.1) (2020-12-03) - -**Note:** Version bump only for package amplify-util-mock - -# [3.27.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.26.3...amplify-util-mock@3.27.0) (2020-11-30) - -### Features - -- pre-deploy pull, new login mechanism and pkg cli updates ([#5941](https://github.com/aws-amplify/amplify-cli/issues/5941)) ([7274251](https://github.com/aws-amplify/amplify-cli/commit/7274251faadc1035acce5f44699b172e10e2e67d)) - -## [3.26.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.26.2...amplify-util-mock@3.26.3) (2020-11-27) - -**Note:** Version bump only for package amplify-util-mock - -## [3.26.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.26.1...amplify-util-mock@3.26.2) (2020-11-26) - -**Note:** Version bump only for package amplify-util-mock - -## [3.26.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.25.3...amplify-util-mock@3.26.1) (2020-11-22) - -**Note:** Version bump only for package amplify-util-mock - -# 3.26.0 (2020-11-22) - -### Bug Fixes - -- fixed exit codes on message ([#5385](https://github.com/aws-amplify/amplify-cli/issues/5385)) ([b5641db](https://github.com/aws-amplify/amplify-cli/commit/b5641db760134bcf3185b798b384fbb7cc5ac382)) -- timeout mock function invocation ([#5198](https://github.com/aws-amplify/amplify-cli/issues/5198)) ([9d7af87](https://github.com/aws-amplify/amplify-cli/commit/9d7af8731431154091f29a7f194fae2d4ee2ac71)) -- **amplify-appsync-simulator:** fix returning null on nonexistent fields ([#5093](https://github.com/aws-amplify/amplify-cli/issues/5093)) ([a0439db](https://github.com/aws-amplify/amplify-cli/commit/a0439db462e8189d7b158472f269326e2c6bdb8d)), closes [#5003](https://github.com/aws-amplify/amplify-cli/issues/5003) -- **amplify-appsync-simulator:** support inline resolver templates ([56fdd00](https://github.com/aws-amplify/amplify-cli/commit/56fdd0057a6ecfbd320f2a3f8b0858959bbe750e)), closes [#3834](https://github.com/aws-amplify/amplify-cli/issues/3834) -- **amplify-category-api:** use standard json read ([#2581](https://github.com/aws-amplify/amplify-cli/issues/2581)) ([3adc395](https://github.com/aws-amplify/amplify-cli/commit/3adc395a5e4ccf3673735f8091db63923a46c501)) -- **amplify-util-mock:** add support for custom resolver template name ([#2355](https://github.com/aws-amplify/amplify-cli/issues/2355)) ([c9829e2](https://github.com/aws-amplify/amplify-cli/commit/c9829e22aed7082798605f23aeff978ac1fa85f6)), closes [#2306](https://github.com/aws-amplify/amplify-cli/issues/2306) -- **amplify-util-mock:** fixes [#3510](https://github.com/aws-amplify/amplify-cli/issues/3510) bucketname error ([#3526](https://github.com/aws-amplify/amplify-cli/issues/3526)) ([0552f72](https://github.com/aws-amplify/amplify-cli/commit/0552f72cf3ec301c6ff0dc7d2617cf9beb787725)) -- **amplify-util-mock:** pass transform config into generateCode ([#5259](https://github.com/aws-amplify/amplify-cli/issues/5259)) ([7a5ec2d](https://github.com/aws-amplify/amplify-cli/commit/7a5ec2ddc36ef2402f305eeca12964a5caac0b84)), closes [#5055](https://github.com/aws-amplify/amplify-cli/issues/5055) -- match Fn::GetAtt and Fn::Sub when initializing lambda resolvers ([#5095](https://github.com/aws-amplify/amplify-cli/issues/5095)) ([11771f6](https://github.com/aws-amplify/amplify-cli/commit/11771f6b5dee939abbc4baf54da5fdacf49fbf85)) -- **amplify-appsync-simulator:** add support for AppSync template version ([#2329](https://github.com/aws-amplify/amplify-cli/issues/2329)) ([88cd220](https://github.com/aws-amplify/amplify-cli/commit/88cd220cbb254a018b888ee587c9c35994010377)), closes [#2134](https://github.com/aws-amplify/amplify-cli/issues/2134) [#2211](https://github.com/aws-amplify/amplify-cli/issues/2211) [#2299](https://github.com/aws-amplify/amplify-cli/issues/2299) -- **amplify-util-mock:** fix inifinte reload on windows ([#4270](https://github.com/aws-amplify/amplify-cli/issues/4270)) ([20f207e](https://github.com/aws-amplify/amplify-cli/commit/20f207ef835e7866cae78e6a521bf11e1d62b41d)), closes [#2736](https://github.com/aws-amplify/amplify-cli/issues/2736) -- **amplify-util-mock:** fixes [#3319](https://github.com/aws-amplify/amplify-cli/issues/3319) java version check ([#3511](https://github.com/aws-amplify/amplify-cli/issues/3511)) ([e237610](https://github.com/aws-amplify/amplify-cli/commit/e237610ac7e799f2f0f752596489528812c5d9dc)), closes [aws-amplify#3317](https://github.com/aws-amplify/issues/3317) -- **amplify-util-mock:** handle unsupported data source gracefully ([#1999](https://github.com/aws-amplify/amplify-cli/issues/1999)) ([f7cfe3e](https://github.com/aws-amplify/amplify-cli/commit/f7cfe3e01be7a3abe45a1129419f2306924b4ebe)), closes [#1997](https://github.com/aws-amplify/amplify-cli/issues/1997) -- **amplify-util-mock:** include custom resolver templates ([#2119](https://github.com/aws-amplify/amplify-cli/issues/2119)) ([f7174a7](https://github.com/aws-amplify/amplify-cli/commit/f7174a7b0bf09023e620cb4e2f4b0c7ccc154eea)), closes [#2049](https://github.com/aws-amplify/amplify-cli/issues/2049) [#2004](https://github.com/aws-amplify/amplify-cli/issues/2004) -- **amplify-util-mock:** loading resources from amplify-meta ([#4194](https://github.com/aws-amplify/amplify-cli/issues/4194)) ([2c73f44](https://github.com/aws-amplify/amplify-cli/commit/2c73f440e01ec9b471fbbf9d77658d42a5b61d3d)), closes [#4085](https://github.com/aws-amplify/amplify-cli/issues/4085) [#4012](https://github.com/aws-amplify/amplify-cli/issues/4012) -- **amplify-util-mock:** mock to add/update DDB index ([#3960](https://github.com/aws-amplify/amplify-cli/issues/3960)) ([132ca06](https://github.com/aws-amplify/amplify-cli/commit/132ca06829e54677dde62798dade117aecdd9315)), closes [#2210](https://github.com/aws-amplify/amplify-cli/issues/2210) -- **amplify-util-mock:** non-promise lambda failing ([#4203](https://github.com/aws-amplify/amplify-cli/issues/4203)) ([e34b97f](https://github.com/aws-amplify/amplify-cli/commit/e34b97f3750374a8bc8b693d9998fba1ec6f3ea0)) -- **amplify-util-mock:** pass env vars to lambda when invoked with mock ([#3790](https://github.com/aws-amplify/amplify-cli/issues/3790)) ([cc9c8a9](https://github.com/aws-amplify/amplify-cli/commit/cc9c8a92a37d8e47c1acaadb5d6caab79e5f0e9e)), closes [#2453](https://github.com/aws-amplify/amplify-cli/issues/2453) [#2690](https://github.com/aws-amplify/amplify-cli/issues/2690) -- **amplify-util-mock:** prevent resolver file overwrite in windows ([#2007](https://github.com/aws-amplify/amplify-cli/issues/2007)) ([5b78d25](https://github.com/aws-amplify/amplify-cli/commit/5b78d25519228085c5a0010ef90ac01cf161ccff)), closes [#2006](https://github.com/aws-amplify/amplify-cli/issues/2006) -- **amplify-util-mock:** safe access to LambdaConfiguration ([#2294](https://github.com/aws-amplify/amplify-cli/issues/2294)) ([0624739](https://github.com/aws-amplify/amplify-cli/commit/0624739fd3e44a14ae20122a2c29c77169b6bc0a)) -- **amplify-util-mock:** support large response from lambda ([#2060](https://github.com/aws-amplify/amplify-cli/issues/2060)) ([60efd28](https://github.com/aws-amplify/amplify-cli/commit/60efd2889bf59f533efe9aed9a39886eca296d1e)) -- **amplify-util-mock:** update Java version check logic ([dc28a0e](https://github.com/aws-amplify/amplify-cli/commit/dc28a0e770ae78a4d37138b76d3c22bae4679c6a)), closes [#5044](https://github.com/aws-amplify/amplify-cli/issues/5044) -- **amplify-util-mock:** use lambda fn name instead of resource name ([#2357](https://github.com/aws-amplify/amplify-cli/issues/2357)) ([4858921](https://github.com/aws-amplify/amplify-cli/commit/48589212b329e81122aab5adfb7589dd479934b7)), closes [#2280](https://github.com/aws-amplify/amplify-cli/issues/2280) -- **graphql-auth-transformer:** add list support for ownerField in subs ([#3166](https://github.com/aws-amplify/amplify-cli/issues/3166)) ([8d68277](https://github.com/aws-amplify/amplify-cli/commit/8d6827752ebd076424d3c76122b136eca65b02a8)) -- **graphql-auth-transformer:** early return if no obj ([#5050](https://github.com/aws-amplify/amplify-cli/issues/5050)) ([ed1f2b3](https://github.com/aws-amplify/amplify-cli/commit/ed1f2b364b50ab3f2b16ddac849c937b239bb499)) -- **graphql-auth-transformer:** use read to allow subscriptions ([#4340](https://github.com/aws-amplify/amplify-cli/issues/4340)) ([b8fc10d](https://github.com/aws-amplify/amplify-cli/commit/b8fc10d4e55c871826f1309fe340e32d0259ac0e)), closes [#3777](https://github.com/aws-amplify/amplify-cli/issues/3777) [#4182](https://github.com/aws-amplify/amplify-cli/issues/4182) [#4137](https://github.com/aws-amplify/amplify-cli/issues/4137) -- **graphql-key-transformer:** add key validation in create ([#4146](https://github.com/aws-amplify/amplify-cli/issues/4146)) ([0e20424](https://github.com/aws-amplify/amplify-cli/commit/0e20424f78876a1e4d8d5e0c80e6f76bcef98f84)), closes [#1756](https://github.com/aws-amplify/amplify-cli/issues/1756) -- [#1056](https://github.com/aws-amplify/amplify-cli/issues/1056), dedup environment file reading ([#2088](https://github.com/aws-amplify/amplify-cli/issues/2088)) ([940deaa](https://github.com/aws-amplify/amplify-cli/commit/940deaa6bbe7370e40e61946d0f1073623ba6e90)) -- [#2296](https://github.com/aws-amplify/amplify-cli/issues/2296) [#2304](https://github.com/aws-amplify/amplify-cli/issues/2304) [#2100](https://github.com/aws-amplify/amplify-cli/issues/2100) ([#2439](https://github.com/aws-amplify/amplify-cli/issues/2439)) ([82762d6](https://github.com/aws-amplify/amplify-cli/commit/82762d6187eb2102ebd134b181622188c5632d1d)) -- Bubbling error up to Graphiql from Lambda ([#3231](https://github.com/aws-amplify/amplify-cli/issues/3231)) ([12345da](https://github.com/aws-amplify/amplify-cli/commit/12345da3e99990d6f9994917667c30da0b0b2f2e)) -- build break, chore: typescript, lerna update ([#2640](https://github.com/aws-amplify/amplify-cli/issues/2640)) ([29fae36](https://github.com/aws-amplify/amplify-cli/commit/29fae366f4cab054feefa58c7dc733002d19570c)) -- e2e test failures with node env ([#2831](https://github.com/aws-amplify/amplify-cli/issues/2831)) ([377dfa7](https://github.com/aws-amplify/amplify-cli/commit/377dfa7c78d97408d53ba3611045d19d477c163d)) -- e2e tests, tsconfigs, [@deprecated](https://github.com/deprecated) directive for codegen: ([#3338](https://github.com/aws-amplify/amplify-cli/issues/3338)) ([2ed7715](https://github.com/aws-amplify/amplify-cli/commit/2ed77151dd6367ac9547f78fe600e7913a3d37b2)) -- export Typescript definitions and fix resulting type errors ([#2452](https://github.com/aws-amplify/amplify-cli/issues/2452)) ([7de3845](https://github.com/aws-amplify/amplify-cli/commit/7de384594d3b9cbf22cdaa85107fc8df26c141ec)), closes [#2451](https://github.com/aws-amplify/amplify-cli/issues/2451) -- falsy values can be returned in mock now ([#3254](https://github.com/aws-amplify/amplify-cli/issues/3254)) ([6795e78](https://github.com/aws-amplify/amplify-cli/commit/6795e783c104004a2b2576f6903b35c1c6d2ed03)), closes [#2566](https://github.com/aws-amplify/amplify-cli/issues/2566) -- local mock fix ([#1982](https://github.com/aws-amplify/amplify-cli/issues/1982)) ([8ee9029](https://github.com/aws-amplify/amplify-cli/commit/8ee90298189f4d3140ab84fe2d40d16bcb95485f)) -- move py test event to src/event.json ([#3851](https://github.com/aws-amplify/amplify-cli/issues/3851)) ([1c4a0cb](https://github.com/aws-amplify/amplify-cli/commit/1c4a0cb5022869fc6aa3c358e9a4c8935fec2b54)) -- regression in graphiql-explorer build ([#3453](https://github.com/aws-amplify/amplify-cli/issues/3453)) ([98c905e](https://github.com/aws-amplify/amplify-cli/commit/98c905edfdf52495224d2af3a934faeaab8b310a)) -- replaced v1 docs references with v2 docs references ([#4169](https://github.com/aws-amplify/amplify-cli/issues/4169)) ([b578c2d](https://github.com/aws-amplify/amplify-cli/commit/b578c2dcd10038367c653ede2f6da42e7644b41b)) -- test config update for e2e ([#3345](https://github.com/aws-amplify/amplify-cli/issues/3345)) ([0d8cadc](https://github.com/aws-amplify/amplify-cli/commit/0d8cadcafeeaaaf1f4251017769021d00b8600be)) -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) -- **cli:** fix new plugin platform codegen related issue ([#2266](https://github.com/aws-amplify/amplify-cli/issues/2266)) ([c557182](https://github.com/aws-amplify/amplify-cli/commit/c557182b2d423bb1c2f8832ecd49076c806b05bb)) -- **graphql-auth-transformer:** remove enforce model check for field ([#2607](https://github.com/aws-amplify/amplify-cli/issues/2607)) ([b1d6d4b](https://github.com/aws-amplify/amplify-cli/commit/b1d6d4b1c933e552874b3bb016f611567df186d0)), closes [#2591](https://github.com/aws-amplify/amplify-cli/issues/2591) [#2591](https://github.com/aws-amplify/amplify-cli/issues/2591) -- **mock:** [#2606](https://github.com/aws-amplify/amplify-cli/issues/2606) - mocking does not start when there are LSIs in DynamoDB table ([#2667](https://github.com/aws-amplify/amplify-cli/issues/2667)) ([914470e](https://github.com/aws-amplify/amplify-cli/commit/914470e304391fbff756138d381754021aec6528)) - -### Features - -- feature flag implementation ([#4891](https://github.com/aws-amplify/amplify-cli/issues/4891)) ([6d1c632](https://github.com/aws-amplify/amplify-cli/commit/6d1c632952a49cb56670c11c9cb0c3620d0eb332)) -- Lambda layers ([#4697](https://github.com/aws-amplify/amplify-cli/issues/4697)) ([4e97400](https://github.com/aws-amplify/amplify-cli/commit/4e974007d95c894ab4108a2dff8d5996e7e3ce25)) -- minor tweaks to multi-runtime platform ([#3804](https://github.com/aws-amplify/amplify-cli/issues/3804)) ([60d68d7](https://github.com/aws-amplify/amplify-cli/commit/60d68d7e1a6e8c00cd629a38e9aefb2396a59737)) -- support for overriding pipeline function templates in transformer ([#4196](https://github.com/aws-amplify/amplify-cli/issues/4196)) ([e1830ae](https://github.com/aws-amplify/amplify-cli/commit/e1830aeb31fef8f035cb0a992a150d37f78e07bb)), closes [#4192](https://github.com/aws-amplify/amplify-cli/issues/4192) -- update post-install to copy executable assets to .amplify ([#5595](https://github.com/aws-amplify/amplify-cli/issues/5595)) ([53a23a0](https://github.com/aws-amplify/amplify-cli/commit/53a23a07cbb9e09566c1f0f577ba2b7488bc2eae)) -- **amplify-appsync-simulator:** add support for websocket subscriptions ([#3912](https://github.com/aws-amplify/amplify-cli/issues/3912)) ([f6dac5b](https://github.com/aws-amplify/amplify-cli/commit/f6dac5b6d55867e35b28b1c3eec9a6eeb4e4fbe3)), closes [#3008](https://github.com/aws-amplify/amplify-cli/issues/3008) -- **amplify-category-function:** Refactor invoke to call runtime plugins ([#3768](https://github.com/aws-amplify/amplify-cli/issues/3768)) ([92293fa](https://github.com/aws-amplify/amplify-cli/commit/92293fa83190bd18aacdc2f46a22938f94b89609)) -- **amplify-util-mock:** add mock config for JAVA_OPTS ([#3503](https://github.com/aws-amplify/amplify-cli/issues/3503)) ([24d8085](https://github.com/aws-amplify/amplify-cli/commit/24d8085325d435284b9c49a43592e61891fd72bc)) -- **amplify-util-mock:** add support for S3 triggers in local mocking ([#2101](https://github.com/aws-amplify/amplify-cli/issues/2101)) ([ac9a134](https://github.com/aws-amplify/amplify-cli/commit/ac9a13469704f9c3cfa584760087e389380add3d)) -- **amplify-util-mock:** update cfn processing ([#3285](https://github.com/aws-amplify/amplify-cli/issues/3285)) ([ab369b3](https://github.com/aws-amplify/amplify-cli/commit/ab369b33a1459c9296c648748624e2219f1d1fcf)) -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) -- **cli:** new plugin platform ([#2254](https://github.com/aws-amplify/amplify-cli/issues/2254)) ([7ec29dd](https://github.com/aws-amplify/amplify-cli/commit/7ec29dd4f2da8c90727b36469eca646d289877b6)) -- **graphql-key-transformer:** add query automatically for named keys ([#4458](https://github.com/aws-amplify/amplify-cli/issues/4458)) ([375282d](https://github.com/aws-amplify/amplify-cli/commit/375282d648cf9d096d13c7b958a0dfb7bd6d60b0)) -- add support for multiauth in mock server ([#2109](https://github.com/aws-amplify/amplify-cli/issues/2109)) ([fe8ee8c](https://github.com/aws-amplify/amplify-cli/commit/fe8ee8cff355a826fa9ccddcf0fad8a200a081af)) -- implement multi-auth functionality ([#1916](https://github.com/aws-amplify/amplify-cli/issues/1916)) ([b99f58e](https://github.com/aws-amplify/amplify-cli/commit/b99f58e4a2b85cbe9f430838554ae3c277440132)) -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e5346ee1f27a2e9bee25fbbdcb19417f5230f)) - -### Reverts - -- add query automatically for named keys ([#4513](https://github.com/aws-amplify/amplify-cli/issues/4513)) ([50c1120](https://github.com/aws-amplify/amplify-cli/commit/50c112050645b8fd5011a1e6863d30f58e0c55cb)) -- Revert "fix(graphql-auth-transformer): add list support for ownerField in subs (#3166)" (#3572) ([d693e6b](https://github.com/aws-amplify/amplify-cli/commit/d693e6b2819a5d20188fa9f68d94ef955e474bd3)), closes [#3166](https://github.com/aws-amplify/amplify-cli/issues/3166) [#3572](https://github.com/aws-amplify/amplify-cli/issues/3572) - -* Adding Auth on Subscriptions (#2068) ([81c630d](https://github.com/aws-amplify/amplify-cli/commit/81c630d782a6be720e513677a34b7a7dacbdc629)), closes [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) - -### BREAKING CHANGES - -- If an owner is used in the auth directive it will either be a requirement if it's - the only rule or an optional input if used with other rules -- If an owner is included in the auth directive it will either be a requirement if - it's the only rule or an optional input if used with other rules -- the subscription operations will require an argument if owner is the only auth rule -- Subscriptions will require an argument if an owner is only rule set - If owner & - group rules are owner will be an optional arg - -## [3.25.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.25.3...amplify-util-mock@3.25.6) (2020-11-20) - -**Note:** Version bump only for package amplify-util-mock - -## [3.25.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.25.3...amplify-util-mock@3.25.5) (2020-11-20) - -**Note:** Version bump only for package amplify-util-mock - -## [3.25.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.25.3...amplify-util-mock@3.25.4) (2020-11-19) - -**Note:** Version bump only for package amplify-util-mock - -## [3.25.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.25.2...amplify-util-mock@3.25.3) (2020-11-08) - -**Note:** Version bump only for package amplify-util-mock - -## [3.25.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.25.1...amplify-util-mock@3.25.2) (2020-10-30) - -**Note:** Version bump only for package amplify-util-mock - -## [3.25.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.25.0...amplify-util-mock@3.25.1) (2020-10-27) - -**Note:** Version bump only for package amplify-util-mock - -# [3.25.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.24.16...amplify-util-mock@3.25.0) (2020-10-22) - -### Features - -- update post-install to copy executable assets to .amplify ([#5595](https://github.com/aws-amplify/amplify-cli/issues/5595)) ([53a23a0](https://github.com/aws-amplify/amplify-cli/commit/53a23a07cbb9e09566c1f0f577ba2b7488bc2eae)) - -## [3.24.16](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.24.15...amplify-util-mock@3.24.16) (2020-10-17) - -**Note:** Version bump only for package amplify-util-mock - -## [3.24.15](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.24.14...amplify-util-mock@3.24.15) (2020-10-15) - -**Note:** Version bump only for package amplify-util-mock - -## [3.24.14](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.24.13...amplify-util-mock@3.24.14) (2020-10-13) - -**Note:** Version bump only for package amplify-util-mock - -## [3.24.13](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.24.12...amplify-util-mock@3.24.13) (2020-10-07) - -### Bug Fixes - -- fixed exit codes on message ([#5385](https://github.com/aws-amplify/amplify-cli/issues/5385)) ([b5641db](https://github.com/aws-amplify/amplify-cli/commit/b5641db760134bcf3185b798b384fbb7cc5ac382)) - -## [3.24.12](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.24.11...amplify-util-mock@3.24.12) (2020-10-01) - -**Note:** Version bump only for package amplify-util-mock - -## [3.24.11](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.24.10...amplify-util-mock@3.24.11) (2020-09-25) - -**Note:** Version bump only for package amplify-util-mock - -## [3.24.10](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.24.9...amplify-util-mock@3.24.10) (2020-09-16) - -### Bug Fixes - -- **amplify-util-mock:** pass transform config into generateCode ([#5259](https://github.com/aws-amplify/amplify-cli/issues/5259)) ([7a5ec2d](https://github.com/aws-amplify/amplify-cli/commit/7a5ec2ddc36ef2402f305eeca12964a5caac0b84)), closes [#5055](https://github.com/aws-amplify/amplify-cli/issues/5055) -- timeout mock function invocation ([#5198](https://github.com/aws-amplify/amplify-cli/issues/5198)) ([9d7af87](https://github.com/aws-amplify/amplify-cli/commit/9d7af8731431154091f29a7f194fae2d4ee2ac71)) - -## [3.24.9](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.24.8...amplify-util-mock@3.24.9) (2020-09-09) - -**Note:** Version bump only for package amplify-util-mock - -## [3.24.8](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.24.7...amplify-util-mock@3.24.8) (2020-09-03) - -**Note:** Version bump only for package amplify-util-mock - -## [3.24.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.24.6...amplify-util-mock@3.24.7) (2020-09-03) - -**Note:** Version bump only for package amplify-util-mock - -## [3.24.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.24.5...amplify-util-mock@3.24.6) (2020-09-02) - -**Note:** Version bump only for package amplify-util-mock - -## [3.24.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.24.4...amplify-util-mock@3.24.5) (2020-08-31) - -### Bug Fixes - -- match Fn::GetAtt and Fn::Sub when initializing lambda resolvers ([#5095](https://github.com/aws-amplify/amplify-cli/issues/5095)) ([11771f6](https://github.com/aws-amplify/amplify-cli/commit/11771f6b5dee939abbc4baf54da5fdacf49fbf85)) - -## [3.24.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.24.3...amplify-util-mock@3.24.4) (2020-08-20) - -### Bug Fixes - -- **amplify-appsync-simulator:** fix returning null on nonexistent fields ([#5093](https://github.com/aws-amplify/amplify-cli/issues/5093)) ([a0439db](https://github.com/aws-amplify/amplify-cli/commit/a0439db462e8189d7b158472f269326e2c6bdb8d)), closes [#5003](https://github.com/aws-amplify/amplify-cli/issues/5003) -- **amplify-util-mock:** update Java version check logic ([dc28a0e](https://github.com/aws-amplify/amplify-cli/commit/dc28a0e770ae78a4d37138b76d3c22bae4679c6a)), closes [#5044](https://github.com/aws-amplify/amplify-cli/issues/5044) - -## [3.24.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.24.2...amplify-util-mock@3.24.3) (2020-08-14) - -### Bug Fixes - -- **graphql-auth-transformer:** early return if no obj ([#5050](https://github.com/aws-amplify/amplify-cli/issues/5050)) ([ed1f2b3](https://github.com/aws-amplify/amplify-cli/commit/ed1f2b364b50ab3f2b16ddac849c937b239bb499)) - -## [3.24.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.24.1...amplify-util-mock@3.24.2) (2020-08-11) - -**Note:** Version bump only for package amplify-util-mock - -## [3.24.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.24.0...amplify-util-mock@3.24.1) (2020-08-06) - -**Note:** Version bump only for package amplify-util-mock - -# [3.24.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.22.4...amplify-util-mock@3.24.0) (2020-07-29) - -### Features - -- feature flag implementation ([#4891](https://github.com/aws-amplify/amplify-cli/issues/4891)) ([6d1c632](https://github.com/aws-amplify/amplify-cli/commit/6d1c632952a49cb56670c11c9cb0c3620d0eb332)) - -# [3.23.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.22.4...amplify-util-mock@3.23.0) (2020-07-23) - -### Features - -- feature flag implementation ([#4891](https://github.com/aws-amplify/amplify-cli/issues/4891)) ([4639450](https://github.com/aws-amplify/amplify-cli/commit/463945029cfe861f74986d9a8b9af6b827d2063d)) - -## [3.22.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.22.3...amplify-util-mock@3.22.4) (2020-07-18) - -**Note:** Version bump only for package amplify-util-mock - -## [3.22.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.22.2...amplify-util-mock@3.22.3) (2020-07-15) - -**Note:** Version bump only for package amplify-util-mock - -## [3.22.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.22.1...amplify-util-mock@3.22.2) (2020-07-14) - -**Note:** Version bump only for package amplify-util-mock - -## [3.22.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.22.0...amplify-util-mock@3.22.1) (2020-07-09) - -**Note:** Version bump only for package amplify-util-mock - -# [3.22.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.21.3...amplify-util-mock@3.22.0) (2020-07-07) - -### Features - -- Lambda layers ([#4697](https://github.com/aws-amplify/amplify-cli/issues/4697)) ([c55b2e0](https://github.com/aws-amplify/amplify-cli/commit/c55b2e0c3377127aaf887591d7bc20d7240ef11d)) - -## [3.21.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.21.2...amplify-util-mock@3.21.3) (2020-06-25) - -### Reverts - -- Revert "fix: change scope of hashed files for AppSync (#4602)" ([73aaab1](https://github.com/aws-amplify/amplify-cli/commit/73aaab1a7b1f8b2de5fa22fa1ef9aeea7de35cb4)), closes [#4602](https://github.com/aws-amplify/amplify-cli/issues/4602) - -## [3.21.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.21.1...amplify-util-mock@3.21.2) (2020-06-18) - -### Bug Fixes - -- change scope of hashed files for AppSync ([#4602](https://github.com/aws-amplify/amplify-cli/issues/4602)) ([10fa9da](https://github.com/aws-amplify/amplify-cli/commit/10fa9da646f4de755e2dc92cd4bb2a6319425d72)), closes [#4458](https://github.com/aws-amplify/amplify-cli/issues/4458) - -## [3.21.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.21.0...amplify-util-mock@3.21.1) (2020-06-11) - -### Reverts - -- add query automatically for named keys ([#4513](https://github.com/aws-amplify/amplify-cli/issues/4513)) ([6d3123b](https://github.com/aws-amplify/amplify-cli/commit/6d3123bfe3ba412d3b1af076e550e6733c988c8f)) - -# [3.21.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.20.2...amplify-util-mock@3.21.0) (2020-06-10) - -### Features - -- **graphql-key-transformer:** add query automatically for named keys ([#4458](https://github.com/aws-amplify/amplify-cli/issues/4458)) ([3d194f8](https://github.com/aws-amplify/amplify-cli/commit/3d194f805dcbd6325ddf78155c4327dbca3e7f4a)) - -## [3.20.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.20.1...amplify-util-mock@3.20.2) (2020-06-02) - -### Bug Fixes - -- **graphql-auth-transformer:** use read to allow subscriptions ([#4340](https://github.com/aws-amplify/amplify-cli/issues/4340)) ([15eac84](https://github.com/aws-amplify/amplify-cli/commit/15eac8454e0455cd402776308a2716ac406bacbb)), closes [#3777](https://github.com/aws-amplify/amplify-cli/issues/3777) [#4182](https://github.com/aws-amplify/amplify-cli/issues/4182) [#4137](https://github.com/aws-amplify/amplify-cli/issues/4137) - -## [3.20.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.20.0...amplify-util-mock@3.20.1) (2020-05-26) - -### Bug Fixes - -- **amplify-util-mock:** fix inifinte reload on windows ([#4270](https://github.com/aws-amplify/amplify-cli/issues/4270)) ([7f3dc48](https://github.com/aws-amplify/amplify-cli/commit/7f3dc48fa158cdba6d3282fbb856d879f3784b8b)), closes [#2736](https://github.com/aws-amplify/amplify-cli/issues/2736) -- **amplify-util-mock:** fixes [#3319](https://github.com/aws-amplify/amplify-cli/issues/3319) java version check ([#3511](https://github.com/aws-amplify/amplify-cli/issues/3511)) ([808e36e](https://github.com/aws-amplify/amplify-cli/commit/808e36ec763f33fd497fa56850811abd6c0c77f8)), closes [aws-amplify#3317](https://github.com/aws-amplify/issues/3317) -- **amplify-util-mock:** loading resources from amplify-meta ([#4194](https://github.com/aws-amplify/amplify-cli/issues/4194)) ([eaa9bcf](https://github.com/aws-amplify/amplify-cli/commit/eaa9bcf46c21d4ac4879919d1cadf264ecbb8eef)), closes [#4085](https://github.com/aws-amplify/amplify-cli/issues/4085) [#4012](https://github.com/aws-amplify/amplify-cli/issues/4012) - -# [3.20.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.19.1...amplify-util-mock@3.20.0) (2020-05-15) - -### Bug Fixes - -- **amplify-appsync-simulator:** support inline resolver templates ([56fdd00](https://github.com/aws-amplify/amplify-cli/commit/56fdd0057a6ecfbd320f2a3f8b0858959bbe750e)), closes [#3834](https://github.com/aws-amplify/amplify-cli/issues/3834) -- **amplify-util-mock:** non-promise lambda failing ([#4203](https://github.com/aws-amplify/amplify-cli/issues/4203)) ([cb533c6](https://github.com/aws-amplify/amplify-cli/commit/cb533c69aaddd6d2f38a7152f4471f2074cd8198)) -- **graphql-key-transformer:** add key validation in create ([#4146](https://github.com/aws-amplify/amplify-cli/issues/4146)) ([0e20424](https://github.com/aws-amplify/amplify-cli/commit/0e20424f78876a1e4d8d5e0c80e6f76bcef98f84)), closes [#1756](https://github.com/aws-amplify/amplify-cli/issues/1756) - -### Features - -- support for overriding pipeline function templates in transformer ([#4196](https://github.com/aws-amplify/amplify-cli/issues/4196)) ([e1830ae](https://github.com/aws-amplify/amplify-cli/commit/e1830aeb31fef8f035cb0a992a150d37f78e07bb)), closes [#4192](https://github.com/aws-amplify/amplify-cli/issues/4192) - -## [3.19.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.19.0...amplify-util-mock@3.19.1) (2020-05-08) - -### Bug Fixes - -- replaced v1 docs references with v2 docs references ([#4169](https://github.com/aws-amplify/amplify-cli/issues/4169)) ([b578c2d](https://github.com/aws-amplify/amplify-cli/commit/b578c2dcd10038367c653ede2f6da42e7644b41b)) - -# [3.19.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.18.0...amplify-util-mock@3.19.0) (2020-04-23) - -### Bug Fixes - -- **amplify-util-mock:** mock to add/update DDB index ([#3960](https://github.com/aws-amplify/amplify-cli/issues/3960)) ([132ca06](https://github.com/aws-amplify/amplify-cli/commit/132ca06829e54677dde62798dade117aecdd9315)), closes [#2210](https://github.com/aws-amplify/amplify-cli/issues/2210) - -### Features - -- **amplify-appsync-simulator:** add support for websocket subscriptions ([#3912](https://github.com/aws-amplify/amplify-cli/issues/3912)) ([f6dac5b](https://github.com/aws-amplify/amplify-cli/commit/f6dac5b6d55867e35b28b1c3eec9a6eeb4e4fbe3)), closes [#3008](https://github.com/aws-amplify/amplify-cli/issues/3008) - -# [3.18.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.17.1...amplify-util-mock@3.18.0) (2020-04-06) - -### Bug Fixes - -- **amplify-util-mock:** pass env vars to lambda when invoked with mock ([#3790](https://github.com/aws-amplify/amplify-cli/issues/3790)) ([cc9c8a9](https://github.com/aws-amplify/amplify-cli/commit/cc9c8a92a37d8e47c1acaadb5d6caab79e5f0e9e)), closes [#2453](https://github.com/aws-amplify/amplify-cli/issues/2453) [#2690](https://github.com/aws-amplify/amplify-cli/issues/2690) -- move py test event to src/event.json ([#3851](https://github.com/aws-amplify/amplify-cli/issues/3851)) ([1c4a0cb](https://github.com/aws-amplify/amplify-cli/commit/1c4a0cb5022869fc6aa3c358e9a4c8935fec2b54)) - -### Features - -- **amplify-category-function:** Refactor invoke to call runtime plugins ([#3768](https://github.com/aws-amplify/amplify-cli/issues/3768)) ([92293fa](https://github.com/aws-amplify/amplify-cli/commit/92293fa83190bd18aacdc2f46a22938f94b89609)) -- minor tweaks to multi-runtime platform ([#3804](https://github.com/aws-amplify/amplify-cli/issues/3804)) ([60d68d7](https://github.com/aws-amplify/amplify-cli/commit/60d68d7e1a6e8c00cd629a38e9aefb2396a59737)) - -## [3.17.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.17.0...amplify-util-mock@3.17.1) (2020-03-26) - -**Note:** Version bump only for package amplify-util-mock - -# [3.17.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.16.2...amplify-util-mock@3.17.0) (2020-03-22) - -### Features - -- **amplify-util-mock:** add mock config for JAVA_OPTS ([#3503](https://github.com/aws-amplify/amplify-cli/issues/3503)) ([24d8085](https://github.com/aws-amplify/amplify-cli/commit/24d8085325d435284b9c49a43592e61891fd72bc)) - -## [3.16.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.16.1...amplify-util-mock@3.16.2) (2020-03-10) - -**Note:** Version bump only for package amplify-util-mock - -## [3.16.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.14.1...amplify-util-mock@3.16.1) (2020-03-07) - -### Bug Fixes - -- Bubbling error up to Graphiql from Lambda ([#3231](https://github.com/aws-amplify/amplify-cli/issues/3231)) ([12345da](https://github.com/aws-amplify/amplify-cli/commit/12345da3e99990d6f9994917667c30da0b0b2f2e)) -- **amplify-util-mock:** fixes [#3510](https://github.com/aws-amplify/amplify-cli/issues/3510) bucketname error ([#3526](https://github.com/aws-amplify/amplify-cli/issues/3526)) ([0552f72](https://github.com/aws-amplify/amplify-cli/commit/0552f72cf3ec301c6ff0dc7d2617cf9beb787725)) -- **graphql-auth-transformer:** add list support for ownerField in subs ([#3166](https://github.com/aws-amplify/amplify-cli/issues/3166)) ([8d68277](https://github.com/aws-amplify/amplify-cli/commit/8d6827752ebd076424d3c76122b136eca65b02a8)) - -### Reverts - -- Revert "fix(graphql-auth-transformer): add list support for ownerField in subs (#3166)" (#3572) ([d693e6b](https://github.com/aws-amplify/amplify-cli/commit/d693e6b2819a5d20188fa9f68d94ef955e474bd3)), closes [#3166](https://github.com/aws-amplify/amplify-cli/issues/3166) [#3572](https://github.com/aws-amplify/amplify-cli/issues/3572) - -## [3.15.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.14.3-beta.0...amplify-util-mock@3.15.1) (2020-03-05) - -**Note:** Version bump only for package amplify-util-mock - -## [3.14.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.14.0...amplify-util-mock@3.14.1) (2020-02-18) - -### Bug Fixes - -- regression in graphiql-explorer build ([#3453](https://github.com/aws-amplify/amplify-cli/issues/3453)) ([98c905e](https://github.com/aws-amplify/amplify-cli/commit/98c905edfdf52495224d2af3a934faeaab8b310a)) - -# [3.14.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.13.2...amplify-util-mock@3.14.0) (2020-02-13) - -### Features - -- **amplify-util-mock:** update cfn processing ([#3285](https://github.com/aws-amplify/amplify-cli/issues/3285)) ([ab369b3](https://github.com/aws-amplify/amplify-cli/commit/ab369b33a1459c9296c648748624e2219f1d1fcf)) - -## [3.13.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.13.1...amplify-util-mock@3.13.2) (2020-02-07) - -### Bug Fixes - -- e2e tests, tsconfigs, [@deprecated](https://github.com/deprecated) directive for codegen: ([#3338](https://github.com/aws-amplify/amplify-cli/issues/3338)) ([2ed7715](https://github.com/aws-amplify/amplify-cli/commit/2ed77151dd6367ac9547f78fe600e7913a3d37b2)) -- falsy values can be returned in mock now ([#3254](https://github.com/aws-amplify/amplify-cli/issues/3254)) ([6795e78](https://github.com/aws-amplify/amplify-cli/commit/6795e783c104004a2b2576f6903b35c1c6d2ed03)), closes [#2566](https://github.com/aws-amplify/amplify-cli/issues/2566) -- test config update for e2e ([#3345](https://github.com/aws-amplify/amplify-cli/issues/3345)) ([0d8cadc](https://github.com/aws-amplify/amplify-cli/commit/0d8cadcafeeaaaf1f4251017769021d00b8600be)) - -## [3.13.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@3.13.0...amplify-util-mock@3.13.1) (2020-01-24) - -**Note:** Version bump only for package amplify-util-mock - -# [3.13.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@2.17.0...amplify-util-mock@3.13.0) (2020-01-23) - -### Bug Fixes - -- **mock:** [#2606](https://github.com/aws-amplify/amplify-cli/issues/2606) - mocking does not start when there are LSIs in DynamoDB table ([#2667](https://github.com/aws-amplify/amplify-cli/issues/2667)) ([914470e](https://github.com/aws-amplify/amplify-cli/commit/914470e304391fbff756138d381754021aec6528)) -- e2e test failures with node env ([#2831](https://github.com/aws-amplify/amplify-cli/issues/2831)) ([377dfa7](https://github.com/aws-amplify/amplify-cli/commit/377dfa7c78d97408d53ba3611045d19d477c163d)) -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [3.12.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@2.17.0...amplify-util-mock@3.12.0) (2020-01-09) - -### Bug Fixes - -- **mock:** [#2606](https://github.com/aws-amplify/amplify-cli/issues/2606) - mocking does not start when there are LSIs in DynamoDB table ([#2667](https://github.com/aws-amplify/amplify-cli/issues/2667)) ([914470e](https://github.com/aws-amplify/amplify-cli/commit/914470e304391fbff756138d381754021aec6528)) -- e2e test failures with node env ([#2831](https://github.com/aws-amplify/amplify-cli/issues/2831)) ([377dfa7](https://github.com/aws-amplify/amplify-cli/commit/377dfa7c78d97408d53ba3611045d19d477c163d)) -- upgrade to node10 as min version for CLI ([#3128](https://github.com/aws-amplify/amplify-cli/issues/3128)) ([a0b18e0](https://github.com/aws-amplify/amplify-cli/commit/a0b18e0187a26b4ab0e6e986b0277f347e829444)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [3.11.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@2.17.0...amplify-util-mock@3.11.0) (2019-12-31) - -### Bug Fixes - -- **mock:** [#2606](https://github.com/aws-amplify/amplify-cli/issues/2606) - mocking does not start when there are LSIs in DynamoDB table ([#2667](https://github.com/aws-amplify/amplify-cli/issues/2667)) ([914470e](https://github.com/aws-amplify/amplify-cli/commit/914470e304391fbff756138d381754021aec6528)) -- e2e test failures with node env ([#2831](https://github.com/aws-amplify/amplify-cli/issues/2831)) ([377dfa7](https://github.com/aws-amplify/amplify-cli/commit/377dfa7c78d97408d53ba3611045d19d477c163d)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [3.10.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@2.17.0...amplify-util-mock@3.10.0) (2019-12-28) - -### Bug Fixes - -- **mock:** [#2606](https://github.com/aws-amplify/amplify-cli/issues/2606) - mocking does not start when there are LSIs in DynamoDB table ([#2667](https://github.com/aws-amplify/amplify-cli/issues/2667)) ([914470e](https://github.com/aws-amplify/amplify-cli/commit/914470e304391fbff756138d381754021aec6528)) -- e2e test failures with node env ([#2831](https://github.com/aws-amplify/amplify-cli/issues/2831)) ([377dfa7](https://github.com/aws-amplify/amplify-cli/commit/377dfa7c78d97408d53ba3611045d19d477c163d)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [3.9.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@2.17.0...amplify-util-mock@3.9.0) (2019-12-26) - -### Bug Fixes - -- **mock:** [#2606](https://github.com/aws-amplify/amplify-cli/issues/2606) - mocking does not start when there are LSIs in DynamoDB table ([#2667](https://github.com/aws-amplify/amplify-cli/issues/2667)) ([914470e](https://github.com/aws-amplify/amplify-cli/commit/914470e304391fbff756138d381754021aec6528)) -- e2e test failures with node env ([#2831](https://github.com/aws-amplify/amplify-cli/issues/2831)) ([377dfa7](https://github.com/aws-amplify/amplify-cli/commit/377dfa7c78d97408d53ba3611045d19d477c163d)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [3.8.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@2.17.0...amplify-util-mock@3.8.0) (2019-12-25) - -### Bug Fixes - -- **mock:** [#2606](https://github.com/aws-amplify/amplify-cli/issues/2606) - mocking does not start when there are LSIs in DynamoDB table ([#2667](https://github.com/aws-amplify/amplify-cli/issues/2667)) ([914470e](https://github.com/aws-amplify/amplify-cli/commit/914470e304391fbff756138d381754021aec6528)) -- e2e test failures with node env ([#2831](https://github.com/aws-amplify/amplify-cli/issues/2831)) ([377dfa7](https://github.com/aws-amplify/amplify-cli/commit/377dfa7c78d97408d53ba3611045d19d477c163d)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [3.7.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@2.17.0...amplify-util-mock@3.7.0) (2019-12-20) - -### Bug Fixes - -- **mock:** [#2606](https://github.com/aws-amplify/amplify-cli/issues/2606) - mocking does not start when there are LSIs in DynamoDB table ([#2667](https://github.com/aws-amplify/amplify-cli/issues/2667)) ([914470e](https://github.com/aws-amplify/amplify-cli/commit/914470e304391fbff756138d381754021aec6528)) -- e2e test failures with node env ([#2831](https://github.com/aws-amplify/amplify-cli/issues/2831)) ([377dfa7](https://github.com/aws-amplify/amplify-cli/commit/377dfa7c78d97408d53ba3611045d19d477c163d)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [3.6.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@2.17.0...amplify-util-mock@3.6.0) (2019-12-10) - -### Bug Fixes - -- **mock:** [#2606](https://github.com/aws-amplify/amplify-cli/issues/2606) - mocking does not start when there are LSIs in DynamoDB table ([#2667](https://github.com/aws-amplify/amplify-cli/issues/2667)) ([914470e](https://github.com/aws-amplify/amplify-cli/commit/914470e304391fbff756138d381754021aec6528)) -- e2e test failures with node env ([#2831](https://github.com/aws-amplify/amplify-cli/issues/2831)) ([377dfa7](https://github.com/aws-amplify/amplify-cli/commit/377dfa7c78d97408d53ba3611045d19d477c163d)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [3.4.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@2.17.0...amplify-util-mock@3.4.0) (2019-12-03) - -### Bug Fixes - -- **mock:** [#2606](https://github.com/aws-amplify/amplify-cli/issues/2606) - mocking does not start when there are LSIs in DynamoDB table ([#2667](https://github.com/aws-amplify/amplify-cli/issues/2667)) ([914470e](https://github.com/aws-amplify/amplify-cli/commit/914470e304391fbff756138d381754021aec6528)) -- e2e test failures with node env ([#2831](https://github.com/aws-amplify/amplify-cli/issues/2831)) ([377dfa7](https://github.com/aws-amplify/amplify-cli/commit/377dfa7c78d97408d53ba3611045d19d477c163d)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [3.3.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@2.17.0...amplify-util-mock@3.3.0) (2019-12-01) - -### Bug Fixes - -- **mock:** [#2606](https://github.com/aws-amplify/amplify-cli/issues/2606) - mocking does not start when there are LSIs in DynamoDB table ([#2667](https://github.com/aws-amplify/amplify-cli/issues/2667)) ([914470e](https://github.com/aws-amplify/amplify-cli/commit/914470e304391fbff756138d381754021aec6528)) -- e2e test failures with node env ([#2831](https://github.com/aws-amplify/amplify-cli/issues/2831)) ([377dfa7](https://github.com/aws-amplify/amplify-cli/commit/377dfa7c78d97408d53ba3611045d19d477c163d)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [3.2.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@2.17.0...amplify-util-mock@3.2.0) (2019-11-27) - -### Bug Fixes - -- **mock:** [#2606](https://github.com/aws-amplify/amplify-cli/issues/2606) - mocking does not start when there are LSIs in DynamoDB table ([#2667](https://github.com/aws-amplify/amplify-cli/issues/2667)) ([914470e](https://github.com/aws-amplify/amplify-cli/commit/914470e304391fbff756138d381754021aec6528)) -- e2e test failures with node env ([#2831](https://github.com/aws-amplify/amplify-cli/issues/2831)) ([377dfa7](https://github.com/aws-amplify/amplify-cli/commit/377dfa7c78d97408d53ba3611045d19d477c163d)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# [3.1.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-util-mock@2.17.0...amplify-util-mock@3.1.0) (2019-11-27) - -### Bug Fixes - -- **mock:** [#2606](https://github.com/aws-amplify/amplify-cli/issues/2606) - mocking does not start when there are LSIs in DynamoDB table ([#2667](https://github.com/aws-amplify/amplify-cli/issues/2667)) ([914470e](https://github.com/aws-amplify/amplify-cli/commit/914470e304391fbff756138d381754021aec6528)) -- e2e test failures with node env ([#2831](https://github.com/aws-amplify/amplify-cli/issues/2831)) ([377dfa7](https://github.com/aws-amplify/amplify-cli/commit/377dfa7c78d97408d53ba3611045d19d477c163d)) - -### Features - -- **cli:** cLI updates and new features for Amplify Console ([#2742](https://github.com/aws-amplify/amplify-cli/issues/2742)) ([0fd0dd5](https://github.com/aws-amplify/amplify-cli/commit/0fd0dd5102177766c454c8715fa5acac32385048)) - -# 2.0.0 (2019-08-30) - -### Bug Fixes - -- **amplify-util-mock:** handle unsupported data source gracefully ([#1999](https://github.com/aws-amplify/amplify-cli/issues/1999)) ([f7cfe3e](https://github.com/aws-amplify/amplify-cli/commit/f7cfe3e)), closes [#1997](https://github.com/aws-amplify/amplify-cli/issues/1997) -- [#1056](https://github.com/aws-amplify/amplify-cli/issues/1056), dedup environment file reading ([#2088](https://github.com/aws-amplify/amplify-cli/issues/2088)) ([940deaa](https://github.com/aws-amplify/amplify-cli/commit/940deaa)) -- local mock fix ([#1982](https://github.com/aws-amplify/amplify-cli/issues/1982)) ([8ee9029](https://github.com/aws-amplify/amplify-cli/commit/8ee9029)) -- **amplify-util-mock:** include custom resolver templates ([#2119](https://github.com/aws-amplify/amplify-cli/issues/2119)) ([f7174a7](https://github.com/aws-amplify/amplify-cli/commit/f7174a7)), closes [#2049](https://github.com/aws-amplify/amplify-cli/issues/2049) [#2004](https://github.com/aws-amplify/amplify-cli/issues/2004) -- **amplify-util-mock:** prevent resolver file overwrite in windows ([#2007](https://github.com/aws-amplify/amplify-cli/issues/2007)) ([5b78d25](https://github.com/aws-amplify/amplify-cli/commit/5b78d25)), closes [#2006](https://github.com/aws-amplify/amplify-cli/issues/2006) -- **amplify-util-mock:** support large response from lambda ([#2060](https://github.com/aws-amplify/amplify-cli/issues/2060)) ([60efd28](https://github.com/aws-amplify/amplify-cli/commit/60efd28)) - -### Features - -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e534)) -- **amplify-util-mock:** add support for S3 triggers in local mocking ([#2101](https://github.com/aws-amplify/amplify-cli/issues/2101)) ([ac9a134](https://github.com/aws-amplify/amplify-cli/commit/ac9a134)) - -* Adding Auth on Subscriptions (#2068) ([81c630d](https://github.com/aws-amplify/amplify-cli/commit/81c630d)), closes [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) - -### BREAKING CHANGES - -- If an owner is used in the auth directive it will either be a requirement if it's - the only rule or an optional input if used with other rules -- If an owner is included in the auth directive it will either be a requirement if - it's the only rule or an optional input if used with other rules -- the subscription operations will require an argument if owner is the only auth rule -- Subscriptions will require an argument if an owner is only rule set - If owner & - group rules are owner will be an optional arg - -# 1.0.0 (2019-08-28) - -### Bug Fixes - -- **amplify-util-mock:** handle unsupported data source gracefully ([#1999](https://github.com/aws-amplify/amplify-cli/issues/1999)) ([f7cfe3e](https://github.com/aws-amplify/amplify-cli/commit/f7cfe3e)), closes [#1997](https://github.com/aws-amplify/amplify-cli/issues/1997) -- [#1056](https://github.com/aws-amplify/amplify-cli/issues/1056), dedup environment file reading ([#2088](https://github.com/aws-amplify/amplify-cli/issues/2088)) ([940deaa](https://github.com/aws-amplify/amplify-cli/commit/940deaa)) -- local mock fix ([#1982](https://github.com/aws-amplify/amplify-cli/issues/1982)) ([8ee9029](https://github.com/aws-amplify/amplify-cli/commit/8ee9029)) -- **amplify-util-mock:** include custom resolver templates ([#2119](https://github.com/aws-amplify/amplify-cli/issues/2119)) ([f7174a7](https://github.com/aws-amplify/amplify-cli/commit/f7174a7)), closes [#2049](https://github.com/aws-amplify/amplify-cli/issues/2049) [#2004](https://github.com/aws-amplify/amplify-cli/issues/2004) -- **amplify-util-mock:** prevent resolver file overwrite in windows ([#2007](https://github.com/aws-amplify/amplify-cli/issues/2007)) ([5b78d25](https://github.com/aws-amplify/amplify-cli/commit/5b78d25)), closes [#2006](https://github.com/aws-amplify/amplify-cli/issues/2006) -- **amplify-util-mock:** support large response from lambda ([#2060](https://github.com/aws-amplify/amplify-cli/issues/2060)) ([60efd28](https://github.com/aws-amplify/amplify-cli/commit/60efd28)) - -### Features - -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e534)) -- **amplify-util-mock:** add support for S3 triggers in local mocking ([#2101](https://github.com/aws-amplify/amplify-cli/issues/2101)) ([ac9a134](https://github.com/aws-amplify/amplify-cli/commit/ac9a134)) - -* Adding Auth on Subscriptions (#2068) ([81c630d](https://github.com/aws-amplify/amplify-cli/commit/81c630d)), closes [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#1766](https://github.com/aws-amplify/amplify-cli/issues/1766) [#1043](https://github.com/aws-amplify/amplify-cli/issues/1043) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) [#2068](https://github.com/aws-amplify/amplify-cli/issues/2068) - -### BREAKING CHANGES - -- If an owner is used in the auth directive it will either be a requirement if it's - the only rule or an optional input if used with other rules -- If an owner is included in the auth directive it will either be a requirement if - it's the only rule or an optional input if used with other rules -- the subscription operations will require an argument if owner is the only auth rule -- Subscriptions will require an argument if an owner is only rule set - If owner & - group rules are owner will be an optional arg - -# 0.3.0 (2019-08-13) - -### Bug Fixes - -- local mock fix ([#1982](https://github.com/aws-amplify/amplify-cli/issues/1982)) ([8ee9029](https://github.com/aws-amplify/amplify-cli/commit/8ee9029)) -- **amplify-util-mock:** handle unsupported data source gracefully ([#1999](https://github.com/aws-amplify/amplify-cli/issues/1999)) ([f7cfe3e](https://github.com/aws-amplify/amplify-cli/commit/f7cfe3e)), closes [#1997](https://github.com/aws-amplify/amplify-cli/issues/1997) -- **amplify-util-mock:** prevent resolver file overwrite in windows ([#2007](https://github.com/aws-amplify/amplify-cli/issues/2007)) ([5b78d25](https://github.com/aws-amplify/amplify-cli/commit/5b78d25)), closes [#2006](https://github.com/aws-amplify/amplify-cli/issues/2006) - -### Features - -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e534)) - -# 0.2.0 (2019-08-07) - -### Bug Fixes - -- local mock fix ([#1982](https://github.com/aws-amplify/amplify-cli/issues/1982)) ([8ee9029](https://github.com/aws-amplify/amplify-cli/commit/8ee9029)) - -### Features - -- mock support for API, function and storage ([#1893](https://github.com/aws-amplify/amplify-cli/issues/1893)) ([372e534](https://github.com/aws-amplify/amplify-cli/commit/372e534)) diff --git a/packages/amplify-util-mock/package.json b/packages/amplify-util-mock/package.json deleted file mode 100644 index be13153e4b..0000000000 --- a/packages/amplify-util-mock/package.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "name": "amplify-category-api-util-mock", - "version": "6.5.5", - "description": "Amplify CLI plugin providing local testing", - "repository": { - "type": "git", - "url": "https://github.com/aws-amplify/amplify-category-api.git", - "directory": "packages/amplify-util-mock" - }, - "author": "Amazon Web Services", - "license": "Apache-2.0", - "main": "lib/index.js", - "keywords": [ - "graphql", - "appsync", - "aws" - ], - "private": "true", - "scripts": { - "e2e": "yarn run e2e_v1 && yarn run e2e_v2", - "e2e_v2": "jest --runInBand --forceExit ./src/__e2e_v2__/*.test.ts", - "e2e_v1": "jest --runInBand --forceExit ./src/__e2e__/*.test.ts", - "test": "jest src/__tests__/**/*.test.ts", - "test-watch": "jest --watch", - "build": "tsc", - "watch": "tsc -w", - "clean": "rimraf lib tsconfig.tsbuildinfo", - "velocity": "jest ./src/__tests__/velocity/*.test.ts", - "jest": "jest", - "extract-api": "ts-node ../../scripts/extract-api.ts" - }, - "dependencies": { - "@aws-amplify/amplify-appsync-simulator": "^2.16.4", - "@aws-amplify/amplify-category-function": "^5.7.9", - "@aws-amplify/amplify-provider-awscloudformation": "^8.10.11", - "@hapi/topo": "^5.0.0", - "amplify-category-api-dynamodb-simulator": "2.4.17", - "amplify-codegen": "^4.9.3", - "amplify-storage-simulator": "^1.11.3", - "chokidar": "^3.5.3", - "detect-port": "^1.3.0", - "dotenv": "^8.2.0", - "execa": "^5.1.1", - "fs-extra": "^8.1.0", - "graphql-transformer-common": "4.31.1", - "inquirer": "^7.3.3", - "lodash": "^4.17.21", - "semver": "^7.5.2", - "which": "^2.0.2" - }, - "peerDependencies": { - "@aws-amplify/amplify-cli-core": "^4.3.9", - "@aws-amplify/amplify-environment-parameters": "^1.9.14" - }, - "devDependencies": { - "@aws-amplify/graphql-auth-transformer": "3.6.5", - "@aws-amplify/graphql-function-transformer": "2.1.26", - "@aws-amplify/graphql-index-transformer": "2.4.9", - "@aws-amplify/graphql-maps-to-transformer": "3.4.23", - "@aws-amplify/graphql-model-transformer": "2.11.4", - "@aws-amplify/graphql-relational-transformer": "2.5.11", - "@aws-amplify/graphql-searchable-transformer": "2.7.9", - "@aws-amplify/graphql-transformer-core": "2.9.3", - "@aws-amplify/graphql-transformer-interfaces": "3.10.1", - "@aws-amplify/graphql-transformer-test-utils": "0.5.6", - "@types/detect-port": "^1.3.0", - "@types/lodash": "^4.14.149", - "@types/node": "^12.12.6", - "@types/semver": "^7.5.0", - "@types/which": "^1.3.2", - "amplify-function-plugin-interface": "^1.9.7", - "amplify-nodejs-function-runtime-provider": "^2.5.23", - "aws-appsync": "^4.1.9", - "aws-sdk": "^2.1113.0", - "aws-sdk-mock": "^5.6.2", - "axios": "^1.6.0", - "graphql-auth-transformer": "7.2.82", - "graphql-connection-transformer": "5.2.80", - "graphql-dynamodb-transformer": "7.2.80", - "graphql-function-transformer": "3.3.71", - "graphql-key-transformer": "3.2.80", - "graphql-tag": "^2.10.1", - "graphql-transformer-core": "8.2.13", - "graphql-versioned-transformer": "5.2.80", - "isomorphic-fetch": "^3.0.0", - "jsonwebtoken": "^9.0.0", - "uuid": "^8.3.2", - "ws": "^7.5.7" - }, - "jest": { - "testRunner": "jest-circus/runner", - "preset": "ts-jest", - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, - "collectCoverage": true, - "coverageProvider": "v8", - "collectCoverageFrom": [ - "src/**/*.ts" - ], - "coverageReporters": [ - "clover", - "text" - ], - "reporters": [ - "default", - "jest-junit" - ], - "testURL": "http://localhost/", - "testRegex": "(src/(__tests__|__e2e__|__e2e_v2__)/.*.test.ts)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], - "moduleNameMapper": { - "axios": "axios/dist/node/axios.cjs" - }, - "testEnvironment": "../../FixJestEnvironment.js", - "coveragePathIgnorePatterns": [ - "/__tests__/", - "/lib/", - "/node_modules" - ] - }, - "jest-junit": { - "outputDirectory": "reports/junit/", - "outputName": "js-test-results.xml", - "usePathForSuiteName": "true", - "addFileAttribute": "true" - } -} diff --git a/yarn.lock b/yarn.lock index 187d2e3952..f70a0c1998 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5031,16 +5031,6 @@ enabled "2.0.x" kuler "^2.0.0" -"@discoveryjs/json-ext@^0.5.7": - version "0.5.7" - resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" - integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== - -"@discoveryjs/natural-compare@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@discoveryjs/natural-compare/-/natural-compare-1.1.0.tgz#75f0642ad64701ffa9d42f1d7ada3b83f4e67cf3" - integrity sha512-yuctPJs5lRXoI8LkpVZGAV6n+DKOuEsfpfcIDQ8ZjWHwazqk1QjBc4jMlof0UlZHyUqv4dwsOTooMiAmtzvwXA== - "@es-joy/jsdoccomment@~0.37.0": version "0.37.1" resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.37.1.tgz#fa32a41ba12097452693343e09ad4d26d157aedd" @@ -5341,15 +5331,6 @@ source-map "^0.6.1" write-file-atomic "^3.0.0" -"@jest/types@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" - integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^13.0.0" - "@jest/types@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" @@ -5380,14 +5361,6 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/source-map@^0.3.3": - version "0.3.5" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91" - integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ== - dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" - "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" @@ -6636,13 +6609,6 @@ colors "~1.2.1" string-argv "~0.3.1" -"@samverschueren/stream-to-observable@^0.3.0": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.1.tgz#a21117b19ee9be70c379ec1877537ef2e1c63301" - integrity sha512-c/qwwcHyafOQuVQJj0IlBjf5yYgBI7YPJ77k4fOJYesb41jio65eaJODRUmfYKhTOFBrIZ66kgvGPlNbjuoRdQ== - dependencies: - any-observable "^0.3.0" - "@sigstore/bundle@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@sigstore/bundle/-/bundle-1.1.0.tgz#17f8d813b09348b16eeed66a8cf1c3d6bd3d04f1" @@ -6691,35 +6657,6 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@size-limit/file@6.0.4": - version "6.0.4" - resolved "https://registry.yarnpkg.com/@size-limit/file/-/file-6.0.4.tgz#64681f0e0ec93d69b1d99f0a40bbbcdd2fb7def6" - integrity sha512-SoGUUNEHsZJTDlw6znuMbR0z6apr/NmeEXSFT6iB6gUPyOHIdFtFJpvWeS1vijC7OFQhWHskedB6nBJ6L+bd+A== - dependencies: - semver "7.3.5" - -"@size-limit/preset-small-lib@6.0.4": - version "6.0.4" - resolved "https://registry.yarnpkg.com/@size-limit/preset-small-lib/-/preset-small-lib-6.0.4.tgz#707863bee82c7412b2e7201c301db1de793e7158" - integrity sha512-eMay+Hv/ufJyCUX/pFXa30AiYsjrT/Tjw1G7h7CCNKulbEjAY2rAiEsCQkm+rCNnYoPUgOsWhMYy908J23Qb6Q== - dependencies: - "@size-limit/file" "6.0.4" - "@size-limit/webpack" "6.0.4" - -"@size-limit/webpack@6.0.4": - version "6.0.4" - resolved "https://registry.yarnpkg.com/@size-limit/webpack/-/webpack-6.0.4.tgz#2e23b6a3efb11cb081fb65394d05f218c7051270" - integrity sha512-51rvLztZcvT+Qc5g8FusyC8ZDcpVg7+O1a4hfO2K2XMZV8CFguRN//xMwQXv5q6I1ImUQeyURyiCXIQD24qJYQ== - dependencies: - "@statoscope/webpack-plugin" "^5.17.0" - css-loader "^6.5.0" - css-minimizer-webpack-plugin "^3.0.2" - escape-string-regexp "^4.0.0" - mkdirp "^1.0.4" - nanoid "^3.1.30" - style-loader "^3.3.1" - webpack "^5.61.0" - "@smithy/abort-controller@^2.0.1": version "2.0.12" resolved "https://registry.yarnpkg.com/@smithy/abort-controller/-/abort-controller-2.0.12.tgz#62cd47c81fa1d7d6c2d6fde0c2f54ea89892fb6a" @@ -7967,135 +7904,6 @@ "@smithy/types" "^3.3.0" tslib "^2.6.2" -"@statoscope/extensions@5.14.1": - version "5.14.1" - resolved "https://registry.yarnpkg.com/@statoscope/extensions/-/extensions-5.14.1.tgz#b7c32b39de447da76b9fa2daada61b2f699754e6" - integrity sha512-5O31566+bOkkdYFH81mGGBTh0YcU0zoYurTrsK5uZfpNY87ZCPpptrszX8npTRHNsxbjBBNt7vAwImJyYdhzLw== - -"@statoscope/helpers@5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@statoscope/helpers/-/helpers-5.28.0.tgz#ecc5826495fa7aec79e0039cc13bcfe9caa0bc85" - integrity sha512-OpLYiDfIofnrCflooKfHj+DuzxXSID435ekdwZfFR8kHZhM6fziQAwZSzcEMgKtWhRKHpah7q8pnlTE/l++zLw== - dependencies: - "@types/archy" "^0.0.32" - "@types/semver" "^7.3.10" - archy "~1.0.0" - jora "1.0.0-beta.8" - semver "^7.3.7" - -"@statoscope/report-writer@5.27.0": - version "5.27.0" - resolved "https://registry.yarnpkg.com/@statoscope/report-writer/-/report-writer-5.27.0.tgz#528b980b9ba761925e520f93f59f485053bc10e2" - integrity sha512-h4Xyy2JFmaDUXBwevC6w5BI86OU0ZMYNyhty5AguWHRUAifOhEfemLHdvz/RJQ9gVjnqZ135omAtHaq6JMersw== - dependencies: - "@discoveryjs/json-ext" "^0.5.7" - "@types/pako" "^2.0.0" - pako "^2.0.4" - -"@statoscope/stats-extension-compressed@5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@statoscope/stats-extension-compressed/-/stats-extension-compressed-5.28.0.tgz#b6b1b9e0ed00bc6349d232b9c279ba0738b198ea" - integrity sha512-94pAKXjHDg6tPVF1rcDypVemw/NZPujNJmLAzNT6PDNd0HVpftqQ/U8MjeXffyYZEgTDk/AfAApc0vWDulfD8A== - dependencies: - "@statoscope/helpers" "5.28.0" - gzip-size "^6.0.0" - -"@statoscope/stats-extension-custom-reports@5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@statoscope/stats-extension-custom-reports/-/stats-extension-custom-reports-5.28.0.tgz#ef86460427866892ab63059c026fb82cbe897569" - integrity sha512-l8BU9w86AbII5E6qij5KfRUheZ8lhCli2wnujojP95oS0xu/E721B6AlXqwz2/5r3fulgSsM9IaeEaUeAhg9Ag== - dependencies: - "@statoscope/extensions" "5.14.1" - "@statoscope/helpers" "5.28.0" - "@statoscope/stats" "5.14.1" - "@statoscope/types" "5.27.0" - -"@statoscope/stats-extension-package-info@5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@statoscope/stats-extension-package-info/-/stats-extension-package-info-5.28.0.tgz#10895b21b7b1fd2be6e701fb3968de2e16808751" - integrity sha512-80Kp+9wK6/m/yM+2MjC6ExroFbVPIFBOk+RdrWVshEKPzA0f4cXlfQsOjt8vhxjMuEzyWyQQjau6AzgmcpFwkA== - dependencies: - "@statoscope/helpers" "5.28.0" - -"@statoscope/stats-extension-stats-validation-result@5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@statoscope/stats-extension-stats-validation-result/-/stats-extension-stats-validation-result-5.28.0.tgz#6bef6b91a01901bd041b4cefd857682d4d102f4f" - integrity sha512-AOL8uxjvSxeCiP3dL+F2NXxqtkTvmnfxQiK8O3hpVHrP/JFR1mOf3lkCSeRO09COG4/fAFlqM/pWpwzbATfqhA== - dependencies: - "@statoscope/extensions" "5.14.1" - "@statoscope/helpers" "5.28.0" - "@statoscope/stats" "5.14.1" - "@statoscope/types" "5.27.0" - -"@statoscope/stats@5.14.1": - version "5.14.1" - resolved "https://registry.yarnpkg.com/@statoscope/stats/-/stats-5.14.1.tgz#728656629bc06aa4bf5634398662ac05287793d5" - integrity sha512-Kz7kCKuT6DXaqAPfyTwp27xHMDUna9o6UlRSQXXBZ8Yyk7eYYvTNw+5ffRyqivL9IOzD7FQYDQ6VUBHh0UfyDw== - -"@statoscope/types@5.27.0": - version "5.27.0" - resolved "https://registry.yarnpkg.com/@statoscope/types/-/types-5.27.0.tgz#b58b0c1e9a0a0c831bd2a6ee2b564d175ebb856f" - integrity sha512-3BWUmpoRRHU/b6NiHqnFjDeKBAjrUiFVsZPPZONFeOtHlfRI1CoVeVkmPocCQHuk7JyTWuiEaOT5OBycOYlExg== - dependencies: - "@statoscope/stats" "5.14.1" - -"@statoscope/webpack-model@5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@statoscope/webpack-model/-/webpack-model-5.28.0.tgz#6b7f410050a86f3480e89f73d75eb9c7c01ebdc8" - integrity sha512-xp7DDrlfeZsZTQyCkf6lKnK08lYMBJdTpDxXoYPC5guv47Jqfi0szYE+ItNIFMRT09dEtdFZZttgFY5lr9pfXA== - dependencies: - "@statoscope/extensions" "5.14.1" - "@statoscope/helpers" "5.28.0" - "@statoscope/stats" "5.14.1" - "@statoscope/stats-extension-compressed" "5.28.0" - "@statoscope/stats-extension-custom-reports" "5.28.0" - "@statoscope/stats-extension-package-info" "5.28.0" - "@statoscope/stats-extension-stats-validation-result" "5.28.0" - "@statoscope/types" "5.27.0" - md5 "^2.3.0" - -"@statoscope/webpack-plugin@^5.17.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@statoscope/webpack-plugin/-/webpack-plugin-5.28.0.tgz#6bdd58ddc812734b3c014c363927532e0e9672de" - integrity sha512-RWPicoOnlLnnXIp6x6C8ZEFqINa3vGQHhVFJ70HGpjGfl7h85TkLmC6yf7J1OZzFQJEWWMSlJXlRM8F7xA6nFQ== - dependencies: - "@discoveryjs/json-ext" "^0.5.7" - "@statoscope/report-writer" "5.27.0" - "@statoscope/stats" "5.14.1" - "@statoscope/stats-extension-compressed" "5.28.0" - "@statoscope/stats-extension-custom-reports" "5.28.0" - "@statoscope/types" "5.27.0" - "@statoscope/webpack-model" "5.28.0" - "@statoscope/webpack-stats-extension-compressed" "5.28.0" - "@statoscope/webpack-stats-extension-package-info" "5.28.0" - "@statoscope/webpack-ui" "5.28.0" - open "^8.4.0" - -"@statoscope/webpack-stats-extension-compressed@5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@statoscope/webpack-stats-extension-compressed/-/webpack-stats-extension-compressed-5.28.0.tgz#e1147ec6a5a69ac3fae47dd9db98f968e976271a" - integrity sha512-V7mVK5Raxbm5ihcbNUdgrCII7S2QjsU3YlzrEHOfL6xaWabfH4afWKZ3dFMlzwFMeeTayRiujK0lEQzDSWAWQw== - dependencies: - "@statoscope/stats" "5.14.1" - "@statoscope/stats-extension-compressed" "5.28.0" - "@statoscope/webpack-model" "5.28.0" - -"@statoscope/webpack-stats-extension-package-info@5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@statoscope/webpack-stats-extension-package-info/-/webpack-stats-extension-package-info-5.28.0.tgz#afea114533aa7a837b07a77caba0228e2ca65fa1" - integrity sha512-4VqCPkj3oyiOzr8UbcR6eeqgrptNGNfHVNXOAhSYzhKpspF7WnMPQjRMyXQahs8r7UPrZdV9rzTD0/wLPGlHJQ== - dependencies: - "@statoscope/stats" "5.14.1" - "@statoscope/stats-extension-package-info" "5.28.0" - "@statoscope/webpack-model" "5.28.0" - -"@statoscope/webpack-ui@5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@statoscope/webpack-ui/-/webpack-ui-5.28.0.tgz#614c22465a7a35030c9f35edb1d6dc0385d87b6c" - integrity sha512-I5ttBHmhDvxZ6dNqqfErUIzoFk1N3vXD9k6nwwYqtkAqzwCYvA30RKs/ON+8GXUtVGR4F9YzR7De3uam0U9wmQ== - dependencies: - "@statoscope/types" "5.27.0" - "@szmarczak/http-timer@^5.0.1": version "5.0.1" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-5.0.1.tgz#c7c1bf1141cdd4751b0399c8fc7b8b664cd5be3a" @@ -8118,11 +7926,6 @@ resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c" integrity sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA== -"@trysound/sax@0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" - integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== - "@tsconfig/node10@^1.0.7": version "1.0.9" resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" @@ -8176,11 +7979,6 @@ dependencies: "@turf/helpers" "^6.5.0" -"@types/archy@^0.0.32": - version "0.0.32" - resolved "https://registry.yarnpkg.com/@types/archy/-/archy-0.0.32.tgz#8b572741dad9172dfbf289397af1bb41296d3e40" - integrity sha512-5ZZ5+YGmUE01yejiXsKnTcvhakMZ2UllZlMsQni53Doc1JWhe21ia8VntRoRD6fAEWw08JBh/z9qQHJ+//MrIg== - "@types/argparse@1.0.38": version "1.0.38" resolved "https://registry.yarnpkg.com/@types/argparse/-/argparse-1.0.38.tgz#a81fd8606d481f873a3800c6ebae4f1d768a56a9" @@ -8234,27 +8032,6 @@ resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.3.3.tgz#85bc74ba782fb7aa3a514d11767832b0e3bc6803" integrity sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow== -"@types/eslint-scope@^3.7.3": - version "3.7.5" - resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.5.tgz#e28b09dbb1d9d35fdfa8a884225f00440dfc5a3e" - integrity sha512-JNvhIEyxVW6EoMIFIvj93ZOywYFatlpu9deeH6eSx6PE3WHYvHaQtmHmQeNw7aA81bYGBPPQqdtBm6b1SsQMmA== - dependencies: - "@types/eslint" "*" - "@types/estree" "*" - -"@types/eslint@*": - version "8.44.4" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.4.tgz#28eaff82e1ca0a96554ec5bb0188f10ae1a74c2f" - integrity sha512-lOzjyfY/D9QR4hY9oblZ76B90MYTB3RrQ4z2vBIJKj9ROCRqdkYl2gSUx1x1a4IWPjKJZLL4Aw1Zfay7eMnmnA== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - -"@types/estree@*", "@types/estree@^1.0.0": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.2.tgz#ff02bc3dc8317cd668dfec247b750ba1f1d62453" - integrity sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA== - "@types/fs-extra@^8.0.1": version "8.1.3" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.1.3.tgz#4807768c0b0a5a5f4746d8fde2f7ab0137076eea" @@ -8312,14 +8089,6 @@ dependencies: "@types/istanbul-lib-coverage" "*" -"@types/istanbul-reports@^1.1.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" - integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== - dependencies: - "@types/istanbul-lib-coverage" "*" - "@types/istanbul-lib-report" "*" - "@types/istanbul-reports@^3.0.0": version "3.0.2" resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.2.tgz#edc8e421991a3b4df875036d381fc0a5a982f549" @@ -8327,13 +8096,6 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^24.0.18": - version "24.9.1" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.9.1.tgz#02baf9573c78f1b9974a5f36778b366aa77bd534" - integrity sha512-Fb38HkXSVA4L8fGKEZ6le5bB8r6MRWlOCZbVuWZcmOMSCd2wCYOwN1ibj8daIoV9naq7aaOZjrLCoCMptKU/4Q== - dependencies: - jest-diff "^24.3.0" - "@types/jest@^26.0.20": version "26.0.24" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.24.tgz#943d11976b16739185913a1936e0de0c4a7d595a" @@ -8347,7 +8109,7 @@ resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.7.tgz#f11c2ec37bb748fa5cfa3262abcb8b1cfd83d8ae" integrity sha512-RJZP9WAMMr1514KbdSXkLRrKvYQacjr1+HWnY8pui/uBTBoSgD9ZGR17u/d4nb9NpERp0FkdLBe7hq8NIPBgkg== -"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": +"@types/json-schema@^7.0.5", "@types/json-schema@^7.0.9": version "7.0.13" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.13.tgz#02c24f4363176d2d18fc8b70b9f3c54aba178a85" integrity sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ== @@ -8428,11 +8190,6 @@ resolved "https://registry.yarnpkg.com/@types/object-hash/-/object-hash-2.2.1.tgz#67c169f8f033e0b62abbf81df2d00f4598d540b9" integrity sha512-i/rtaJFCsPljrZvP/akBqEwUP2y5cZLOmvO+JaYnz01aPknrQ+hB5MRcO7iqCUsFaYfTG8kGfKUyboA07xeDHQ== -"@types/pako@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/pako/-/pako-2.0.1.tgz#99e4b7ae6a8560c5928d7f31e89a394e1e6fd169" - integrity sha512-fXhui1fHdLrUR0KEyQsBzqdi3Z+MitnRcpI2eeFJyzaRdqO2miX/BDz2Hh0VdkBbrWprgcQ+ItFmbdKYdbMjvg== - "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" @@ -8448,7 +8205,7 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== -"@types/semver@^7.3.10", "@types/semver@^7.3.12": +"@types/semver@^7.3.12": version "7.5.3" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.3.tgz#9a726e116beb26c24f1ccd6850201e1246122e04" integrity sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw== @@ -8480,13 +8237,6 @@ resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.1.tgz#07773d7160494d56aa882d7531aac7319ea67c3b" integrity sha512-axdPBuLuEJt0c4yI5OZssC19K2Mq1uKdrfZBzuxLvaztgqUtFYZUNw7lETExPYJR9jdEoIg4mb7RQKRQzOkeGQ== -"@types/yargs@^13.0.0": - version "13.0.12" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.12.tgz#d895a88c703b78af0465a9de88aa92c61430b092" - integrity sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ== - dependencies: - "@types/yargs-parser" "*" - "@types/yargs@^15.0.0": version "15.0.16" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.16.tgz#258009dc52907e8f03041eb64ffdac297ba4b208" @@ -8588,127 +8338,6 @@ "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" -"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" - integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q== - dependencies: - "@webassemblyjs/helper-numbers" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - -"@webassemblyjs/floating-point-hex-parser@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" - integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== - -"@webassemblyjs/helper-api-error@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" - integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== - -"@webassemblyjs/helper-buffer@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093" - integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA== - -"@webassemblyjs/helper-numbers@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" - integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== - dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.6" - "@webassemblyjs/helper-api-error" "1.11.6" - "@xtuc/long" "4.2.2" - -"@webassemblyjs/helper-wasm-bytecode@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" - integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== - -"@webassemblyjs/helper-wasm-section@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577" - integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-buffer" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/wasm-gen" "1.11.6" - -"@webassemblyjs/ieee754@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" - integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== - dependencies: - "@xtuc/ieee754" "^1.2.0" - -"@webassemblyjs/leb128@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" - integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== - dependencies: - "@xtuc/long" "4.2.2" - -"@webassemblyjs/utf8@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" - integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== - -"@webassemblyjs/wasm-edit@^1.11.5": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab" - integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-buffer" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/helper-wasm-section" "1.11.6" - "@webassemblyjs/wasm-gen" "1.11.6" - "@webassemblyjs/wasm-opt" "1.11.6" - "@webassemblyjs/wasm-parser" "1.11.6" - "@webassemblyjs/wast-printer" "1.11.6" - -"@webassemblyjs/wasm-gen@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268" - integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - -"@webassemblyjs/wasm-opt@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2" - integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-buffer" "1.11.6" - "@webassemblyjs/wasm-gen" "1.11.6" - "@webassemblyjs/wasm-parser" "1.11.6" - -"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1" - integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-api-error" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - -"@webassemblyjs/wast-printer@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20" - integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@xtuc/long" "4.2.2" - "@wry/equality@^0.1.2": version "0.1.11" resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.1.11.tgz#35cb156e4a96695aa81a9ecc4d03787bc17f1790" @@ -8721,16 +8350,6 @@ resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99" integrity sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw== -"@xtuc/ieee754@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" - integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== - -"@xtuc/long@4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" - integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== - "@yarnpkg/lockfile@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" @@ -8794,11 +8413,6 @@ acorn-globals@^6.0.0: acorn "^7.1.1" acorn-walk "^7.1.1" -acorn-import-assertions@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" - integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== - acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -8819,7 +8433,7 @@ acorn@^7.1.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.2.4, acorn@^8.4.1, acorn@^8.7.1, acorn@^8.8.2, acorn@^8.9.0: +acorn@^8.2.4, acorn@^8.4.1, acorn@^8.9.0: version "8.10.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== @@ -8858,26 +8472,12 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv-formats@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" - integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== - dependencies: - ajv "^8.0.0" - ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv-keywords@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" - integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== - dependencies: - fast-deep-equal "^3.1.3" - -ajv@^6.12.4, ajv@^6.12.5, ajv@^6.12.6, ajv@~6.12.6: +ajv@^6.12.4, ajv@^6.12.6, ajv@~6.12.6: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -8887,7 +8487,7 @@ ajv@^6.12.4, ajv@^6.12.5, ajv@^6.12.6, ajv@~6.12.6: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0, ajv@^8.0.1, ajv@^8.12.0, ajv@^8.9.0: +ajv@^8.0.1, ajv@^8.12.0: version "8.12.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== @@ -8942,7 +8542,7 @@ ansi-colors@^4.1.1: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== -ansi-escapes@^3.0.0, ansi-escapes@^3.2.0: +ansi-escapes@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== @@ -8961,17 +8561,12 @@ ansi-escapes@^5.0.0: dependencies: type-fest "^1.0.2" -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== - ansi-regex@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== -ansi-regex@^4.0.0, ansi-regex@^4.1.0: +ansi-regex@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== @@ -8986,12 +8581,7 @@ ansi-regex@^6.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA== - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -9010,11 +8600,6 @@ ansi-styles@^6.0.0, ansi-styles@^6.1.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== -any-observable@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" - integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog== - anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -9195,11 +8780,6 @@ archiver@^5.3.0: tar-stream "^2.2.0" zip-stream "^4.1.0" -archy@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" - integrity sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw== - are-we-there-yet@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd" @@ -9805,7 +9385,7 @@ browser-process-hrtime@^1.0.0: resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== -browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.21.4, browserslist@^4.21.9: +browserslist@^4.21.9: version "4.22.1" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.1.tgz#ba91958d1a59b87dab6fed8dfbcb3da5e2e9c619" integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ== @@ -9886,11 +9466,6 @@ byte-size@^7.0.0: resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-7.0.1.tgz#b1daf3386de7ab9d706b941a748dbfc71130dee3" integrity sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A== -bytes-iec@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/bytes-iec/-/bytes-iec-3.1.1.tgz#94cd36bf95c2c22a82002c247df8772d1d591083" - integrity sha512-fey6+4jDK7TFtFg/klGSvNKJctyU7n2aQdnM+CO0ruLPbqqMOM8Tio0Pc+deqUeVKX1tL5DQep1zQ7+37aTAsA== - bytes@3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -10027,17 +9602,7 @@ camelcase@^7.0.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-7.0.1.tgz#f02e50af9fd7782bc8b88a3558c32fd3a388f048" integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw== -caniuse-api@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" - integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== - dependencies: - browserslist "^4.0.0" - caniuse-lite "^1.0.0" - lodash.memoize "^4.1.2" - lodash.uniq "^4.5.0" - -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001541: +caniuse-lite@^1.0.30001541: version "1.0.30001547" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001547.tgz#d4f92efc488aab3c7f92c738d3977c2a3180472b" integrity sha512-W7CrtIModMAxobGhz8iXmDfuJiiKg1WADMO/9x7/CLNin5cpSbuBjooyoIUVB5eyCc36QuTVlkVa1iB2S5+/eA== @@ -10059,18 +9624,7 @@ chalk@5.3.0, chalk@^5.0.1, chalk@^5.2.0, chalk@^5.3.0: resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== -chalk@^1.0.0, chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A== - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.1, chalk@^2.4.1, chalk@^2.4.2: +chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -10110,7 +9664,7 @@ charenc@0.0.2, charenc@^0.0.2: resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== -chokidar@^3.4.0, chokidar@^3.5.2: +chokidar@^3.4.0: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -10135,11 +9689,6 @@ chownr@^2.0.0: resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== -chrome-trace-event@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" - integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== - ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" @@ -10150,11 +9699,6 @@ ci-info@^3.2.0, ci-info@^3.8.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== -ci-job-number@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/ci-job-number/-/ci-job-number-1.2.2.tgz#f4e5918fcaeeda95b604f214be7d7d4a961fe0c0" - integrity sha512-CLOGsVDrVamzv8sXJGaILUVI6dsuAkouJP/n6t+OxLPeeA4DDby7zn9SB6EUpa1H7oIKoE+rMmkW80zYsFfUjA== - circleci-api@^4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/circleci-api/-/circleci-api-4.1.4.tgz#6880a28eb021879d81789b50996640dc6373c5ad" @@ -10194,7 +9738,7 @@ cli-cursor@3.1.0, cli-cursor@^3.1.0: dependencies: restore-cursor "^3.1.0" -cli-cursor@^2.0.0, cli-cursor@^2.1.0: +cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" integrity sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw== @@ -10227,14 +9771,6 @@ cli-table3@^0.6.0, cli-table3@^0.6.3: optionalDependencies: "@colors/colors" "1.5.0" -cli-truncate@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" - integrity sha512-f4r4yJnbT++qUPI9NR4XLDLq41gQ+uqnPItWG0F5ZkehuNiTTa3EY0S4AqTSUOeJ7/zU41oWPQSNkW5BqPL9bg== - dependencies: - slice-ansi "0.0.4" - string-width "^1.0.1" - cli-truncate@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389" @@ -10321,11 +9857,6 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== - codecov@^3.7.0: version "3.8.3" resolved "https://registry.npmjs.org/codecov/-/codecov-3.8.3.tgz#9c3e364b8a700c597346ae98418d09880a3fdbe7" @@ -10404,11 +9935,6 @@ color@^3.1.3: color-convert "^1.9.3" color-string "^1.6.0" -colord@^2.9.1: - version "2.9.3" - resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" - integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== - colorette@2.0.19: version "2.0.19" resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" @@ -10462,21 +9988,11 @@ commander@^10.0.0, commander@^10.0.1: resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== -commander@^2.20.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - commander@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== -commander@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== - commander@^9.1.0: version "9.5.0" resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" @@ -10825,122 +10341,6 @@ crypto-random-string@^4.0.0: dependencies: type-fest "^1.0.1" -css-declaration-sorter@^6.3.1: - version "6.4.1" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz#28beac7c20bad7f1775be3a7129d7eae409a3a71" - integrity sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g== - -css-loader@^6.5.0: - version "6.8.1" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.8.1.tgz#0f8f52699f60f5e679eab4ec0fcd68b8e8a50a88" - integrity sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g== - dependencies: - icss-utils "^5.1.0" - postcss "^8.4.21" - postcss-modules-extract-imports "^3.0.0" - postcss-modules-local-by-default "^4.0.3" - postcss-modules-scope "^3.0.0" - postcss-modules-values "^4.0.0" - postcss-value-parser "^4.2.0" - semver "^7.3.8" - -css-minimizer-webpack-plugin@^3.0.2: - version "3.4.1" - resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz#ab78f781ced9181992fe7b6e4f3422e76429878f" - integrity sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q== - dependencies: - cssnano "^5.0.6" - jest-worker "^27.0.2" - postcss "^8.3.5" - schema-utils "^4.0.0" - serialize-javascript "^6.0.0" - source-map "^0.6.1" - -css-select@^4.1.3: - version "4.3.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b" - integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== - dependencies: - boolbase "^1.0.0" - css-what "^6.0.1" - domhandler "^4.3.1" - domutils "^2.8.0" - nth-check "^2.0.1" - -css-tree@^1.1.2, css-tree@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" - integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== - dependencies: - mdn-data "2.0.14" - source-map "^0.6.1" - -css-what@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" - integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== - -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - -cssnano-preset-default@^5.2.14: - version "5.2.14" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz#309def4f7b7e16d71ab2438052093330d9ab45d8" - integrity sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A== - dependencies: - css-declaration-sorter "^6.3.1" - cssnano-utils "^3.1.0" - postcss-calc "^8.2.3" - postcss-colormin "^5.3.1" - postcss-convert-values "^5.1.3" - postcss-discard-comments "^5.1.2" - postcss-discard-duplicates "^5.1.0" - postcss-discard-empty "^5.1.1" - postcss-discard-overridden "^5.1.0" - postcss-merge-longhand "^5.1.7" - postcss-merge-rules "^5.1.4" - postcss-minify-font-values "^5.1.0" - postcss-minify-gradients "^5.1.1" - postcss-minify-params "^5.1.4" - postcss-minify-selectors "^5.2.1" - postcss-normalize-charset "^5.1.0" - postcss-normalize-display-values "^5.1.0" - postcss-normalize-positions "^5.1.1" - postcss-normalize-repeat-style "^5.1.1" - postcss-normalize-string "^5.1.0" - postcss-normalize-timing-functions "^5.1.0" - postcss-normalize-unicode "^5.1.1" - postcss-normalize-url "^5.1.0" - postcss-normalize-whitespace "^5.1.1" - postcss-ordered-values "^5.1.3" - postcss-reduce-initial "^5.1.2" - postcss-reduce-transforms "^5.1.0" - postcss-svgo "^5.1.0" - postcss-unique-selectors "^5.1.1" - -cssnano-utils@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-3.1.0.tgz#95684d08c91511edfc70d2636338ca37ef3a6861" - integrity sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA== - -cssnano@^5.0.6: - version "5.1.15" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.15.tgz#ded66b5480d5127fcb44dac12ea5a983755136bf" - integrity sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw== - dependencies: - cssnano-preset-default "^5.2.14" - lilconfig "^2.0.3" - yaml "^1.10.2" - -csso@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" - integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== - dependencies: - css-tree "^1.1.2" - cssom@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" @@ -10992,11 +10392,6 @@ dataloader@^2.0.0: resolved "https://registry.npmjs.org/dataloader/-/dataloader-2.2.2.tgz#216dc509b5abe39d43a9b9d97e6e5e473dfbe3e0" integrity sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g== -date-fns@^1.27.2: - version "1.30.1" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" - integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== - date-format@^4.0.14: version "4.0.14" resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.14.tgz#7a8e584434fb169a521c8b7aa481f355810d9400" @@ -11159,20 +10554,6 @@ degenerator@^5.0.0: escodegen "^2.1.0" esprima "^4.0.1" -del@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/del/-/del-5.1.0.tgz#d9487c94e367410e6eff2925ee58c0c84a75b3a7" - integrity sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA== - dependencies: - globby "^10.0.1" - graceful-fs "^4.2.2" - is-glob "^4.0.1" - is-path-cwd "^2.2.0" - is-path-inside "^3.0.1" - p-map "^3.0.0" - rimraf "^3.0.0" - slash "^3.0.0" - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -11241,11 +10622,6 @@ dezalgo@^1.0.0: asap "^2.0.0" wrappy "1" -diff-sequences@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5" - integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew== - diff-sequences@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" @@ -11277,20 +10653,6 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -dom-serializer@^1.0.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30" - integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag== - dependencies: - domelementtype "^2.0.1" - domhandler "^4.2.0" - entities "^2.0.0" - -domelementtype@^2.0.1, domelementtype@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" - integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== - domexception@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" @@ -11298,22 +10660,6 @@ domexception@^2.0.1: dependencies: webidl-conversions "^5.0.0" -domhandler@^4.2.0, domhandler@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" - integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== - dependencies: - domelementtype "^2.2.0" - -domutils@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" - integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== - dependencies: - dom-serializer "^1.0.1" - domelementtype "^2.2.0" - domhandler "^4.2.0" - dot-prop@^5.1.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" @@ -11347,7 +10693,7 @@ downlevel-dts@^0.11.0: shelljs "^0.8.3" typescript next -duplexer@^0.1.1, duplexer@^0.1.2: +duplexer@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== @@ -11374,11 +10720,6 @@ electron-to-chromium@^1.4.535: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.550.tgz#8a56ff5a8597f486d2972a653b0852945fc7a9c3" integrity sha512-LfcsAzGj18xBYFM5WetwNQdqA03iLDozfCo0SWpu5G9zA5H1G/2GOiHOVnQdOrqaZ8vI8IiSgS3JMUrq930zsw== -elegant-spinner@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" - integrity sha512-B+ZM+RXvRqQaAmkMlO/oSe5nMUOaUnyfGYCEHoR8wrXsZR2mA0XVibsxV1bvTwxdRWah1PkQqso2EzhILGHtEQ== - emittery@^0.7.1: version "0.7.2" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" @@ -11423,14 +10764,6 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" -enhanced-resolve@^5.15.0: - version "5.15.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" - integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - enquirer@^2.3.6: version "2.4.1" resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" @@ -11446,7 +10779,7 @@ enquirer@~2.3.6: dependencies: ansi-colors "^4.1.1" -entities@2.2.0, entities@^2.0.0: +entities@2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== @@ -11543,11 +10876,6 @@ es-iterator-helpers@^1.0.12: iterator.prototype "^1.1.2" safe-array-concat "^1.0.1" -es-module-lexer@^1.2.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.3.1.tgz#c1b0dd5ada807a3b3155315911f364dc4e909db1" - integrity sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q== - es-set-tostringtag@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" @@ -11588,7 +10916,7 @@ escape-html@~1.0.3: resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== @@ -11747,7 +11075,7 @@ eslint-plugin-spellcheck@^0.0.17: hunspell-spellchecker "^1.0.2" lodash "^4.17.15" -eslint-scope@5.1.1, eslint-scope@^5.1.1: +eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -11884,7 +11212,7 @@ events@1.1.1: resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" integrity sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw== -events@3.3.0, events@^3.1.0, events@^3.2.0: +events@3.3.0, events@^3.1.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== @@ -11922,21 +11250,6 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -execa@^2.0.3: - version "2.1.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-2.1.0.tgz#e5d3ecd837d2a60ec50f3da78fd39767747bbe99" - integrity sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw== - dependencies: - cross-spawn "^7.0.0" - get-stream "^5.0.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^3.0.0" - onetime "^5.1.0" - p-finally "^2.0.0" - signal-exit "^3.0.2" - strip-final-newline "^2.0.0" - execa@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" @@ -12103,7 +11416,7 @@ fast-glob@3.2.7: merge2 "^1.3.0" micromatch "^4.0.4" -fast-glob@^3.0.3, fast-glob@^3.2.9, fast-glob@^3.3.1: +fast-glob@^3.2.9, fast-glob@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== @@ -12193,14 +11506,6 @@ figures@3.2.0, figures@^3.0.0: dependencies: escape-string-regexp "^1.0.5" -figures@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" - integrity sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ== - dependencies: - escape-string-regexp "^1.0.5" - object-assign "^4.1.0" - figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -12538,11 +11843,6 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@ has-proto "^1.0.1" has-symbols "^1.0.3" -get-own-enumerable-property-symbols@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" - integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== - get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -12688,11 +11988,6 @@ glob-promise@^6.0.3: dependencies: "@types/glob" "^8.0.0" -glob-to-regexp@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" - integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== - glob@7.1.4: version "7.1.4" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" @@ -12772,20 +12067,6 @@ globalthis@^1.0.3: dependencies: define-properties "^1.1.3" -globby@^10.0.1: - version "10.0.2" - resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543" - integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg== - dependencies: - "@types/glob" "^7.1.1" - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.0.3" - glob "^7.1.3" - ignore "^5.1.1" - merge2 "^1.2.3" - slash "^3.0.0" - globby@^11.0.1, globby@^11.0.2, globby@^11.0.3, globby@^11.0.4, globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -12827,7 +12108,7 @@ graceful-fs@4.2.10: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.10, graceful-fs@^4.2.11, graceful-fs@^4.2.2, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.10, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.6: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -12902,13 +12183,6 @@ growly@^1.3.0: resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw== -gzip-size@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" - integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q== - dependencies: - duplexer "^0.1.2" - handlebars@^4.7.7: version "4.7.8" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" @@ -12926,13 +12200,6 @@ hard-rejection@^2.1.0: resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg== - dependencies: - ansi-regex "^2.0.0" - has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" @@ -13192,11 +12459,6 @@ iconv-lite@^0.6.2, iconv-lite@^0.6.3: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -icss-utils@^5.0.0, icss-utils@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" - integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== - idb@5.0.6: version "5.0.6" resolved "https://registry.yarnpkg.com/idb/-/idb-5.0.6.tgz#8c94624f5a8a026abe3bef3c7166a5febd1cadc1" @@ -13233,7 +12495,7 @@ ignore-walk@^6.0.0: dependencies: minimatch "^9.0.0" -ignore@^5.0.4, ignore@^5.1.1, ignore@^5.2.0: +ignore@^5.0.4, ignore@^5.2.0: version "5.2.4" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== @@ -13297,11 +12559,6 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== -indent-string@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" - integrity sha512-BYqTHXTGUIvg7t1r4sJNKcbDZkL92nkXA8YtRpbjFHRHGDL/NtUeiBJMeE60kIFN/Mg8ESaWQvftaYMGJzQZCQ== - indent-string@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" @@ -13645,13 +12902,6 @@ is-finalizationregistry@^1.0.2: dependencies: call-bind "^1.0.2" -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== - dependencies: - number-is-nan "^1.0.0" - is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" @@ -13679,7 +12929,7 @@ is-generator-function@^1.0.10, is-generator-function@^1.0.7: dependencies: has-tostringtag "^1.0.0" -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -13738,29 +12988,12 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - integrity sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg== - is-obj@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== -is-observable@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-observable/-/is-observable-1.1.0.tgz#b3e986c8f44de950867cab5403f5a3465005975e" - integrity sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA== - dependencies: - symbol-observable "^1.1.0" - -is-path-cwd@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" - integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== - -is-path-inside@^3.0.1, is-path-inside@^3.0.2, is-path-inside@^3.0.3: +is-path-inside@^3.0.2, is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== @@ -13792,11 +13025,6 @@ is-potential-custom-element-name@^1.0.1: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== -is-promise@^2.1.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" - integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== - is-property@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" @@ -13810,11 +13038,6 @@ is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" - integrity sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA== - is-set@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" @@ -14138,16 +13361,6 @@ jest-config@^26.6.3: micromatch "^4.0.2" pretty-format "^26.6.2" -jest-diff@^24.3.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da" - integrity sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ== - dependencies: - chalk "^2.0.1" - diff-sequences "^24.9.0" - jest-get-type "^24.9.0" - pretty-format "^24.9.0" - jest-diff@^26.0.0, jest-diff@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" @@ -14176,7 +13389,7 @@ jest-each@^26.6.2: jest-util "^26.6.2" pretty-format "^26.6.2" -jest-environment-jsdom@26.6.2, jest-environment-jsdom@^26.6.2, jest-environment-jsdom@^29.3.1: +jest-environment-jsdom@26.6.2, jest-environment-jsdom@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== @@ -14201,11 +13414,6 @@ jest-environment-node@26.6.2, jest-environment-node@^26.6.2: jest-mock "^26.6.2" jest-util "^26.6.2" -jest-get-type@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e" - integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q== - jest-get-type@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" @@ -14475,16 +13683,7 @@ jest-worker@^26.6.2: merge-stream "^2.0.0" supports-color "^7.0.0" -jest-worker@^27.0.2, jest-worker@^27.4.5: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" - integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -jest@26.6.2, jest@^26.6.2, jest@^29.0.0: +jest@26.6.2, jest@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.2.tgz#d116f55438129360f523c22b5cf010f88740272d" integrity sha512-lL0hW7mh/2hhQmpo/1fDWQji/BUB3Xcxxj7r0fAOa3t56OAnwbE0HEl2bZ7XjAwV5TXOt8UpCgaa/WBJBB0CYw== @@ -14503,13 +13702,6 @@ jmespath@0.16.0: resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.16.0.tgz#b15b0a85dfd4d930d43e69ed605943c802785076" integrity sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw== -jora@1.0.0-beta.8: - version "1.0.0-beta.8" - resolved "https://registry.yarnpkg.com/jora/-/jora-1.0.0-beta.8.tgz#e50a4c1493cd3392b4fe6f390b63cb460ef3b3cb" - integrity sha512-f3WpYwfDTlhfSdyCkAlAXSKRpwZYBgCDnyWmA9D0yyItCTFnFefKtvFpaczrj/FItkgDkHiewgFuHsgh4TmokA== - dependencies: - "@discoveryjs/natural-compare" "^1.0.0" - js-cookie@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" @@ -14962,7 +14154,7 @@ libphonenumber-js@1.9.47: resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.9.47.tgz#0cb3d6a3dd8d917d364da48a5355bc3b1d145f5b" integrity sha512-FIWFLJ2jUJi8SCztgd2k/isQHZedh7xuxOVifqFLwG/ogZtdH9TXFK92w/KWFj1lwoadqVedtLO3Jqp0q67PZw== -lilconfig@2.1.0, lilconfig@^2.0.3: +lilconfig@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== @@ -14993,55 +14185,6 @@ lint-staged@^13.2.2: string-argv "0.3.2" yaml "2.3.1" -lint-staged@^9.2.5: - version "9.5.0" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-9.5.0.tgz#290ec605252af646d9b74d73a0fa118362b05a33" - integrity sha512-nawMob9cb/G1J98nb8v3VC/E8rcX1rryUYXVZ69aT9kde6YWX+uvNOEHY5yf2gcWcTJGiD0kqXmCnS3oD75GIA== - dependencies: - chalk "^2.4.2" - commander "^2.20.0" - cosmiconfig "^5.2.1" - debug "^4.1.1" - dedent "^0.7.0" - del "^5.0.0" - execa "^2.0.3" - listr "^0.14.3" - log-symbols "^3.0.0" - micromatch "^4.0.2" - normalize-path "^3.0.0" - please-upgrade-node "^3.1.1" - string-argv "^0.3.0" - stringify-object "^3.3.0" - -listr-silent-renderer@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e" - integrity sha512-L26cIFm7/oZeSNVhWB6faeorXhMg4HNlb/dS/7jHhr708jxlXrtrBWo4YUxZQkc6dGoxEAe6J/D3juTRBUzjtA== - -listr-update-renderer@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz#4ea8368548a7b8aecb7e06d8c95cb45ae2ede6a2" - integrity sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA== - dependencies: - chalk "^1.1.3" - cli-truncate "^0.2.1" - elegant-spinner "^1.0.1" - figures "^1.7.0" - indent-string "^3.0.0" - log-symbols "^1.0.2" - log-update "^2.3.0" - strip-ansi "^3.0.1" - -listr-verbose-renderer@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz#f1132167535ea4c1261102b9f28dac7cba1e03db" - integrity sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw== - dependencies: - chalk "^2.4.1" - cli-cursor "^2.1.0" - date-fns "^1.27.2" - figures "^2.0.0" - listr2@6.6.1: version "6.6.1" resolved "https://registry.yarnpkg.com/listr2/-/listr2-6.6.1.tgz#08b2329e7e8ba6298481464937099f4a2cd7f95d" @@ -15054,21 +14197,6 @@ listr2@6.6.1: rfdc "^1.3.0" wrap-ansi "^8.1.0" -listr@^0.14.3: - version "0.14.3" - resolved "https://registry.yarnpkg.com/listr/-/listr-0.14.3.tgz#2fea909604e434be464c50bddba0d496928fa586" - integrity sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA== - dependencies: - "@samverschueren/stream-to-observable" "^0.3.0" - is-observable "^1.1.0" - is-promise "^2.1.0" - is-stream "^1.1.0" - listr-silent-renderer "^1.1.1" - listr-update-renderer "^0.5.0" - listr-verbose-renderer "^0.5.0" - p-map "^2.0.0" - rxjs "^6.3.3" - lnk@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/lnk/-/lnk-1.1.0.tgz#acee59b91ca9a0a8fc12a3dbc53b9edc5f353dd7" @@ -15099,11 +14227,6 @@ load-json-file@^6.2.0: strip-bom "^4.0.0" type-fest "^0.6.0" -loader-runner@^4.2.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" - integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== - loader-utils@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" @@ -15175,11 +14298,6 @@ lodash.isplainobject@^4.0.6: resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== -lodash.memoize@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== - lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -15200,23 +14318,11 @@ lodash.union@^4.6.0: resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" integrity sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw== -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== - lodash@4.x, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.2.1, lodash@^4.7.0, lodash@~4.17.15: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" - integrity sha512-mmPrW0Fh2fxOzdBbFv4g1m6pR72haFLPJ2G5SJEELf1y+iaQrDG6cWCPjy54RHYbZAt7X+ls690Kw62AdWXBzQ== - dependencies: - chalk "^1.0.0" - log-symbols@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" @@ -15232,15 +14338,6 @@ log-symbols@^4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" -log-update@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-2.3.0.tgz#88328fd7d1ce7938b29283746f0b1bc126b24708" - integrity sha512-vlP11XfFGyeNQlmEn9tJ66rEW1coA/79m5z6BCkudjbAGE83uhAcGYrBFwfs3AdLiLzGRusRPAbSPK9xZteCmg== - dependencies: - ansi-escapes "^3.0.0" - cli-cursor "^2.0.0" - wrap-ansi "^3.0.1" - log-update@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/log-update/-/log-update-5.0.1.tgz#9e928bf70cb183c1f0c9e91d9e6b7115d597ce09" @@ -15429,11 +14526,6 @@ md5@^2.2.1, md5@^2.3.0: crypt "0.0.2" is-buffer "~1.1.6" -mdn-data@2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" - integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== - mdurl@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" @@ -15471,7 +14563,7 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: +merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== @@ -15513,7 +14605,7 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -15823,11 +14915,6 @@ nan@^2.17.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554" integrity sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w== -nanoid@^3.1.30, nanoid@^3.3.6: - version "3.3.6" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" - integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== - nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -15845,13 +14932,6 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" -nanospinner@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/nanospinner/-/nanospinner-0.4.0.tgz#f544f71fb990423528b8f6dd6c26134cf9f21659" - integrity sha512-FhxiB9PcEztMw6XfQDSLJBMlmN4n7B2hl/oiK4Hy9479r1+df0i2099DgcEx+m6yBfBJVUuKpILvP8fM3rK3Sw== - dependencies: - picocolors "^1.0.0" - napi-build-utils@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" @@ -16038,11 +15118,6 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -normalize-url@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" - integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== - normalize-url@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-8.0.0.tgz#593dbd284f743e8dcf6a5ddf8fadff149c82701a" @@ -16235,13 +15310,6 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -npm-run-path@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-3.1.0.tgz#7f91be317f6a466efed3c9f2980ad8a4ee8b0fa5" - integrity sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg== - dependencies: - path-key "^3.0.0" - npm-run-path@^4.0.0, npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -16273,11 +15341,6 @@ nth-check@^2.0.1: dependencies: boolbase "^1.0.0" -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== - nwsapi@^2.2.0: version "2.2.7" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" @@ -16334,7 +15397,7 @@ nx@15.9.7, "nx@>=14.8.1 < 16": "@nrwl/nx-win32-arm64-msvc" "15.9.7" "@nrwl/nx-win32-x64-msvc" "15.9.7" -object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== @@ -16571,11 +15634,6 @@ p-finally@^1.0.0: resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== -p-finally@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" - integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== - p-is-promise@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-3.0.0.tgz#58e78c7dfe2e163cf2a04ff869e7c1dba64a5971" @@ -16628,18 +15686,6 @@ p-map-series@^2.1.0: resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-2.1.0.tgz#7560d4c452d9da0c07e692fdbfe6e2c81a2a91f2" integrity sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q== -p-map@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" - integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== - -p-map@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" - integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== - dependencies: - aggregate-error "^3.0.0" - p-map@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" @@ -16788,11 +15834,6 @@ pako@2.0.4: resolved "https://registry.yarnpkg.com/pako/-/pako-2.0.4.tgz#6cebc4bbb0b6c73b0d5b8d7e8476e2b2fbea576d" integrity sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg== -pako@^2.0.4: - version "2.1.0" - resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86" - integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug== - parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -17070,7 +16111,7 @@ pkg@^5.4.1: resolve "^1.22.0" stream-meter "^1.0.4" -please-upgrade-node@^3.1.1, please-upgrade-node@^3.2.0: +please-upgrade-node@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg== @@ -17096,253 +16137,6 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== -postcss-calc@^8.2.3: - version "8.2.4" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.2.4.tgz#77b9c29bfcbe8a07ff6693dc87050828889739a5" - integrity sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q== - dependencies: - postcss-selector-parser "^6.0.9" - postcss-value-parser "^4.2.0" - -postcss-colormin@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.3.1.tgz#86c27c26ed6ba00d96c79e08f3ffb418d1d1988f" - integrity sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ== - dependencies: - browserslist "^4.21.4" - caniuse-api "^3.0.0" - colord "^2.9.1" - postcss-value-parser "^4.2.0" - -postcss-convert-values@^5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz#04998bb9ba6b65aa31035d669a6af342c5f9d393" - integrity sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA== - dependencies: - browserslist "^4.21.4" - postcss-value-parser "^4.2.0" - -postcss-discard-comments@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz#8df5e81d2925af2780075840c1526f0660e53696" - integrity sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ== - -postcss-discard-duplicates@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz#9eb4fe8456706a4eebd6d3b7b777d07bad03e848" - integrity sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw== - -postcss-discard-empty@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz#e57762343ff7f503fe53fca553d18d7f0c369c6c" - integrity sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A== - -postcss-discard-overridden@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz#7e8c5b53325747e9d90131bb88635282fb4a276e" - integrity sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw== - -postcss-merge-longhand@^5.1.7: - version "5.1.7" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz#24a1bdf402d9ef0e70f568f39bdc0344d568fb16" - integrity sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ== - dependencies: - postcss-value-parser "^4.2.0" - stylehacks "^5.1.1" - -postcss-merge-rules@^5.1.4: - version "5.1.4" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz#2f26fa5cacb75b1402e213789f6766ae5e40313c" - integrity sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g== - dependencies: - browserslist "^4.21.4" - caniuse-api "^3.0.0" - cssnano-utils "^3.1.0" - postcss-selector-parser "^6.0.5" - -postcss-minify-font-values@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz#f1df0014a726083d260d3bd85d7385fb89d1f01b" - integrity sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-minify-gradients@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz#f1fe1b4f498134a5068240c2f25d46fcd236ba2c" - integrity sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw== - dependencies: - colord "^2.9.1" - cssnano-utils "^3.1.0" - postcss-value-parser "^4.2.0" - -postcss-minify-params@^5.1.4: - version "5.1.4" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz#c06a6c787128b3208b38c9364cfc40c8aa5d7352" - integrity sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw== - dependencies: - browserslist "^4.21.4" - cssnano-utils "^3.1.0" - postcss-value-parser "^4.2.0" - -postcss-minify-selectors@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz#d4e7e6b46147b8117ea9325a915a801d5fe656c6" - integrity sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg== - dependencies: - postcss-selector-parser "^6.0.5" - -postcss-modules-extract-imports@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" - integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== - -postcss-modules-local-by-default@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz#b08eb4f083050708998ba2c6061b50c2870ca524" - integrity sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA== - dependencies: - icss-utils "^5.0.0" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.1.0" - -postcss-modules-scope@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" - integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== - dependencies: - postcss-selector-parser "^6.0.4" - -postcss-modules-values@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" - integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== - dependencies: - icss-utils "^5.0.0" - -postcss-normalize-charset@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz#9302de0b29094b52c259e9b2cf8dc0879879f0ed" - integrity sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg== - -postcss-normalize-display-values@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz#72abbae58081960e9edd7200fcf21ab8325c3da8" - integrity sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-normalize-positions@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz#ef97279d894087b59325b45c47f1e863daefbb92" - integrity sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-normalize-repeat-style@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz#e9eb96805204f4766df66fd09ed2e13545420fb2" - integrity sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-normalize-string@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz#411961169e07308c82c1f8c55f3e8a337757e228" - integrity sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-normalize-timing-functions@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz#d5614410f8f0b2388e9f240aa6011ba6f52dafbb" - integrity sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-normalize-unicode@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz#f67297fca3fea7f17e0d2caa40769afc487aa030" - integrity sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA== - dependencies: - browserslist "^4.21.4" - postcss-value-parser "^4.2.0" - -postcss-normalize-url@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz#ed9d88ca82e21abef99f743457d3729a042adcdc" - integrity sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew== - dependencies: - normalize-url "^6.0.1" - postcss-value-parser "^4.2.0" - -postcss-normalize-whitespace@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz#08a1a0d1ffa17a7cc6efe1e6c9da969cc4493cfa" - integrity sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-ordered-values@^5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz#b6fd2bd10f937b23d86bc829c69e7732ce76ea38" - integrity sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ== - dependencies: - cssnano-utils "^3.1.0" - postcss-value-parser "^4.2.0" - -postcss-reduce-initial@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz#798cd77b3e033eae7105c18c9d371d989e1382d6" - integrity sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg== - dependencies: - browserslist "^4.21.4" - caniuse-api "^3.0.0" - -postcss-reduce-transforms@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz#333b70e7758b802f3dd0ddfe98bb1ccfef96b6e9" - integrity sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9: - version "6.0.13" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b" - integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - -postcss-svgo@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.1.0.tgz#0a317400ced789f233a28826e77523f15857d80d" - integrity sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA== - dependencies: - postcss-value-parser "^4.2.0" - svgo "^2.7.0" - -postcss-unique-selectors@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz#a9f273d1eacd09e9aa6088f4b0507b18b1b541b6" - integrity sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA== - dependencies: - postcss-selector-parser "^6.0.5" - -postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" - integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== - -postcss@^8.3.5, postcss@^8.4.21: - version "8.4.31" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" - integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== - dependencies: - nanoid "^3.3.6" - picocolors "^1.0.0" - source-map-js "^1.0.2" - postgres-array@~2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" @@ -17393,16 +16187,6 @@ prettier@^2.8.8: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== -pretty-format@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" - integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== - dependencies: - "@jest/types" "^24.9.0" - ansi-regex "^4.0.0" - ansi-styles "^3.2.0" - react-is "^16.8.4" - pretty-format@^26.0.0, pretty-format@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" @@ -17616,13 +16400,6 @@ quick-lru@^5.1.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - range-parser@~1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -17658,7 +16435,7 @@ rc@1.2.8, rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-is@^16.13.1, react-is@^16.8.4: +react-is@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -18110,7 +16887,7 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@^6.3.3, rxjs@^6.4.0, rxjs@^6.6.0: +rxjs@^6.4.0, rxjs@^6.6.0: version "6.6.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== @@ -18134,7 +16911,7 @@ safe-array-concat@^1.0.1: has-symbols "^1.0.3" isarray "^2.0.5" -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -18211,25 +16988,6 @@ schema-utils@^2.6.5: ajv "^6.12.4" ajv-keywords "^3.5.2" -schema-utils@^3.1.1, schema-utils@^3.2.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" - integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== - dependencies: - "@types/json-schema" "^7.0.8" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - -schema-utils@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.2.0.tgz#70d7c93e153a273a805801882ebd3bff20d89c8b" - integrity sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw== - dependencies: - "@types/json-schema" "^7.0.9" - ajv "^8.9.0" - ajv-formats "^2.1.1" - ajv-keywords "^5.1.0" - semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" @@ -18261,7 +17019,7 @@ semver-utils@^1.1.4: resolved "https://registry.yarnpkg.com/semver-utils/-/semver-utils-1.1.4.tgz#cf0405e669a57488913909fc1c3f29bf2a4871e2" integrity sha512-EjnoLE5OGmDAVV/8YDoN5KiajNadjzIp9BAHOhYeQHt7j0UWxjmgsx4YD48wp4Ue1Qogq38F1GNUJNqF1kKKxA== -"semver@2 || 3 || 4 || 5", semver@7.3.5, semver@7.3.7, semver@7.5.4, semver@7.x, semver@^5.0.0, semver@^5.5.0, semver@^5.6.0, semver@^6.0.0, semver@^6.3.0, semver@^6.3.1, semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.2, semver@~7.5.4: +"semver@2 || 3 || 4 || 5", semver@7.3.7, semver@7.5.4, semver@7.x, semver@^5.0.0, semver@^5.5.0, semver@^5.6.0, semver@^6.0.0, semver@^6.3.0, semver@^6.3.1, semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.2, semver@~7.5.4: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -18292,13 +17050,6 @@ seq-queue@^0.0.5: resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" integrity sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q== -serialize-javascript@^6.0.0, serialize-javascript@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" - integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== - dependencies: - randombytes "^2.1.0" - serve-static@1.15.0: version "1.15.0" resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" @@ -18453,19 +17204,6 @@ sisteransi@^1.0.5: resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== -size-limit@6.0.4: - version "6.0.4" - resolved "https://registry.yarnpkg.com/size-limit/-/size-limit-6.0.4.tgz#f3345206d8c25485d0d31ea41622761a3a1aad93" - integrity sha512-zo/9FrXzetvZGFJnd1LC4mR9GvirElALlerMY3EOwEGdW7Lwgl2WT0hTRC2559ZR2PGfRpnXEgAFkayGAJOebg== - dependencies: - bytes-iec "^3.1.1" - chokidar "^3.5.2" - ci-job-number "^1.2.2" - globby "^11.0.4" - lilconfig "^2.0.3" - nanospinner "^0.4.0" - picocolors "^1.0.0" - slash@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" @@ -18476,11 +17214,6 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slice-ansi@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" - integrity sha512-up04hB2hR92PgjpyU3y/eg91yIBILyjVY26NvvciY3EVVPjybkMszMpXQ9QAkcS3I5rtJBDLoTxxg+qvW8c7rw== - slice-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" @@ -18566,11 +17299,6 @@ sort-keys@^4.0.0: dependencies: is-plain-obj "^2.0.0" -source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== - source-map-resolve@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" @@ -18582,7 +17310,7 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.17, source-map-support@^0.5.21, source-map-support@^0.5.6, source-map-support@~0.5.20: +source-map-support@^0.5.17, source-map-support@^0.5.21, source-map-support@^0.5.6: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -18703,11 +17431,6 @@ ssri@^9.0.0, ssri@^9.0.1: dependencies: minipass "^3.1.1" -stable@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" - integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== - stack-trace@0.0.x: version "0.0.10" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" @@ -18781,7 +17504,7 @@ streamroller@^3.1.5: debug "^4.3.4" fs-extra "^8.1.0" -string-argv@0.3.2, string-argv@^0.3.0, string-argv@~0.3.1: +string-argv@0.3.2, string-argv@~0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== @@ -18803,16 +17526,7 @@ string-length@^4.0.1: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -string-width@^2.1.0, string-width@^2.1.1: +string-width@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -18895,15 +17609,6 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -stringify-object@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" - integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== - dependencies: - get-own-enumerable-property-symbols "^3.0.0" - is-obj "^1.0.1" - is-regexp "^1.0.0" - "strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -18911,13 +17616,6 @@ stringify-object@^3.3.0: dependencies: ansi-regex "^5.0.1" -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== - dependencies: - ansi-regex "^2.0.0" - strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" @@ -19005,24 +17703,6 @@ stubs@^3.0.0: resolved "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b" integrity sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw== -style-loader@^3.3.1: - version "3.3.3" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.3.tgz#bba8daac19930169c0c9c96706749a597ae3acff" - integrity sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw== - -stylehacks@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.1.tgz#7934a34eb59d7152149fa69d6e9e56f2fc34bcc9" - integrity sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw== - dependencies: - browserslist "^4.21.4" - postcss-selector-parser "^6.0.4" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g== - supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -19037,13 +17717,6 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -supports-color@^8.0.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - supports-hyperlinks@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" @@ -19057,20 +17730,7 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -svgo@^2.7.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" - integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== - dependencies: - "@trysound/sax" "0.2.0" - commander "^7.2.0" - css-select "^4.1.3" - css-tree "^1.1.3" - csso "^4.2.0" - picocolors "^1.0.0" - stable "^0.1.8" - -symbol-observable@^1.0.2, symbol-observable@^1.0.3, symbol-observable@^1.1.0: +symbol-observable@^1.0.2, symbol-observable@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== @@ -19091,11 +17751,6 @@ table@^6.8.1: string-width "^4.2.3" strip-ansi "^6.0.1" -tapable@^2.1.1, tapable@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" - integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== - tar-fs@^2.0.0, tar-fs@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" @@ -19158,27 +17813,6 @@ terminal-link@^2.0.0: ansi-escapes "^4.2.1" supports-hyperlinks "^2.0.0" -terser-webpack-plugin@^5.3.7: - version "5.3.9" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz#832536999c51b46d468067f9e37662a3b96adfe1" - integrity sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA== - dependencies: - "@jridgewell/trace-mapping" "^0.3.17" - jest-worker "^27.4.5" - schema-utils "^3.1.1" - serialize-javascript "^6.0.1" - terser "^5.16.8" - -terser@^5.16.8: - version "5.21.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.21.0.tgz#d2b27e92b5e56650bc83b6defa00a110f0b124b2" - integrity sha512-WtnFKrxu9kaoXuiZFSGrcAvvBqAdmKx0SFNmVNYdJamMu9yyN3I/QF0FbH4QcqJQ+y1CJnzxGIKH0cSj+FGYRw== - dependencies: - "@jridgewell/source-map" "^0.3.3" - acorn "^8.8.2" - commander "^2.20.0" - source-map-support "~0.5.20" - test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -19335,7 +17969,7 @@ ts-invariant@^0.4.0: dependencies: tslib "^1.9.3" -ts-jest@26.4.4, ts-jest@^26.4.4, ts-jest@^26.5.5, ts-jest@^29.0.2: +ts-jest@26.4.4, ts-jest@^26.4.4, ts-jest@^26.5.5: version "26.5.6" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.6.tgz#c32e0746425274e1dfe333f43cd3c800e014ec35" integrity sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA== @@ -19370,7 +18004,7 @@ ts-node@^10.2.1, ts-node@^10.8.1: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -ts-node@^8.10.1, ts-node@^8.10.2, ts-node@^8.5.0: +ts-node@^8.10.1, ts-node@^8.10.2: version "8.10.2" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d" integrity sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA== @@ -19794,7 +18428,7 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== @@ -19929,14 +18563,6 @@ walker@^1.0.7, walker@~1.0.5: dependencies: makeerror "1.0.12" -watchpack@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" - integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== - dependencies: - glob-to-regexp "^0.4.1" - graceful-fs "^4.1.2" - wcwidth@^1.0.0, wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" @@ -19959,41 +18585,6 @@ webidl-conversions@^6.1.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== -webpack-sources@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" - integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== - -webpack@^5.61.0: - version "5.88.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.2.tgz#f62b4b842f1c6ff580f3fcb2ed4f0b579f4c210e" - integrity sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== - dependencies: - "@types/eslint-scope" "^3.7.3" - "@types/estree" "^1.0.0" - "@webassemblyjs/ast" "^1.11.5" - "@webassemblyjs/wasm-edit" "^1.11.5" - "@webassemblyjs/wasm-parser" "^1.11.5" - acorn "^8.7.1" - acorn-import-assertions "^1.9.0" - browserslist "^4.14.5" - chrome-trace-event "^1.0.2" - enhanced-resolve "^5.15.0" - es-module-lexer "^1.2.1" - eslint-scope "5.1.1" - events "^3.2.0" - glob-to-regexp "^0.4.1" - graceful-fs "^4.2.9" - json-parse-even-better-errors "^2.3.1" - loader-runner "^4.2.0" - mime-types "^2.1.27" - neo-async "^2.6.2" - schema-utils "^3.2.0" - tapable "^2.1.1" - terser-webpack-plugin "^5.3.7" - watchpack "^2.4.0" - webpack-sources "^3.2.3" - whatwg-encoding@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" @@ -20183,14 +18774,6 @@ workerpool@^6.5.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba" - integrity sha512-iXR3tDXpbnTpzjKSylUJRkLuOrEC7hwEB221cgn6wtF8wpmz28puFXAEfPT5zrjM3wahygB//VuWEr1vTkDcNQ== - dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi@^6.0.1, wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -20355,7 +18938,7 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@1.10.2, yaml@^1.10.0, yaml@^1.10.2: +yaml@1.10.2, yaml@^1.10.0: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== From 4c313c21839599aa63081d18d8969cd8d16d68e7 Mon Sep 17 00:00:00 2001 From: phani-srikar Date: Fri, 16 Aug 2024 07:28:08 -0700 Subject: [PATCH 19/23] chore: refresh lock file --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index f70a0c1998..556232fdcb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11610,7 +11610,7 @@ fn.name@1.x.x: resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== -follow-redirects@^1.15.0: +follow-redirects@^1.15.6: version "1.15.6" resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== From 7dac35cceb971b256b5688b0745ef82afc78b641 Mon Sep 17 00:00:00 2001 From: phani-srikar Date: Fri, 16 Aug 2024 15:01:05 -0700 Subject: [PATCH 20/23] feat!: bump version for v2 transformer packages BREAKING CHANGE: distinguish from LTS version --- packages/amplify-graphql-auth-transformer/package.json | 3 ++- .../amplify-graphql-default-value-transformer/package.json | 3 ++- packages/amplify-graphql-directives/package.json | 3 ++- packages/amplify-graphql-function-transformer/package.json | 3 ++- packages/amplify-graphql-http-transformer/package.json | 3 ++- packages/amplify-graphql-index-transformer/package.json | 3 ++- packages/amplify-graphql-model-transformer/package.json | 3 ++- packages/amplify-graphql-name-mapping-transformer/package.json | 3 ++- packages/amplify-graphql-predictions-transformer/package.json | 3 ++- packages/amplify-graphql-relational-transformer/package.json | 3 ++- packages/amplify-graphql-schema-generator/package.json | 3 ++- packages/amplify-graphql-schema-test-library/package.json | 3 ++- packages/amplify-graphql-searchable-transformer/package.json | 3 ++- packages/amplify-graphql-sql-transformer/package.json | 3 ++- packages/amplify-graphql-transformer-core/package.json | 3 ++- packages/amplify-graphql-transformer-interfaces/package.json | 3 ++- packages/amplify-graphql-transformer-test-utils/package.json | 3 ++- packages/amplify-graphql-transformer/package.json | 3 ++- packages/graphql-mapping-template/package.json | 3 ++- packages/graphql-transformer-common/package.json | 3 ++- packages/graphql-transformer-core/package.json | 3 ++- 21 files changed, 42 insertions(+), 21 deletions(-) diff --git a/packages/amplify-graphql-auth-transformer/package.json b/packages/amplify-graphql-auth-transformer/package.json index 85a0cd9b27..3d28c62541 100644 --- a/packages/amplify-graphql-auth-transformer/package.json +++ b/packages/amplify-graphql-auth-transformer/package.json @@ -16,7 +16,8 @@ "cloudformation", "aws", "amplify", - "auth" + "auth", + "transformer" ], "publishConfig": { "access": "public" diff --git a/packages/amplify-graphql-default-value-transformer/package.json b/packages/amplify-graphql-default-value-transformer/package.json index 975c65f4c4..777c26b840 100644 --- a/packages/amplify-graphql-default-value-transformer/package.json +++ b/packages/amplify-graphql-default-value-transformer/package.json @@ -15,7 +15,8 @@ "graphql", "cloudformation", "aws", - "amplify" + "amplify", + "transformer" ], "publishConfig": { "access": "public" diff --git a/packages/amplify-graphql-directives/package.json b/packages/amplify-graphql-directives/package.json index c4b9dd38e8..2d3f59f546 100644 --- a/packages/amplify-graphql-directives/package.json +++ b/packages/amplify-graphql-directives/package.json @@ -14,7 +14,8 @@ "keywords": [ "graphql", "aws", - "amplify" + "amplify", + "directives" ], "publishConfig": { "access": "public" diff --git a/packages/amplify-graphql-function-transformer/package.json b/packages/amplify-graphql-function-transformer/package.json index 5489b8b430..86bd3a1fdf 100644 --- a/packages/amplify-graphql-function-transformer/package.json +++ b/packages/amplify-graphql-function-transformer/package.json @@ -15,7 +15,8 @@ "graphql", "cloudformation", "aws", - "amplify" + "amplify", + "transformer" ], "publishConfig": { "access": "public" diff --git a/packages/amplify-graphql-http-transformer/package.json b/packages/amplify-graphql-http-transformer/package.json index bb93529e19..ef8e2aba80 100644 --- a/packages/amplify-graphql-http-transformer/package.json +++ b/packages/amplify-graphql-http-transformer/package.json @@ -15,7 +15,8 @@ "graphql", "cloudformation", "aws", - "amplify" + "amplify", + "transformer" ], "publishConfig": { "access": "public" diff --git a/packages/amplify-graphql-index-transformer/package.json b/packages/amplify-graphql-index-transformer/package.json index 6433e8e74d..27f48bb0c8 100644 --- a/packages/amplify-graphql-index-transformer/package.json +++ b/packages/amplify-graphql-index-transformer/package.json @@ -15,7 +15,8 @@ "graphql", "cloudformation", "aws", - "amplify" + "amplify", + "transformer" ], "publishConfig": { "access": "public" diff --git a/packages/amplify-graphql-model-transformer/package.json b/packages/amplify-graphql-model-transformer/package.json index f2b8f669bd..8386dec33a 100644 --- a/packages/amplify-graphql-model-transformer/package.json +++ b/packages/amplify-graphql-model-transformer/package.json @@ -15,7 +15,8 @@ "graphql", "cloudformation", "aws", - "amplify" + "amplify", + "transformer" ], "publishConfig": { "access": "public" diff --git a/packages/amplify-graphql-name-mapping-transformer/package.json b/packages/amplify-graphql-name-mapping-transformer/package.json index 084548e47d..2022ae32a7 100644 --- a/packages/amplify-graphql-name-mapping-transformer/package.json +++ b/packages/amplify-graphql-name-mapping-transformer/package.json @@ -17,7 +17,8 @@ "cloudformation", "aws", "mapsto", - "transformer" + "transformer", + "refersTo" ], "publishConfig": { "access": "public" diff --git a/packages/amplify-graphql-predictions-transformer/package.json b/packages/amplify-graphql-predictions-transformer/package.json index 7cfd85b2a6..7b25b62773 100644 --- a/packages/amplify-graphql-predictions-transformer/package.json +++ b/packages/amplify-graphql-predictions-transformer/package.json @@ -15,7 +15,8 @@ "graphql", "cloudformation", "aws", - "amplify" + "amplify", + "transformer" ], "publishConfig": { "access": "public" diff --git a/packages/amplify-graphql-relational-transformer/package.json b/packages/amplify-graphql-relational-transformer/package.json index e117c098b8..97fa17c889 100644 --- a/packages/amplify-graphql-relational-transformer/package.json +++ b/packages/amplify-graphql-relational-transformer/package.json @@ -15,7 +15,8 @@ "graphql", "cloudformation", "aws", - "amplify" + "amplify", + "transformer" ], "publishConfig": { "access": "public" diff --git a/packages/amplify-graphql-schema-generator/package.json b/packages/amplify-graphql-schema-generator/package.json index e75bca2a39..2e9ac19daf 100644 --- a/packages/amplify-graphql-schema-generator/package.json +++ b/packages/amplify-graphql-schema-generator/package.json @@ -16,7 +16,8 @@ "schema", "aws", "amplify", - "generator" + "generator", + "transformer" ], "publishConfig": { "access": "public" diff --git a/packages/amplify-graphql-schema-test-library/package.json b/packages/amplify-graphql-schema-test-library/package.json index c619b69f7f..b0625c86a2 100644 --- a/packages/amplify-graphql-schema-test-library/package.json +++ b/packages/amplify-graphql-schema-test-library/package.json @@ -16,7 +16,8 @@ "cloudformation", "aws", "amplify", - "schema" + "schema", + "transformer" ], "publishConfig": { "access": "public" diff --git a/packages/amplify-graphql-searchable-transformer/package.json b/packages/amplify-graphql-searchable-transformer/package.json index c2a5d37ec2..f44dbba510 100644 --- a/packages/amplify-graphql-searchable-transformer/package.json +++ b/packages/amplify-graphql-searchable-transformer/package.json @@ -15,7 +15,8 @@ "graphql", "cloudformation", "aws", - "amplify" + "amplify", + "transformer" ], "publishConfig": { "access": "public" diff --git a/packages/amplify-graphql-sql-transformer/package.json b/packages/amplify-graphql-sql-transformer/package.json index d02539e80d..b7d3dfa1dc 100644 --- a/packages/amplify-graphql-sql-transformer/package.json +++ b/packages/amplify-graphql-sql-transformer/package.json @@ -15,7 +15,8 @@ "graphql", "cloudformation", "aws", - "amplify" + "amplify", + "transformer" ], "publishConfig": { "access": "public" diff --git a/packages/amplify-graphql-transformer-core/package.json b/packages/amplify-graphql-transformer-core/package.json index 6b6f7ee404..c5be18a7ce 100644 --- a/packages/amplify-graphql-transformer-core/package.json +++ b/packages/amplify-graphql-transformer-core/package.json @@ -15,7 +15,8 @@ "graphql", "cloudformation", "aws", - "amplify" + "amplify", + "transformer" ], "publishConfig": { "access": "public" diff --git a/packages/amplify-graphql-transformer-interfaces/package.json b/packages/amplify-graphql-transformer-interfaces/package.json index 155f12e7ff..c383d33a7f 100644 --- a/packages/amplify-graphql-transformer-interfaces/package.json +++ b/packages/amplify-graphql-transformer-interfaces/package.json @@ -15,7 +15,8 @@ "graphql", "cloudformation", "aws", - "amplify" + "amplify", + "transformer" ], "publishConfig": { "access": "public" diff --git a/packages/amplify-graphql-transformer-test-utils/package.json b/packages/amplify-graphql-transformer-test-utils/package.json index bb1f4315b0..de746d60eb 100644 --- a/packages/amplify-graphql-transformer-test-utils/package.json +++ b/packages/amplify-graphql-transformer-test-utils/package.json @@ -23,7 +23,8 @@ "cloudformation", "aws", "amplify", - "api" + "api", + "transformer" ], "publishConfig": { "access": "public" diff --git a/packages/amplify-graphql-transformer/package.json b/packages/amplify-graphql-transformer/package.json index 861c4ee853..853fbcf6e6 100644 --- a/packages/amplify-graphql-transformer/package.json +++ b/packages/amplify-graphql-transformer/package.json @@ -22,7 +22,8 @@ "cloudformation", "aws", "amplify", - "api" + "api", + "transformer" ], "publishConfig": { "access": "public" diff --git a/packages/graphql-mapping-template/package.json b/packages/graphql-mapping-template/package.json index 050bdbf9db..d10a016936 100644 --- a/packages/graphql-mapping-template/package.json +++ b/packages/graphql-mapping-template/package.json @@ -15,7 +15,8 @@ "graphql", "appsync", "cloudformation", - "aws" + "aws", + "amplify" ], "scripts": { "test": "jest", diff --git a/packages/graphql-transformer-common/package.json b/packages/graphql-transformer-common/package.json index 8ab535dc1f..32624c5df2 100644 --- a/packages/graphql-transformer-common/package.json +++ b/packages/graphql-transformer-common/package.json @@ -14,7 +14,8 @@ "keywords": [ "graphql", "appsync", - "aws" + "aws", + "amplify" ], "scripts": { "test": "jest", diff --git a/packages/graphql-transformer-core/package.json b/packages/graphql-transformer-core/package.json index c658db0f75..978f95a1c9 100644 --- a/packages/graphql-transformer-core/package.json +++ b/packages/graphql-transformer-core/package.json @@ -14,7 +14,8 @@ "keywords": [ "graphql", "cloudformation", - "aws" + "aws", + "amplify" ], "scripts": { "test": "jest", From baa9bf313edc1e4f241837f62c934fea91001b99 Mon Sep 17 00:00:00 2001 From: phani-srikar Date: Mon, 19 Aug 2024 10:17:30 -0700 Subject: [PATCH 21/23] fix: encode password to handle special chars --- .../src/sql-datatabase-controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-graphql-api-construct-tests/src/sql-datatabase-controller.ts b/packages/amplify-graphql-api-construct-tests/src/sql-datatabase-controller.ts index 61bb96dbf5..e4335a7391 100644 --- a/packages/amplify-graphql-api-construct-tests/src/sql-datatabase-controller.ts +++ b/packages/amplify-graphql-api-construct-tests/src/sql-datatabase-controller.ts @@ -260,6 +260,6 @@ export class SqlDatatabaseController { */ getConnectionUri = (engine: SqlEngine, username: string, password: string, hostname: string, port: number, dbName: string): string => { const protocol = engine === 'postgres' ? 'postgresql' : 'mysql'; - return `${protocol}://${username}:${password}@${hostname}:${port}/${dbName}`; + return `${protocol}://${username}:${encodeURIComponent(password)}@${hostname}:${port}/${dbName}`; }; } From e96acfadcdc5bd7bfade1a01e21502d554bbc86c Mon Sep 17 00:00:00 2001 From: phani-srikar Date: Mon, 19 Aug 2024 11:11:41 -0700 Subject: [PATCH 22/23] fix: encode the username as well since mysql supports spaces --- .../src/sql-datatabase-controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-graphql-api-construct-tests/src/sql-datatabase-controller.ts b/packages/amplify-graphql-api-construct-tests/src/sql-datatabase-controller.ts index e4335a7391..0e724b2464 100644 --- a/packages/amplify-graphql-api-construct-tests/src/sql-datatabase-controller.ts +++ b/packages/amplify-graphql-api-construct-tests/src/sql-datatabase-controller.ts @@ -260,6 +260,6 @@ export class SqlDatatabaseController { */ getConnectionUri = (engine: SqlEngine, username: string, password: string, hostname: string, port: number, dbName: string): string => { const protocol = engine === 'postgres' ? 'postgresql' : 'mysql'; - return `${protocol}://${username}:${encodeURIComponent(password)}@${hostname}:${port}/${dbName}`; + return `${protocol}://${encodeURIComponent(username)}:${encodeURIComponent(password)}@${hostname}:${port}/${dbName}`; }; } From 97b1f36e405808df2ed694c3b94a3da7b3d9759f Mon Sep 17 00:00:00 2001 From: Dane Pilcher Date: Mon, 19 Aug 2024 14:57:20 -0600 Subject: [PATCH 23/23] fix: change gen 1 patterns to warning message instead of error (#2768) --- packages/amplify-graphql-api-construct/.jsii | 170 +++---- packages/amplify-graphql-api-construct/API.md | 4 - .../disable-gen1-patterns.test.ts | 439 +++++------------- .../src/amplify-graphql-api.ts | 9 +- .../src/internal/default-parameters.ts | 1 - .../src/types.ts | 34 -- .../src/graphql-predictions-transformer.ts | 6 + .../src/graphql-belongs-to-transformer.ts | 32 +- .../src/graphql-has-many-transformer.ts | 34 +- .../src/graphql-has-one-transformer.ts | 34 +- .../src/graphql-many-to-many-transformer.ts | 7 + .../src/graphql-searchable-transformer.ts | 9 +- .../API.md | 2 + .../src/cdk-compat/transform-manager.ts | 1 + .../src/deployment-resources.ts | 4 + packages/amplify-graphql-transformer/API.md | 1 - .../amplify-graphql-transformer/package.json | 1 + .../src/__tests__/allow-gen1-patterns.test.ts | 326 +++++++++++++ .../src/__tests__/graphql-transformer.test.ts | 8 - .../src/graphql-transformer.ts | 9 +- 20 files changed, 625 insertions(+), 506 deletions(-) create mode 100644 packages/amplify-graphql-transformer/src/__tests__/allow-gen1-patterns.test.ts diff --git a/packages/amplify-graphql-api-construct/.jsii b/packages/amplify-graphql-api-construct/.jsii index 6e80807c1c..aa8fcf2d30 100644 --- a/packages/amplify-graphql-api-construct/.jsii +++ b/packages/amplify-graphql-api-construct/.jsii @@ -3734,7 +3734,7 @@ "kind": "interface", "locationInModule": { "filename": "src/types.ts", - "line": 902 + "line": 868 }, "name": "AddFunctionProps", "properties": [ @@ -3747,7 +3747,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 906 + "line": 872 }, "name": "dataSource", "type": { @@ -3763,7 +3763,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 911 + "line": 877 }, "name": "name", "type": { @@ -3780,7 +3780,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 946 + "line": 912 }, "name": "code", "optional": true, @@ -3798,7 +3798,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 918 + "line": 884 }, "name": "description", "optional": true, @@ -3816,7 +3816,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 925 + "line": 891 }, "name": "requestMappingTemplate", "optional": true, @@ -3834,7 +3834,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 932 + "line": 898 }, "name": "responseMappingTemplate", "optional": true, @@ -3852,7 +3852,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 939 + "line": 905 }, "name": "runtime", "optional": true, @@ -4148,7 +4148,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 139 + "line": 138 }, "parameters": [ { @@ -4183,7 +4183,7 @@ "kind": "class", "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 85 + "line": 84 }, "methods": [ { @@ -4195,7 +4195,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 291 + "line": 286 }, "name": "addDynamoDbDataSource", "parameters": [ @@ -4244,7 +4244,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 303 + "line": 298 }, "name": "addElasticsearchDataSource", "parameters": [ @@ -4291,7 +4291,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 313 + "line": 308 }, "name": "addEventBridgeDataSource", "parameters": [ @@ -4338,7 +4338,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 395 + "line": 390 }, "name": "addFunction", "parameters": [ @@ -4373,7 +4373,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 324 + "line": 319 }, "name": "addHttpDataSource", "parameters": [ @@ -4421,7 +4421,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 335 + "line": 330 }, "name": "addLambdaDataSource", "parameters": [ @@ -4469,7 +4469,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 346 + "line": 341 }, "name": "addNoneDataSource", "parameters": [ @@ -4508,7 +4508,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 357 + "line": 352 }, "name": "addOpenSearchDataSource", "parameters": [ @@ -4556,7 +4556,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 370 + "line": 365 }, "name": "addRdsDataSource", "parameters": [ @@ -4623,7 +4623,7 @@ }, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 386 + "line": 381 }, "name": "addResolver", "parameters": [ @@ -4664,7 +4664,7 @@ "immutable": true, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 120 + "line": 119 }, "name": "apiId", "type": { @@ -4679,7 +4679,7 @@ "immutable": true, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 100 + "line": 99 }, "name": "generatedFunctionSlots", "type": { @@ -4712,7 +4712,7 @@ "immutable": true, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 105 + "line": 104 }, "name": "graphqlUrl", "type": { @@ -4728,7 +4728,7 @@ "immutable": true, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 110 + "line": 109 }, "name": "realtimeUrl", "type": { @@ -4743,7 +4743,7 @@ "immutable": true, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 89 + "line": 88 }, "name": "resources", "type": { @@ -4759,7 +4759,7 @@ "immutable": true, "locationInModule": { "filename": "src/amplify-graphql-api.ts", - "line": 115 + "line": 114 }, "name": "apiKey", "optional": true, @@ -4782,7 +4782,7 @@ "kind": "interface", "locationInModule": { "filename": "src/types.ts", - "line": 805 + "line": 771 }, "name": "AmplifyGraphqlApiCfnResources", "properties": [ @@ -4795,7 +4795,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 859 + "line": 825 }, "name": "additionalCfnResources", "type": { @@ -4816,7 +4816,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 844 + "line": 810 }, "name": "amplifyDynamoDbTables", "type": { @@ -4837,7 +4837,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 834 + "line": 800 }, "name": "cfnDataSources", "type": { @@ -4858,7 +4858,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 829 + "line": 795 }, "name": "cfnFunctionConfigurations", "type": { @@ -4879,7 +4879,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 854 + "line": 820 }, "name": "cfnFunctions", "type": { @@ -4900,7 +4900,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 809 + "line": 775 }, "name": "cfnGraphqlApi", "type": { @@ -4916,7 +4916,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 814 + "line": 780 }, "name": "cfnGraphqlSchema", "type": { @@ -4932,7 +4932,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 824 + "line": 790 }, "name": "cfnResolvers", "type": { @@ -4953,7 +4953,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 849 + "line": 815 }, "name": "cfnRoles", "type": { @@ -4974,7 +4974,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 839 + "line": 805 }, "name": "cfnTables", "type": { @@ -4995,7 +4995,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 819 + "line": 785 }, "name": "cfnApiKey", "optional": true, @@ -5018,7 +5018,7 @@ "kind": "interface", "locationInModule": { "filename": "src/types.ts", - "line": 722 + "line": 688 }, "name": "AmplifyGraphqlApiProps", "properties": [ @@ -5032,7 +5032,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 739 + "line": 705 }, "name": "authorizationModes", "type": { @@ -5049,7 +5049,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 727 + "line": 693 }, "name": "definition", "type": { @@ -5066,7 +5066,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 733 + "line": 699 }, "name": "apiName", "optional": true, @@ -5085,7 +5085,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 754 + "line": 720 }, "name": "conflictResolution", "optional": true, @@ -5103,7 +5103,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 798 + "line": 764 }, "name": "dataStoreConfiguration", "optional": true, @@ -5123,7 +5123,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 747 + "line": 713 }, "name": "functionNameMap", "optional": true, @@ -5146,7 +5146,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 769 + "line": 735 }, "name": "functionSlots", "optional": true, @@ -5181,7 +5181,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 792 + "line": 758 }, "name": "outputStorageStrategy", "optional": true, @@ -5198,7 +5198,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 781 + "line": 747 }, "name": "predictionsBucket", "optional": true, @@ -5216,7 +5216,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 763 + "line": 729 }, "name": "stackMappings", "optional": true, @@ -5242,7 +5242,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 776 + "line": 742 }, "name": "transformerPlugins", "optional": true, @@ -5264,7 +5264,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 787 + "line": 753 }, "name": "translationBehavior", "optional": true, @@ -5287,7 +5287,7 @@ "kind": "interface", "locationInModule": { "filename": "src/types.ts", - "line": 866 + "line": 832 }, "name": "AmplifyGraphqlApiResources", "properties": [ @@ -5300,7 +5300,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 890 + "line": 856 }, "name": "cfnResources", "type": { @@ -5316,7 +5316,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 885 + "line": 851 }, "name": "functions", "type": { @@ -5337,7 +5337,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 870 + "line": 836 }, "name": "graphqlApi", "type": { @@ -5353,7 +5353,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 895 + "line": 861 }, "name": "nestedStacks", "type": { @@ -5374,7 +5374,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 880 + "line": 846 }, "name": "roles", "type": { @@ -5395,7 +5395,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 875 + "line": 841 }, "name": "tables", "type": { @@ -6434,7 +6434,7 @@ "kind": "interface", "locationInModule": { "filename": "src/types.ts", - "line": 656 + "line": 622 }, "name": "IAmplifyGraphqlDefinition", "properties": [ @@ -6449,7 +6449,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 681 + "line": 647 }, "name": "dataSourceStrategies", "type": { @@ -6483,7 +6483,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 667 + "line": 633 }, "name": "functionSlots", "type": { @@ -6517,7 +6517,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 661 + "line": 627 }, "name": "schema", "type": { @@ -6534,7 +6534,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 687 + "line": 653 }, "name": "customSqlDataSourceStrategies", "optional": true, @@ -6558,7 +6558,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 675 + "line": 641 }, "name": "referencedLambdaFunctions", "optional": true, @@ -6584,7 +6584,7 @@ "kind": "interface", "locationInModule": { "filename": "src/types.ts", - "line": 693 + "line": 659 }, "name": "IBackendOutputEntry", "properties": [ @@ -6597,7 +6597,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 702 + "line": 668 }, "name": "payload", "type": { @@ -6618,7 +6618,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 697 + "line": 663 }, "name": "version", "type": { @@ -6638,7 +6638,7 @@ "kind": "interface", "locationInModule": { "filename": "src/types.ts", - "line": 708 + "line": 674 }, "methods": [ { @@ -6649,7 +6649,7 @@ }, "locationInModule": { "filename": "src/types.ts", - "line": 715 + "line": 681 }, "name": "addBackendOutputEntry", "parameters": [ @@ -6999,7 +6999,7 @@ "kind": "interface", "locationInModule": { "filename": "src/types.ts", - "line": 521 + "line": 504 }, "name": "PartialTranslationBehavior", "properties": [ @@ -7014,7 +7014,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 613 + "line": 596 }, "name": "allowDestructiveGraphqlSchemaUpdates", "optional": true, @@ -7032,7 +7032,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 533 + "line": 516 }, "name": "disableResolverDeduping", "optional": true, @@ -7054,7 +7054,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 578 + "line": 561 }, "name": "enableAutoIndexQueryNames", "optional": true, @@ -7073,7 +7073,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 593 + "line": 576 }, "name": "enableSearchNodeToNodeEncryption", "optional": true, @@ -7091,7 +7091,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 599 + "line": 582 }, "name": "enableTransformerCfnOutputs", "optional": true, @@ -7109,7 +7109,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 558 + "line": 541 }, "name": "populateOwnerFieldForStaticGroupAuth", "optional": true, @@ -7128,7 +7128,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 623 + "line": 606 }, "name": "replaceTableUponGsiUpdate", "optional": true, @@ -7146,7 +7146,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 584 + "line": 567 }, "name": "respectPrimaryKeyAttributesOnConnectionField", "optional": true, @@ -7164,7 +7164,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 539 + "line": 522 }, "name": "sandboxModeEnabled", "optional": true, @@ -7185,7 +7185,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 571 + "line": 554 }, "name": "secondaryKeyAsGSI", "optional": true, @@ -7206,7 +7206,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 526 + "line": 509 }, "name": "shouldDeepMergeDirectiveConfigDefaults", "optional": true, @@ -7224,7 +7224,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 552 + "line": 535 }, "name": "subscriptionsInheritPrimaryAuth", "optional": true, @@ -7243,7 +7243,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 565 + "line": 548 }, "name": "suppressApiKeyGeneration", "optional": true, @@ -7261,7 +7261,7 @@ "immutable": true, "locationInModule": { "filename": "src/types.ts", - "line": 546 + "line": 529 }, "name": "useSubUsernameForDefaultIdentityClaim", "optional": true, @@ -8649,5 +8649,5 @@ } }, "version": "1.11.5", - "fingerprint": "itC1sArd8btBzXDzzeFtCEr/UOX5v/yZgKz+LPxAdCg=" + "fingerprint": "UbD30aPByX855aFWOnKPhuMTI9TgWerKrHxE6yVYnD8=" } \ No newline at end of file diff --git a/packages/amplify-graphql-api-construct/API.md b/packages/amplify-graphql-api-construct/API.md index dd4283457f..6973808384 100644 --- a/packages/amplify-graphql-api-construct/API.md +++ b/packages/amplify-graphql-api-construct/API.md @@ -314,8 +314,6 @@ export interface OptimisticConflictResolutionStrategy extends ConflictResolution // @public export interface PartialTranslationBehavior { readonly allowDestructiveGraphqlSchemaUpdates?: boolean; - // @internal - readonly _allowGen1Patterns?: boolean; readonly disableResolverDeduping?: boolean; readonly enableAutoIndexQueryNames?: boolean; readonly enableSearchNodeToNodeEncryption?: boolean; @@ -442,8 +440,6 @@ export interface TimeToLiveSpecification { // @public export interface TranslationBehavior { readonly allowDestructiveGraphqlSchemaUpdates: boolean; - // @internal - readonly _allowGen1Patterns: boolean; readonly disableResolverDeduping: boolean; readonly enableAutoIndexQueryNames: boolean; // (undocumented) diff --git a/packages/amplify-graphql-api-construct/src/__tests__/__functional__/disable-gen1-patterns.test.ts b/packages/amplify-graphql-api-construct/src/__tests__/__functional__/disable-gen1-patterns.test.ts index 56e167be5e..cc836434c5 100644 --- a/packages/amplify-graphql-api-construct/src/__tests__/__functional__/disable-gen1-patterns.test.ts +++ b/packages/amplify-graphql-api-construct/src/__tests__/__functional__/disable-gen1-patterns.test.ts @@ -1,5 +1,5 @@ import * as cdk from 'aws-cdk-lib'; -import { Template } from 'aws-cdk-lib/assertions'; +import { Annotations } from 'aws-cdk-lib/assertions'; import { Bucket } from 'aws-cdk-lib/aws-s3'; import { AmplifyGraphqlApi } from '../../amplify-graphql-api'; import { AmplifyGraphqlDefinition } from '../../amplify-graphql-definition'; @@ -9,23 +9,21 @@ import { AmplifyGraphqlDefinition } from '../../amplify-graphql-definition'; * @param schema schema to test * @param allowGen1Patterns if gen 1 patterns are allowed. */ -const verifySchema = (schema: string, allowGen1Patterns: boolean): void => { +const verifySchema = (schema: string): cdk.Stack => { const stack = new cdk.Stack(); new AmplifyGraphqlApi(stack, 'TestApi', { definition: AmplifyGraphqlDefinition.fromString(schema), authorizationModes: { apiKeyConfig: { expires: cdk.Duration.days(7) }, }, - translationBehavior: { - _allowGen1Patterns: allowGen1Patterns, - }, }); - Template.fromStack(stack); + + return stack; }; -describe('_allowGen1Patterns', () => { - test('defaults to allow', () => { - const schema = ` +describe('Deprecate Gen 1 patterns', () => { + test('does not allow @manyToMany', () => { + const stack = verifySchema(/* GraphQL */ ` type Post @model { tags: [Tag] @manyToMany(relationName: "PostTags") } @@ -33,325 +31,142 @@ describe('_allowGen1Patterns', () => { type Tag @model { posts: [Post] @manyToMany(relationName: "PostTags") } - `; - const stack = new cdk.Stack(); - expect( - () => - new AmplifyGraphqlApi(stack, 'TestApi', { - definition: AmplifyGraphqlDefinition.fromString(schema), - authorizationModes: { - apiKeyConfig: { expires: cdk.Duration.days(7) }, - }, - }), - ).not.toThrow(); + `); + Annotations.fromStack(stack).hasWarning( + '/Default/TestApi/GraphQLAPI', + '@manyToMany is deprecated. This functionality will be removed in the next major release.', + ); }); - describe('_allowGen1Patterns: true', () => { - test('allows @manyToMany', () => { - expect(() => - verifySchema( - ` - type Post @model { - tags: [Tag] @manyToMany(relationName: "PostTags") - } - - type Tag @model { - posts: [Post] @manyToMany(relationName: "PostTags") - } - `, - true, - ), - ).not.toThrow(); - }); - - test('allows @searchable', () => { - expect(() => - verifySchema( - ` - type Post @model @searchable { - title: String - } - `, - true, - ), - ).not.toThrow(); - }); - - test('allows @predictions', () => { - const schema = ` - type Query { - recognizeLabelsFromImage: [String] @predictions(actions: [identifyLabels]) - } - `; - const stack = new cdk.Stack(); - expect( - () => - new AmplifyGraphqlApi(stack, 'TestApi', { - definition: AmplifyGraphqlDefinition.fromString(schema), - authorizationModes: { - apiKeyConfig: { expires: cdk.Duration.days(7) }, - }, - translationBehavior: { - _allowGen1Patterns: true, - }, - predictionsBucket: new Bucket(stack, 'myfakebucket'), - }), - ).not.toThrow(); - }); - - test('allows fields on @belongsTo', () => { - expect(() => - verifySchema( - ` - type Post @model { - authorID: ID - author: Author @belongsTo(fields: ["authorID"]) - } - - type Author @model { - posts: [Post] @hasMany - } - `, - true, - ), - ).not.toThrow(); - }); - - test('allows fields on @hasMany', () => { - expect(() => - verifySchema( - ` - type Post @model { - author: Author @belongsTo - } - - type Author @model { - postID: ID - posts: [Post] @hasMany(fields: ["postID"]) - } - `, - true, - ), - ).not.toThrow(); - }); - - test('allows fields on @hasOne', () => { - expect(() => - verifySchema( - ` - type Profile @model { - author: Author @belongsTo - } - - type Author @model { - profileID: ID - profile: Profile @hasOne(fields: ["profileID"]) - } - `, - true, - ), - ).not.toThrow(); - }); - - test('allows required @belongsTo fields', () => { - expect(() => - verifySchema( - ` - type Post @model { - author: Author! @belongsTo - } - - type Author @model { - posts: [Post] @hasMany - } - `, - true, - ), - ).not.toThrow(); - }); - - test('allows required @hasMany fields', () => { - expect(() => - verifySchema( - ` - type Post @model { - author: Author @belongsTo - } - - type Author @model { - posts: [Post]! @hasMany - } - `, - true, - ), - ).not.toThrow(); - }); - - test('allows required @hasOne fields', () => { - expect(() => - verifySchema( - ` - type Profile @model { - author: Author @belongsTo - } + test('does not allow @searchable', () => { + const stack = verifySchema(/* GraphQL */ ` + type Post @model @searchable { + title: String + } + `); - type Author @model { - profile: Profile! @hasOne - } - `, - true, - ), - ).not.toThrow(); - }); + Annotations.fromStack(stack).hasWarning( + '/Default/TestApi/GraphQLAPI', + '@searchable is deprecated. This functionality will be removed in the next major release.', + ); }); - describe('_allowGen1Patterns: false', () => { - test('does not allow @manyToMany', () => { - expect(() => - verifySchema( - ` - type Post @model { - tags: [Tag] @manyToMany(relationName: "PostTags") - } - - type Tag @model { - posts: [Post] @manyToMany(relationName: "PostTags") - } - `, - false, - ), - ).toThrow('Unknown directive "@manyToMany".'); - }); - - test('does not allow @searchable', () => { - expect(() => - verifySchema( - ` - type Post @model @searchable { - title: String - } - `, - false, - ), - ).toThrow('Unknown directive "@searchable".'); - }); - - test('does not allow @predictions', () => { - expect(() => - verifySchema( - ` - type Query { - recognizeLabelsFromImage: [String] @predictions(actions: [identifyLabels]) - } - `, - false, - ), - ).toThrow('Unknown directive "@predictions".'); - }); + test('does not allow @predictions', () => { + const schema = /* GraphQL */ ` + type Query { + recognizeLabelsFromImage: [String] @predictions(actions: [identifyLabels]) + } + `; + const stack = new cdk.Stack(); + new AmplifyGraphqlApi(stack, 'TestApi', { + definition: AmplifyGraphqlDefinition.fromString(schema), + authorizationModes: { + apiKeyConfig: { expires: cdk.Duration.days(7) }, + }, + predictionsBucket: new Bucket(stack, 'myfakebucket'), + }); + Annotations.fromStack(stack).hasWarning( + '/Default/TestApi/GraphQLAPI', + '@predictions is deprecated. This functionality will be removed in the next major release.', + ); + }); - test('does not allow fields on @belongsTo', () => { - expect(() => - verifySchema( - ` - type Post @model { - authorID: ID - author: Author @belongsTo(fields: ["authorID"]) - } + test('does not allow fields on @belongsTo', () => { + const stack = verifySchema(/* GraphQL */ ` + type Post @model { + authorID: ID + author: Author @belongsTo(fields: ["authorID"]) + } - type Author @model { - posts: [Post] @hasMany - } - `, - false, - ), - ).toThrow('fields argument on @belongsTo is disallowed. Modify Post.author to use references instead.'); - }); + type Author @model { + posts: [Post] @hasMany + } + `); + Annotations.fromStack(stack).hasWarning( + '/Default/TestApi/GraphQLAPI', + 'fields argument on @belongsTo is deprecated. Modify Post.author to use references instead. This functionality will be removed in the next major release.', + ); + }); - test('does not allow fields on @hasMany', () => { - expect(() => - verifySchema( - ` - type Post @model { - author: Author @belongsTo - } + test('does not allow fields on @hasMany', () => { + const stack = verifySchema(/* GraphQL */ ` + type Post @model { + author: Author @belongsTo + } - type Author @model { - postID: ID - posts: [Post] @hasMany(fields: ["postID"]) - } - `, - false, - ), - ).toThrow('fields argument on @hasMany is disallowed. Modify Author.posts to use references instead.'); - }); + type Author @model { + postID: ID + posts: [Post] @hasMany(fields: ["postID"]) + } + `); + Annotations.fromStack(stack).hasWarning( + '/Default/TestApi/GraphQLAPI', + 'fields argument on @hasMany is deprecated. Modify Author.posts to use references instead. This functionality will be removed in the next major release.', + ); + }); - test('does not allow fields on @hasOne', () => { - expect(() => - verifySchema( - ` - type Profile @model { - author: Author @belongsTo - } + test('does not allow fields on @hasOne', () => { + const stack = verifySchema(/* GraphQL */ ` + type Profile @model { + author: Author @belongsTo + } - type Author @model { - profileID: ID - profile: Profile @hasOne(fields: ["profileID"]) - } - `, - false, - ), - ).toThrow('fields argument on @hasOne is disallowed. Modify Author.profile to use references instead.'); - }); + type Author @model { + profileID: ID + profile: Profile @hasOne(fields: ["profileID"]) + } + `); + Annotations.fromStack(stack).hasWarning( + '/Default/TestApi/GraphQLAPI', + 'fields argument on @hasOne is deprecated. Modify Author.profile to use references instead. This functionality will be removed in the next major release.', + ); + }); - test('does not allow required @belongsTo fields', () => { - expect(() => - verifySchema( - ` - type Post @model { - author: Author! @belongsTo - } + test('does not allow required @belongsTo fields', () => { + const stack = verifySchema(/* GraphQL */ ` + type Post @model { + author: Author! @belongsTo + } - type Author @model { - posts: [Post] @hasMany - } - `, - false, - ), - ).toThrow('@belongsTo cannot be used on required fields. Modify Post.author to be optional.'); - }); + type Author @model { + posts: [Post] @hasMany + } + `); + Annotations.fromStack(stack).hasWarning( + '/Default/TestApi/GraphQLAPI', + 'fields argument on @belongsTo is deprecated. Modify Post.author to use references instead. This functionality will be removed in the next major release.', + ); + }); - test('does not allow required @hasMany fields', () => { - expect(() => - verifySchema( - ` - type Post @model { - author: Author @belongsTo - } + test('does not allow required @hasMany fields', () => { + const stack = verifySchema(/* GraphQL */ ` + type Post @model { + author: Author @belongsTo + } - type Author @model { - posts: [Post]! @hasMany - } - `, - false, - ), - ).toThrow('@hasMany cannot be used on required fields. Modify Author.posts to be optional.'); - }); + type Author @model { + posts: [Post]! @hasMany + } + `); + Annotations.fromStack(stack).hasWarning( + '/Default/TestApi/GraphQLAPI', + '@hasMany on required fields is deprecated. Modify Author.posts to be optional. This functionality will be removed in the next major release.', + ); + }); - test('does not allow required @hasOne fields', () => { - expect(() => - verifySchema( - ` - type Profile @model { - author: Author @belongsTo - } + test('does not allow required @hasOne fields', () => { + const stack = verifySchema(/* GraphQL */ ` + type Profile @model { + author: Author @belongsTo + } - type Author @model { - profile: Profile! @hasOne - } - `, - false, - ), - ).toThrow('@hasOne cannot be used on required fields. Modify Author.profile to be optional.'); - }); + type Author @model { + profile: Profile! @hasOne + } + `); + Annotations.fromStack(stack).hasWarning( + '/Default/TestApi/GraphQLAPI', + '@hasOne on required fields is deprecated. Modify Author.profile to be optional. This functionality will be removed in the next major release.', + ); }); }); diff --git a/packages/amplify-graphql-api-construct/src/amplify-graphql-api.ts b/packages/amplify-graphql-api-construct/src/amplify-graphql-api.ts index 236f274484..946ebed301 100644 --- a/packages/amplify-graphql-api-construct/src/amplify-graphql-api.ts +++ b/packages/amplify-graphql-api-construct/src/amplify-graphql-api.ts @@ -3,7 +3,6 @@ import { Construct } from 'constructs'; import { ExecuteTransformConfig, executeTransform } from '@aws-amplify/graphql-transformer'; import { NestedStack, Stack } from 'aws-cdk-lib'; import { AttributionMetadataStorage, StackMetadataBackendOutputStorageStrategy } from '@aws-amplify/backend-output-storage'; -import { TransformParameters } from '@aws-amplify/graphql-transformer-interfaces'; import { graphqlOutputKey } from '@aws-amplify/backend-output-schemas'; import type { GraphqlOutput, AwsAppsyncAuthenticationType } from '@aws-amplify/backend-output-schemas'; import { @@ -185,13 +184,10 @@ export class AmplifyGraphqlApi extends Construct { const assetProvider = new AssetProvider(this); - const mergedTranslationBehavior = { + const transformParameters = { ...defaultTranslationBehavior, ...(translationBehavior ?? {}), - }; - const transformParameters: TransformParameters = { - ...mergedTranslationBehavior, - allowGen1Patterns: mergedTranslationBehavior._allowGen1Patterns, + allowGen1Patterns: false, }; const executeTransformConfig: ExecuteTransformConfig = { scope: this, @@ -214,7 +210,6 @@ export class AmplifyGraphqlApi extends Construct { ...definition.referencedLambdaFunctions, ...functionNameMap, }, - allowGen1Patterns: transformParameters.allowGen1Patterns, }, authConfig, stackMapping: stackMappings ?? {}, diff --git a/packages/amplify-graphql-api-construct/src/internal/default-parameters.ts b/packages/amplify-graphql-api-construct/src/internal/default-parameters.ts index fe2c7a3084..5b3b780219 100644 --- a/packages/amplify-graphql-api-construct/src/internal/default-parameters.ts +++ b/packages/amplify-graphql-api-construct/src/internal/default-parameters.ts @@ -20,5 +20,4 @@ export const defaultTranslationBehavior: TranslationBehavior = { enableTransformerCfnOutputs: false, allowDestructiveGraphqlSchemaUpdates: false, replaceTableUponGsiUpdate: false, - _allowGen1Patterns: true, }; diff --git a/packages/amplify-graphql-api-construct/src/types.ts b/packages/amplify-graphql-api-construct/src/types.ts index cbc38c9200..d1085c115b 100644 --- a/packages/amplify-graphql-api-construct/src/types.ts +++ b/packages/amplify-graphql-api-construct/src/types.ts @@ -496,23 +496,6 @@ export interface TranslationBehavior { * @experimental */ readonly replaceTableUponGsiUpdate: boolean; - - /** - * When disabled usage of Gen 1 patterns will result in an error thrown. - * - * Gen 1 Patterns that will be disabled when set to false: - * - Use of @manyToMany - * - Use of @searchable - * - Use of @predictions - * - Use of fields argument on @hasOne, @hasMany, and @belongsTo. - * - Use of @hasOne, @hasMany, and @belongsTo on required fields. - * - * @default true - * @internal - * Warning: Although this has `public` access, it is intended for internal use and should not be used directly. - * The behavior of this may change without warning. - */ - readonly _allowGen1Patterns: boolean; } /** @@ -622,23 +605,6 @@ export interface PartialTranslationBehavior { */ readonly replaceTableUponGsiUpdate?: boolean; - /** - * When disabled usage of Gen 1 patterns will result in an error thrown. - * - * Gen 1 Patterns that will be disabled when set to false: - * - Use of @manyToMany - * - Use of @searchable - * - Use of @predictions - * - Use of fields argument on @hasOne, @hasMany, and @belongsTo. - * - Use of @hasOne, @hasMany, and @belongsTo on required fields. - * - * @default true - * @internal - * Warning: Although this has `public` access, it is intended for internal use and should not be used directly. - * The behavior of this may change without warning. - */ - readonly _allowGen1Patterns?: boolean; - /** * When enabled, sandbox deployment will be faster by skipping the creation of the Hotswap friendly resources. * diff --git a/packages/amplify-graphql-predictions-transformer/src/graphql-predictions-transformer.ts b/packages/amplify-graphql-predictions-transformer/src/graphql-predictions-transformer.ts index 93db873206..01f906c6d9 100644 --- a/packages/amplify-graphql-predictions-transformer/src/graphql-predictions-transformer.ts +++ b/packages/amplify-graphql-predictions-transformer/src/graphql-predictions-transformer.ts @@ -153,6 +153,12 @@ export class PredictionsTransformer extends TransformerPluginBase { }; generateResolvers = (context: TransformerContextProvider): void => { + // This validation can't occur in validate because the api has not been initialized until generateResolvers + if (!context.transformParameters.allowGen1Patterns) { + cdk.Annotations.of(context.api).addWarning( + `@${PredictionsDirective.name} is deprecated. This functionality will be removed in the next major release.`, + ); + } if (this.directiveList.length === 0) { return; } diff --git a/packages/amplify-graphql-relational-transformer/src/graphql-belongs-to-transformer.ts b/packages/amplify-graphql-relational-transformer/src/graphql-belongs-to-transformer.ts index 23f212cd22..53d4b797a4 100644 --- a/packages/amplify-graphql-relational-transformer/src/graphql-belongs-to-transformer.ts +++ b/packages/amplify-graphql-relational-transformer/src/graphql-belongs-to-transformer.ts @@ -17,6 +17,7 @@ import { TransformerTransformSchemaStepContextProvider, } from '@aws-amplify/graphql-transformer-interfaces'; import { BelongsToDirective } from '@aws-amplify/graphql-directives'; +import { Annotations } from 'aws-cdk-lib'; import { DirectiveNode, DocumentNode, @@ -150,6 +151,22 @@ export class BelongsToTransformer extends TransformerPluginBase { const context = ctx as TransformerContextProvider; for (const config of this.directiveList) { + // This validation can't occur in validate because the api has not been initialized until generateResolvers + if (!ctx.transformParameters.allowGen1Patterns) { + const { field, object } = config; + const modelName = object.name.value; + const fieldName = field.name.value; + if (field.type.kind === Kind.NON_NULL_TYPE) { + Annotations.of(ctx.api).addWarning( + `@${BelongsToDirective.name} on required fields is deprecated. Modify ${modelName}.${fieldName} to be optional. This functionality will be removed in the next major release.`, + ); + } + if (config.fields) { + Annotations.of(ctx.api).addWarning( + `fields argument on @${BelongsToDirective.name} is deprecated. Modify ${modelName}.${fieldName} to use references instead. This functionality will be removed in the next major release.`, + ); + } + } const dbType = getStrategyDbTypeFromTypeNode(config.field.type, context); const dataSourceBasedTransformer = getBelongsToDirectiveTransformer(dbType, config); dataSourceBasedTransformer.generateResolvers(ctx, config); @@ -159,21 +176,6 @@ export class BelongsToTransformer extends TransformerPluginBase { const validate = (config: BelongsToDirectiveConfiguration, ctx: TransformerContextProvider): void => { const { field, object } = config; - if (!ctx.transformParameters.allowGen1Patterns) { - const modelName = object.name.value; - const fieldName = field.name.value; - if (field.type.kind === Kind.NON_NULL_TYPE) { - throw new InvalidDirectiveError( - `@${BelongsToDirective.name} cannot be used on required fields. Modify ${modelName}.${fieldName} to be optional.`, - ); - } - if (config.fields) { - throw new InvalidDirectiveError( - `fields argument on @${BelongsToDirective.name} is disallowed. Modify ${modelName}.${fieldName} to use references instead.`, - ); - } - } - let dbType: ModelDataSourceStrategyDbType; try { // getStrategyDbTypeFromTypeNode throws if a datasource is not found for the model. We want to catch that condition diff --git a/packages/amplify-graphql-relational-transformer/src/graphql-has-many-transformer.ts b/packages/amplify-graphql-relational-transformer/src/graphql-has-many-transformer.ts index a659ac2376..213c8e5341 100644 --- a/packages/amplify-graphql-relational-transformer/src/graphql-has-many-transformer.ts +++ b/packages/amplify-graphql-relational-transformer/src/graphql-has-many-transformer.ts @@ -17,6 +17,7 @@ import { TransformerSchemaVisitStepContextProvider, TransformerTransformSchemaStepContextProvider, } from '@aws-amplify/graphql-transformer-interfaces'; +import { Annotations } from 'aws-cdk-lib'; import { DirectiveNode, DocumentNode, @@ -150,6 +151,22 @@ export class HasManyTransformer extends TransformerPluginBase { const context = ctx as TransformerContextProvider; for (const config of this.directiveList) { + // This validation can't occur in validate because the api has not been initialized until generateResolvers + if (!ctx.transformParameters.allowGen1Patterns) { + const { field, object } = config; + const modelName = object.name.value; + const fieldName = field.name.value; + if (field.type.kind === Kind.NON_NULL_TYPE) { + Annotations.of(ctx.api).addWarning( + `@${HasManyDirective.name} on required fields is deprecated. Modify ${modelName}.${fieldName} to be optional. This functionality will be removed in the next major release.`, + ); + } + if (config.fields) { + Annotations.of(ctx.api).addWarning( + `fields argument on @${HasManyDirective.name} is deprecated. Modify ${modelName}.${fieldName} to use references instead. This functionality will be removed in the next major release.`, + ); + } + } const dbType = getStrategyDbTypeFromTypeNode(config.field.type, context); const dataSourceBasedTransformer = getHasManyDirectiveTransformer(dbType, config); dataSourceBasedTransformer.generateResolvers(ctx, config); @@ -158,22 +175,7 @@ export class HasManyTransformer extends TransformerPluginBase { } const validate = (config: HasManyDirectiveConfiguration, ctx: TransformerContextProvider): void => { - const { field, object } = config; - if (!ctx.transformParameters.allowGen1Patterns) { - const modelName = object.name.value; - const fieldName = field.name.value; - if (field.type.kind === Kind.NON_NULL_TYPE) { - throw new InvalidDirectiveError( - `@${HasManyDirective.name} cannot be used on required fields. Modify ${modelName}.${fieldName} to be optional.`, - ); - } - if (config.fields) { - throw new InvalidDirectiveError( - `fields argument on @${HasManyDirective.name} is disallowed. Modify ${modelName}.${fieldName} to use references instead.`, - ); - } - } - + const { field } = config; if (!isListType(field.type)) { throw new InvalidDirectiveError(`@${HasManyDirective.name} must be used with a list. Use @hasOne for non-list types.`); } diff --git a/packages/amplify-graphql-relational-transformer/src/graphql-has-one-transformer.ts b/packages/amplify-graphql-relational-transformer/src/graphql-has-one-transformer.ts index c4b1bde544..af25b9ecdf 100644 --- a/packages/amplify-graphql-relational-transformer/src/graphql-has-one-transformer.ts +++ b/packages/amplify-graphql-relational-transformer/src/graphql-has-one-transformer.ts @@ -16,6 +16,7 @@ import { ModelDataSourceStrategyDbType, } from '@aws-amplify/graphql-transformer-interfaces'; import { HasOneDirective } from '@aws-amplify/graphql-directives'; +import { Annotations } from 'aws-cdk-lib'; import { ArgumentNode, DirectiveNode, @@ -178,6 +179,22 @@ export class HasOneTransformer extends TransformerPluginBase { const context = ctx as TransformerContextProvider; for (const config of this.directiveList) { + // This validation can't occur in validate because the api has not been initialized until generateResolvers + if (!ctx.transformParameters.allowGen1Patterns) { + const { field, object } = config; + const modelName = object.name.value; + const fieldName = field.name.value; + if (field.type.kind === Kind.NON_NULL_TYPE) { + Annotations.of(ctx.api).addWarning( + `@${HasOneDirective.name} on required fields is deprecated. Modify ${modelName}.${fieldName} to be optional. This functionality will be removed in the next major release.`, + ); + } + if (config.fields) { + Annotations.of(ctx.api).addWarning( + `fields argument on @${HasOneDirective.name} is deprecated. Modify ${modelName}.${fieldName} to use references instead. This functionality will be removed in the next major release.`, + ); + } + } const dbType = getStrategyDbTypeFromTypeNode(config.field.type, context); const dataSourceBasedTransformer = getHasOneDirectiveTransformer(dbType, config); dataSourceBasedTransformer.generateResolvers(ctx, config); @@ -186,22 +203,7 @@ export class HasOneTransformer extends TransformerPluginBase { } const validate = (config: HasOneDirectiveConfiguration, ctx: TransformerContextProvider): void => { - const { field, object } = config; - if (!ctx.transformParameters.allowGen1Patterns) { - const modelName = object.name.value; - const fieldName = field.name.value; - if (field.type.kind === Kind.NON_NULL_TYPE) { - throw new InvalidDirectiveError( - `@${HasOneDirective.name} cannot be used on required fields. Modify ${modelName}.${fieldName} to be optional.`, - ); - } - if (config.fields) { - throw new InvalidDirectiveError( - `fields argument on @${HasOneDirective.name} is disallowed. Modify ${modelName}.${fieldName} to use references instead.`, - ); - } - } - + const { field } = config; let dbType: ModelDataSourceStrategyDbType; try { // getStrategyDbTypeFromTypeNode throws if a datasource is not found for the model. We want to catch that condition diff --git a/packages/amplify-graphql-relational-transformer/src/graphql-many-to-many-transformer.ts b/packages/amplify-graphql-relational-transformer/src/graphql-many-to-many-transformer.ts index 483258e477..c93a7e1cf4 100644 --- a/packages/amplify-graphql-relational-transformer/src/graphql-many-to-many-transformer.ts +++ b/packages/amplify-graphql-relational-transformer/src/graphql-many-to-many-transformer.ts @@ -23,6 +23,7 @@ import { ModelDataSourceStrategy, } from '@aws-amplify/graphql-transformer-interfaces'; import { ManyToManyDirective } from '@aws-amplify/graphql-directives'; +import { Annotations } from 'aws-cdk-lib'; import { DirectiveNode, DocumentNode, @@ -510,6 +511,12 @@ export class ManyToManyTransformer extends TransformerPluginBase { generateResolvers = (ctx: TransformerContextProvider): void => { const context = ctx as TransformerContextProvider; + // This validation can't occur in validate because the api has not been initialized until generateResolvers + if (!context.transformParameters.allowGen1Patterns) { + Annotations.of(context.api).addWarning( + `@${ManyToManyDirective.name} is deprecated. This functionality will be removed in the next major release.`, + ); + } for (const config of this.directiveList) { updateTableForConnection(config, context); diff --git a/packages/amplify-graphql-searchable-transformer/src/graphql-searchable-transformer.ts b/packages/amplify-graphql-searchable-transformer/src/graphql-searchable-transformer.ts index c8f2288b39..c83c7632fe 100644 --- a/packages/amplify-graphql-searchable-transformer/src/graphql-searchable-transformer.ts +++ b/packages/amplify-graphql-searchable-transformer/src/graphql-searchable-transformer.ts @@ -16,7 +16,7 @@ import { import { SearchableDirective } from '@aws-amplify/graphql-directives'; import { DynamoDbDataSource } from 'aws-cdk-lib/aws-appsync'; import { Table } from 'aws-cdk-lib/aws-dynamodb'; -import { ArnFormat, CfnCondition, Fn } from 'aws-cdk-lib'; +import { ArnFormat, CfnCondition, Fn, Annotations } from 'aws-cdk-lib'; import { IConstruct } from 'constructs'; import { DirectiveNode, InputObjectTypeDefinitionNode, ObjectTypeDefinitionNode } from 'graphql'; import { Expression, str } from 'graphql-mapping-template'; @@ -281,6 +281,13 @@ export class SearchableModelTransformer extends TransformerPluginBase { } generateResolvers = (context: TransformerContextProvider): void => { + // This validation can't occur in validate because the api has not been initialized until generateResolvers + if (!context.transformParameters.allowGen1Patterns) { + Annotations.of(context.api).addWarning( + `@${SearchableDirective.name} is deprecated. This functionality will be removed in the next major release.`, + ); + } + if (!this.isSearchableConfigured()) { return; } diff --git a/packages/amplify-graphql-transformer-test-utils/API.md b/packages/amplify-graphql-transformer-test-utils/API.md index d05fefe097..e567073fbd 100644 --- a/packages/amplify-graphql-transformer-test-utils/API.md +++ b/packages/amplify-graphql-transformer-test-utils/API.md @@ -103,6 +103,8 @@ export const mockSqlDataSourceStrategy: (options?: MakeSqlDataSourceStrategyOpti // @public (undocumented) export interface NestedStacks { + // (undocumented) + rawRootStack: Stack; // (undocumented) rootStack: Template; // (undocumented) diff --git a/packages/amplify-graphql-transformer-test-utils/src/cdk-compat/transform-manager.ts b/packages/amplify-graphql-transformer-test-utils/src/cdk-compat/transform-manager.ts index 854e7003bb..71cc6c757a 100644 --- a/packages/amplify-graphql-transformer-test-utils/src/cdk-compat/transform-manager.ts +++ b/packages/amplify-graphql-transformer-test-utils/src/cdk-compat/transform-manager.ts @@ -119,6 +119,7 @@ export class TransformManager { rootStack: rootStackTemplate!, stackMapping: {}, userOverriddenSlots: [], + rawRootStack: this.rootStack, }; } diff --git a/packages/amplify-graphql-transformer-test-utils/src/deployment-resources.ts b/packages/amplify-graphql-transformer-test-utils/src/deployment-resources.ts index 7f4cdfbc7f..e25ebed479 100644 --- a/packages/amplify-graphql-transformer-test-utils/src/deployment-resources.ts +++ b/packages/amplify-graphql-transformer-test-utils/src/deployment-resources.ts @@ -1,3 +1,5 @@ +import { Stack } from 'aws-cdk-lib'; + export interface Template { AWSTemplateFormatVersion?: string; Description?: string; @@ -34,6 +36,8 @@ export interface ResolversFunctionsAndSchema { export interface NestedStacks { // The root stack template. rootStack: Template; + // root stack as a CDK stack + rawRootStack: Stack; // All the nested stack templates. stacks: Record; // The full stack mapping for the deployment. diff --git a/packages/amplify-graphql-transformer/API.md b/packages/amplify-graphql-transformer/API.md index d8e628ddcf..01a514a4ef 100644 --- a/packages/amplify-graphql-transformer/API.md +++ b/packages/amplify-graphql-transformer/API.md @@ -56,7 +56,6 @@ export type TransformerFactoryArgs = { storageConfig?: any; customTransformers?: TransformerPluginProvider[]; functionNameMap?: Record; - allowGen1Patterns?: boolean; }; // (No @packageDocumentation comment for this package) diff --git a/packages/amplify-graphql-transformer/package.json b/packages/amplify-graphql-transformer/package.json index 853fbcf6e6..ed551f17eb 100644 --- a/packages/amplify-graphql-transformer/package.json +++ b/packages/amplify-graphql-transformer/package.json @@ -44,6 +44,7 @@ "@aws-amplify/graphql-transformer-interfaces": "3.10.1" }, "devDependencies": { + "@aws-amplify/graphql-transformer-test-utils": "0.5.6", "@types/node": "^12.12.6", "fs-extra": "^8.1.0", "rimraf": "^3.0.0", diff --git a/packages/amplify-graphql-transformer/src/__tests__/allow-gen1-patterns.test.ts b/packages/amplify-graphql-transformer/src/__tests__/allow-gen1-patterns.test.ts new file mode 100644 index 0000000000..4930d56e92 --- /dev/null +++ b/packages/amplify-graphql-transformer/src/__tests__/allow-gen1-patterns.test.ts @@ -0,0 +1,326 @@ +import { testTransform } from '@aws-amplify/graphql-transformer-test-utils'; +import { Stack } from 'aws-cdk-lib'; +import { Match, Annotations } from 'aws-cdk-lib/assertions'; +import { constructTransformerChain } from '..'; + +const verifySchema = (schema: string, allowGen1Patterns: boolean): Stack => { + const out = testTransform({ + schema, + transformers: constructTransformerChain({ storageConfig: { bucketName: 'myfakebucket' } }), + transformParameters: { + allowGen1Patterns, + }, + }); + + return out.rawRootStack; +}; +describe('gen 1 patterns', () => { + describe('allow', () => { + test('allows @manyToMany', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Post @model { + tags: [Tag] @manyToMany(relationName: "PostTags") + } + + type Tag @model { + posts: [Post] @manyToMany(relationName: "PostTags") + } + `, + true, + ); + Annotations.fromStack(stack).hasNoWarning('/transformer-root-stack/GraphQLAPI', Match.anyValue()); + }); + + test('allows @searchable', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Post @model @searchable { + title: String + } + `, + true, + ); + Annotations.fromStack(stack).hasNoWarning('/transformer-root-stack/GraphQLAPI', Match.anyValue()); + }); + + test('allows @predictions', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Query { + recognizeLabelsFromImage: [String] @predictions(actions: [identifyLabels]) + } + `, + true, + ); + Annotations.fromStack(stack).hasNoWarning('/transformer-root-stack/GraphQLAPI', Match.anyValue()); + }); + + test('allows fields on @belongsTo', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Post @model { + authorID: ID + author: Author @belongsTo(fields: ["authorID"]) + } + + type Author @model { + posts: [Post] @hasMany + } + `, + true, + ); + Annotations.fromStack(stack).hasNoWarning('/transformer-root-stack/GraphQLAPI', Match.anyValue()); + }); + + test('allows fields on @hasMany', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Post @model { + author: Author @belongsTo + } + + type Author @model { + postID: ID + posts: [Post] @hasMany(fields: ["postID"]) + } + `, + true, + ); + Annotations.fromStack(stack).hasNoWarning('/transformer-root-stack/GraphQLAPI', Match.anyValue()); + }); + + test('allows fields on @hasOne', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Profile @model { + author: Author @belongsTo + } + + type Author @model { + profileID: ID + profile: Profile @hasOne(fields: ["profileID"]) + } + `, + true, + ); + Annotations.fromStack(stack).hasNoWarning('/transformer-root-stack/GraphQLAPI', Match.anyValue()); + }); + + test('allows required @belongsTo fields', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Post @model { + author: Author! @belongsTo + } + + type Author @model { + posts: [Post] @hasMany + } + `, + true, + ); + Annotations.fromStack(stack).hasNoWarning('/transformer-root-stack/GraphQLAPI', Match.anyValue()); + }); + + test('allows required @hasMany fields', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Post @model { + author: Author @belongsTo + } + + type Author @model { + posts: [Post]! @hasMany + } + `, + true, + ); + Annotations.fromStack(stack).hasNoWarning('/transformer-root-stack/GraphQLAPI', Match.anyValue()); + }); + + test('allows required @hasOne fields', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Profile @model { + author: Author @belongsTo + } + + type Author @model { + profile: Profile! @hasOne + } + `, + true, + ); + Annotations.fromStack(stack).hasNoWarning('/transformer-root-stack/GraphQLAPI', Match.anyValue()); + }); + }); + describe('disallow', () => { + test('does not allow @manyToMany', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Post @model { + tags: [Tag] @manyToMany(relationName: "PostTags") + } + + type Tag @model { + posts: [Post] @manyToMany(relationName: "PostTags") + } + `, + false, + ); + Annotations.fromStack(stack).hasWarning( + '/transformer-root-stack/GraphQLAPI', + '@manyToMany is deprecated. This functionality will be removed in the next major release.', + ); + }); + + test('does not allow @searchable', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Post @model @searchable { + title: String + } + `, + false, + ); + + Annotations.fromStack(stack).hasWarning( + '/transformer-root-stack/GraphQLAPI', + '@searchable is deprecated. This functionality will be removed in the next major release.', + ); + }); + + test('does not allow @predictions', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Query { + recognizeLabelsFromImage: [String] @predictions(actions: [identifyLabels]) + } + `, + false, + ); + Annotations.fromStack(stack).hasWarning( + '/transformer-root-stack/GraphQLAPI', + '@predictions is deprecated. This functionality will be removed in the next major release.', + ); + }); + + test('does not allow fields on @belongsTo', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Post @model { + authorID: ID + author: Author @belongsTo(fields: ["authorID"]) + } + + type Author @model { + posts: [Post] @hasMany + } + `, + false, + ); + Annotations.fromStack(stack).hasWarning( + '/transformer-root-stack/GraphQLAPI', + 'fields argument on @belongsTo is deprecated. Modify Post.author to use references instead. This functionality will be removed in the next major release.', + ); + }); + + test('does not allow fields on @hasMany', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Post @model { + author: Author @belongsTo + } + + type Author @model { + postID: ID + posts: [Post] @hasMany(fields: ["postID"]) + } + `, + false, + ); + Annotations.fromStack(stack).hasWarning( + '/transformer-root-stack/GraphQLAPI', + 'fields argument on @hasMany is deprecated. Modify Author.posts to use references instead. This functionality will be removed in the next major release.', + ); + }); + + test('does not allow fields on @hasOne', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Profile @model { + author: Author @belongsTo + } + + type Author @model { + profileID: ID + profile: Profile @hasOne(fields: ["profileID"]) + } + `, + false, + ); + Annotations.fromStack(stack).hasWarning( + '/transformer-root-stack/GraphQLAPI', + 'fields argument on @hasOne is deprecated. Modify Author.profile to use references instead. This functionality will be removed in the next major release.', + ); + }); + + test('does not allow required @belongsTo fields', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Post @model { + author: Author! @belongsTo + } + + type Author @model { + posts: [Post] @hasMany + } + `, + false, + ); + Annotations.fromStack(stack).hasWarning( + '/transformer-root-stack/GraphQLAPI', + 'fields argument on @belongsTo is deprecated. Modify Post.author to use references instead. This functionality will be removed in the next major release.', + ); + }); + + test('does not allow required @hasMany fields', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Post @model { + author: Author @belongsTo + } + + type Author @model { + posts: [Post]! @hasMany + } + `, + false, + ); + Annotations.fromStack(stack).hasWarning( + '/transformer-root-stack/GraphQLAPI', + '@hasMany on required fields is deprecated. Modify Author.posts to be optional. This functionality will be removed in the next major release.', + ); + }); + + test('does not allow required @hasOne fields', () => { + const stack = verifySchema( + /* GraphQL */ ` + type Profile @model { + author: Author @belongsTo + } + + type Author @model { + profile: Profile! @hasOne + } + `, + false, + ); + Annotations.fromStack(stack).hasWarning( + '/transformer-root-stack/GraphQLAPI', + '@hasOne on required fields is deprecated. Modify Author.profile to be optional. This functionality will be removed in the next major release.', + ); + }); + }); +}); diff --git a/packages/amplify-graphql-transformer/src/__tests__/graphql-transformer.test.ts b/packages/amplify-graphql-transformer/src/__tests__/graphql-transformer.test.ts index 9cd5e3c2b6..8c3a056921 100644 --- a/packages/amplify-graphql-transformer/src/__tests__/graphql-transformer.test.ts +++ b/packages/amplify-graphql-transformer/src/__tests__/graphql-transformer.test.ts @@ -37,14 +37,6 @@ describe('constructTransformerChain', () => { it('succeeds on admin roles', () => { expect(constructTransformerChain().length).toEqual(numOfTransformers); }); - - it('allows gen 1 patterns by default', () => { - expect(constructTransformerChain().length).toEqual(numOfTransformers); - }); - - it('removes transformers not supported in gen 2', () => { - expect(constructTransformerChain({ allowGen1Patterns: false }).length).toEqual(numOfTransformers - 3); - }); }); const defaultTransformConfig: TransformConfig = { diff --git a/packages/amplify-graphql-transformer/src/graphql-transformer.ts b/packages/amplify-graphql-transformer/src/graphql-transformer.ts index 930a01127c..563b91efdd 100644 --- a/packages/amplify-graphql-transformer/src/graphql-transformer.ts +++ b/packages/amplify-graphql-transformer/src/graphql-transformer.ts @@ -42,7 +42,6 @@ export type TransformerFactoryArgs = { storageConfig?: any; customTransformers?: TransformerPluginProvider[]; functionNameMap?: Record; - allowGen1Patterns?: boolean; }; /** @@ -63,26 +62,24 @@ export const constructTransformerChain = (options?: TransformerFactoryArgs): Tra const indexTransformer = new IndexTransformer(); const hasOneTransformer = new HasOneTransformer(); - const allowGen1Patterns = options?.allowGen1Patterns === undefined ? true : options?.allowGen1Patterns; - // The default list of transformers should match DefaultDirectives in packages/amplify-graphql-directives/src/index.ts return [ modelTransformer, new FunctionTransformer(options?.functionNameMap), new HttpTransformer(), - ...(allowGen1Patterns ? [new PredictionsTransformer(options?.storageConfig)] : []), + new PredictionsTransformer(options?.storageConfig), new PrimaryKeyTransformer(), indexTransformer, new HasManyTransformer(), hasOneTransformer, - ...(allowGen1Patterns ? [new ManyToManyTransformer(modelTransformer, indexTransformer, hasOneTransformer, authTransformer)] : []), + new ManyToManyTransformer(modelTransformer, indexTransformer, hasOneTransformer, authTransformer), new BelongsToTransformer(), new DefaultValueTransformer(), authTransformer, new MapsToTransformer(), new SqlTransformer(), new RefersToTransformer(), - ...(allowGen1Patterns ? [new SearchableModelTransformer()] : []), + new SearchableModelTransformer(), ...(options?.customTransformers ?? []), ]; };